summaryrefslogtreecommitdiff
path: root/app/controllers/projects/blob_controller.rb
blob: 495a432347e3e9f3df69e4c0025625e6f397f6bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# Controller for viewing a file's blame
class Projects::BlobController < Projects::ApplicationController
  include ExtractsPath
  include CreatesCommit
  include ActionView::Helpers::SanitizeHelper

  # Raised when given an invalid file path
  class InvalidPathError < StandardError; end

  before_action :require_non_empty_project, except: [:new, :create]
  before_action :authorize_download_code!
  before_action :authorize_edit_tree!, only: [:new, :create, :edit, :update, :destroy]
  before_action :assign_blob_vars
  before_action :commit, except: [:new, :create]
  before_action :blob, except: [:new, :create]
  before_action :from_merge_request, only: [:edit, :update]
  before_action :require_branch_head, only: [:edit, :update]
  before_action :editor_variables, except: [:show, :preview, :diff]

  def new
    commit unless @repository.empty?
  end

  def create
    create_commit(Files::CreateService, success_notice: "The file has been successfully created.",
                                        success_path: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)),
                                        failure_view: :new,
                                        failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
  end

  def show
  end

  def edit
    @last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
    blob.load_all_data!(@repository)
  end

  def update
    after_edit_path =
      if from_merge_request && @target_branch == @ref
        diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
          "#file-path-#{hexdigest(@path)}"
      else
        namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path))
      end

    create_commit(Files::UpdateService, success_path: after_edit_path,
                                        failure_view: :edit,
                                        failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
  end

  def preview
    @content = params[:content]
    @blob.load_all_data!(@repository)
    diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
    diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
    diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)
    @diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight

    render layout: false
  end

  def destroy
    create_commit(Files::DeleteService, success_notice: "The file has been successfully deleted.",
                                        success_path: namespace_project_tree_path(@project.namespace, @project, @target_branch),
                                        failure_view: :show,
                                        failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
  end

  def diff
    @form  = UnfoldForm.new(params)
    @lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path)
    @lines = @lines[@form.since - 1..@form.to - 1]

    if @form.bottom?
      @match_line = ''
    else
      lines_length = @lines.length - 1
      line = [@form.since, lines_length].join(',')
      @match_line = "@@ -#{line}+#{line} @@"
    end

    render layout: false
  end

  private

  def blob
    @blob ||= @repository.blob_at(@commit.id, @path)

    if @blob
      @blob
    else
      if tree = @repository.tree(@commit.id, @path)
        if tree.entries.any?
          redirect_to namespace_project_tree_path(@project.namespace, @project, File.join(@ref, @path)) and return
        end
      end

      return render_404
    end
  end

  def commit
    @commit = @repository.commit(@ref)

    return render_404 unless @commit
  end

  def assign_blob_vars
    @id = params[:id]
    @ref, @path = extract_ref(@id)

  rescue InvalidPathError
    render_404
  end

  def from_merge_request
    # If blob edit was initiated from merge request page
    @from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
  end

  def editor_variables
    @target_branch = params[:target_branch]

    @file_path =
      if action_name.to_s == 'create'
        if params[:file].present?
          params[:file_name] = params[:file].original_filename
        end
        File.join(@path, params[:file_name])
      else
        @path
      end

    if params[:file].present?
      params[:content] = Base64.encode64(params[:file].read)
      params[:encoding] = 'base64'
    end

    @commit_params = {
      file_path: @file_path,
      commit_message: params[:commit_message],
      file_content: params[:content],
      file_content_encoding: params[:encoding]
    }
  end
end