summaryrefslogtreecommitdiff
path: root/app/controllers/projects/blob_controller.rb
blob: 100d3d3b3174d3e5103f13090281f5e415e83818 (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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# Controller for viewing a file's blame
class Projects::BlobController < Projects::ApplicationController
  include ExtractsPath
  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_push_code!, only: [: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]
  before_action :after_edit_path, only: [:edit, :update]

  def new
    commit unless @repository.empty?
  end

  def create
    result = Files::CreateService.new(@project, current_user, @commit_params).execute

    if result[:status] == :success
      flash[:notice] = "Your changes have been successfully committed"
      redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path))
    else
      flash[:alert] = result[:message]
      render :new
    end
  end

  def show
  end

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

  def update
    result = Files::UpdateService.new(@project, current_user, @commit_params).execute

    if result[:status] == :success
      flash[:notice] = "Your changes have been successfully committed"
      redirect_to after_edit_path
    else
      flash[:alert] = result[:message]
      render :edit
    end
  end

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

    render layout: false
  end

  def destroy
    result = Files::DeleteService.new(@project, current_user, @commit_params).execute

    if result[:status] == :success
      flash[:notice] = "Your changes have been successfully committed"
      redirect_to namespace_project_tree_path(@project.namespace, @project, @target_branch)
    else
      flash[:alert] = result[:message]
      render :show
    end
  end

  def diff
    @form = UnfoldForm.new(params)
    @lines = @blob.data.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 not_found!
    end
  end

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

    return not_found! unless @commit
  end

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

  rescue InvalidPathError
    not_found!
  end

  def after_edit_path
    @after_edit_path ||=
      if from_merge_request
        diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
          "#file-path-#{hexdigest(@path)}"
      elsif @target_branch.present?
        namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path))
      else
        namespace_project_blob_path(@project.namespace, @project, @id)
      end
  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 sanitized_new_branch_name
    @new_branch ||= sanitize(strip_tags(params[:new_branch]))
  end

  def editor_variables
    @current_branch = @ref
    @target_branch = (sanitized_new_branch_name || @ref)

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

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