gitlab-org--gitlab-foss/app/controllers/projects/blob_controller.rb
Bob Van Landuyt 8c5b3d0302 Allow streaming io objects into Gitaly
This allows us to set the encoding of an IO passed without reading it
into memory.

This is useful if we want to stream files into Gitaly. Like we do when
uploading a new file to the repository.
2019-04-01 20:17:40 +02:00

240 lines
7 KiB
Ruby

# frozen_string_literal: true
# Controller for viewing a file's blame
class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
include CreatesCommit
include RendersBlob
include NotesHelper
include ActionView::Helpers::SanitizeHelper
prepend_before_action :authenticate_user!, only: [:edit]
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
# We need to assign the blob vars before `authorize_edit_tree!` so we can
# validate access to a specific ref.
before_action :assign_blob_vars
before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
before_action :require_branch_head, only: [:edit, :update]
before_action :editor_variables, except: [:show, :preview, :diff]
before_action :validate_diff_params, only: :diff
before_action :set_last_commit_sha, only: [:edit, :update]
def new
commit unless @repository.empty?
end
def create
create_commit(Files::CreateService, success_notice: _("The file has been successfully created."),
success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
failure_view: :new,
failure_path: project_new_blob_path(@project, @ref))
end
def show
conditionally_expand_blob(@blob)
respond_to do |format|
format.html do
show_html
end
format.json do
page_title @blob.path, @ref, @project.full_name
show_json
end
end
end
def edit
if can_collaborate_with_project?(project, ref: @ref)
blob.load_all_data!
else
redirect_to action: 'show'
end
end
def update
@path = params[:file_path] if params[:file_path].present?
create_commit(Files::UpdateService, success_path: -> { after_edit_path },
failure_view: :edit,
failure_path: project_blob_path(@project, @id))
rescue Files::UpdateService::FileChangedError
@conflict = true
render :edit
end
def preview
@content = params[:content]
@blob.load_all_data!
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, repository: @repository).highlight
render layout: false
end
def destroy
create_commit(Files::DeleteService, success_notice: _("The file has been successfully deleted."),
success_path: -> { after_delete_path },
failure_view: :show,
failure_path: project_blob_path(@project, @id))
end
def diff
apply_diff_view_cookie!
@form = Blobs::UnfoldPresenter.new(blob, params.to_unsafe_h)
# keep only json rendering when
# https://gitlab.com/gitlab-org/gitlab-ce/issues/44988 is done
if rendered_for_merge_request?
render json: DiffLineSerializer.new.represent(@form.diff_lines)
else
@lines = @form.lines
@match_line = @form.match_line_text
render layout: false
end
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?
return redirect_to project_tree_path(@project, File.join(@ref, @path))
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
# rubocop: disable CodeReuse/ActiveRecord
def after_edit_path
from_merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).find_by(iid: params[:from_merge_request_iid])
if from_merge_request && @branch_name == @ref
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
"##{hexdigest(@path)}"
else
project_blob_path(@project, File.join(@branch_name, @path))
end
end
# rubocop: enable CodeReuse/ActiveRecord
def after_delete_path
branch = BranchesFinder.new(@repository, search: @ref).execute.first
if @repository.tree(branch.target, tree_path).entries.empty?
project_tree_path(@project, @ref)
else
project_tree_path(@project, File.join(@ref, tree_path))
end
end
def editor_variables
@branch_name = params[:branch_name]
@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])
elsif params[:file_path].present?
params[:file_path]
else
@path
end
if params[:file].present?
params[:content] = params[:file]
end
@commit_params = {
file_path: @file_path,
commit_message: params[:commit_message],
previous_path: @path,
file_content: params[:content],
file_content_encoding: params[:encoding],
last_commit_sha: params[:last_commit_sha]
}
end
def validate_diff_params
return if params[:full]
if [:since, :to, :offset].any? { |key| params[key].blank? }
head :ok
end
end
def set_last_commit_sha
@last_commit_sha = Gitlab::Git::Commit
.last_for_path(@repository, @ref, @path).sha
end
def show_html
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
@last_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
render 'show'
end
def show_json
set_last_commit_sha
json = {
id: @blob.id,
last_commit_sha: @last_commit_sha,
path: blob.path,
name: blob.name,
extension: blob.extension,
size: blob.raw_size,
mime_type: blob.mime_type,
binary: blob.binary?,
simple_viewer: blob.simple_viewer&.class&.partial_name,
rich_viewer: blob.rich_viewer&.class&.partial_name,
show_viewer_switcher: !!blob.show_viewer_switcher?,
render_error: blob.simple_viewer&.render_error || blob.rich_viewer&.render_error,
raw_path: project_raw_path(project, @id),
blame_path: project_blame_path(project, @id),
commits_path: project_commits_path(project, @id),
tree_path: project_tree_path(project, File.join(@ref, tree_path)),
permalink: project_blob_path(project, File.join(@commit.id, @path))
}
json.merge!(blob_json(@blob) || {}) unless params[:viewer] == 'none'
render json: json
end
def tree_path
@path.rpartition('/').first
end
end