2018-12-05 23:21:45 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
module BlobHelper
def no_highlight_files
2015-04-26 12:48:37 +05:30
%w( credits changelog news copying copyright license authors )
end
2018-03-17 18:26:18 +05:30
def edit_blob_path ( project = @project , ref = @ref , path = @path , options = { } )
2017-09-10 17:25:29 +05:30
project_edit_blob_path ( project ,
2018-03-27 19:54:05 +05:30
tree_join ( ref , path ) ,
options [ :link_opts ] )
2016-01-14 18:37:52 +05:30
end
2020-05-24 23:13:21 +05:30
def ide_edit_path ( project = @project , ref = @ref , path = @path )
2019-09-30 21:07:59 +05:30
project_path =
if ! current_user || can? ( current_user , :push_code , project )
project . full_path
else
# We currently always fork to the user's namespace
# in edit_fork_button_tag
" #{ current_user . namespace . full_path } / #{ project . path } "
end
2020-03-13 15:44:24 +05:30
segments = [ ide_path , 'project' , project_path , 'edit' , encode_ide_path ( ref ) ]
2019-07-07 11:18:12 +05:30
segments . concat ( [ '-' , encode_ide_path ( path ) ] ) if path . present?
2018-11-08 19:23:39 +05:30
File . join ( segments )
2018-03-17 18:26:18 +05:30
end
2019-12-21 20:55:43 +05:30
def ide_fork_and_edit_path ( project = @project , ref = @ref , path = @path , options = { } )
2021-01-03 14:25:43 +05:30
fork_path_for_current_user ( project , ide_edit_path ( project , ref , path ) )
end
def fork_and_edit_path ( project = @project , ref = @ref , path = @path , options = { } )
fork_path_for_current_user ( project , edit_blob_path ( project , ref , path , options ) )
end
def fork_path_for_current_user ( project , path )
return unless current_user
project_forks_path ( project ,
namespace_key : current_user . namespace & . id ,
continue : edit_blob_fork_params ( path ) )
2019-12-21 20:55:43 +05:30
end
2019-07-07 11:18:12 +05:30
def encode_ide_path ( path )
2020-11-24 15:15:51 +05:30
ERB :: Util . url_encode ( path ) . gsub ( '%2F' , '/' )
2019-07-07 11:18:12 +05:30
end
2018-03-27 19:54:05 +05:30
def edit_blob_button ( project = @project , ref = @ref , path = @path , options = { } )
return unless blob = readable_blob ( options , path , project , ref )
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
common_classes = " btn btn-primary js-edit-blob ml-2 #{ options [ :extra_class ] } "
2020-10-24 23:57:45 +05:30
data = { track_event : 'click_edit' , track_label : 'Edit' }
if Feature . enabled? ( :web_ide_primary_edit , project . group )
common_classes += " btn-inverted "
data [ :track_property ] = 'secondary'
end
2018-03-17 18:26:18 +05:30
2018-03-27 19:54:05 +05:30
edit_button_tag ( blob ,
common_classes ,
_ ( 'Edit' ) ,
2020-07-28 23:09:34 +05:30
edit_blob_path ( project , ref , path , options ) ,
2018-03-27 19:54:05 +05:30
project ,
2020-10-24 23:57:45 +05:30
ref ,
data )
2018-03-17 18:26:18 +05:30
end
2020-05-24 23:13:21 +05:30
def ide_edit_button ( project = @project , ref = @ref , path = @path , blob : )
return unless blob
2018-05-09 12:01:36 +05:30
2020-10-24 23:57:45 +05:30
common_classes = 'btn btn-primary ide-edit-button ml-2'
data = { track_event : 'click_edit_ide' , track_label : 'Web IDE' }
unless Feature . enabled? ( :web_ide_primary_edit , project . group )
common_classes += " btn-inverted "
data [ :track_property ] = 'secondary'
end
2018-05-09 12:01:36 +05:30
edit_button_tag ( blob ,
2020-10-24 23:57:45 +05:30
common_classes ,
2018-05-09 12:01:36 +05:30
_ ( 'Web IDE' ) ,
2020-05-24 23:13:21 +05:30
ide_edit_path ( project , ref , path ) ,
2018-05-09 12:01:36 +05:30
project ,
2020-10-24 23:57:45 +05:30
ref ,
data )
2018-05-09 12:01:36 +05:30
end
2020-05-24 23:13:21 +05:30
def modify_file_button ( project = @project , ref = @ref , path = @path , blob : , label : , action : , btn_class : , modal_type : )
2016-01-14 18:37:52 +05:30
return unless current_user
return unless blob
2017-08-17 22:00:37 +05:30
common_classes = " btn btn- #{ btn_class } "
2016-01-29 22:53:50 +05:30
if ! on_top_of_branch? ( project , ref )
2017-08-17 22:00:37 +05:30
button_tag label , class : " #{ common_classes } disabled has-tooltip " , title : " You can only #{ action } files when you are on a branch " , data : { container : 'body' }
elsif blob . stored_externally?
button_tag label , class : " #{ common_classes } disabled has-tooltip " , title : " It is not possible to #{ action } files that are stored in LFS using the web interface " , data : { container : 'body' }
elsif can_modify_blob? ( blob , project , ref )
button_tag label , class : " #{ common_classes } " , 'data-target' = > " # modal- #{ modal_type } -blob " , 'data-toggle' = > 'modal'
2018-05-09 12:01:36 +05:30
elsif can? ( current_user , :fork_project , project ) && can? ( current_user , :create_merge_request_in , project )
2018-03-27 19:54:05 +05:30
edit_fork_button_tag ( common_classes , project , label , edit_modify_file_fork_params ( action ) , action )
2016-01-14 18:37:52 +05:30
end
end
2020-05-24 23:13:21 +05:30
def replace_blob_link ( project = @project , ref = @ref , path = @path , blob : )
2018-03-27 19:54:05 +05:30
modify_file_button (
2016-01-14 18:37:52 +05:30
project ,
ref ,
path ,
2020-05-24 23:13:21 +05:30
blob : blob ,
2019-07-07 11:18:12 +05:30
label : _ ( " Replace " ) ,
2016-01-14 18:37:52 +05:30
action : " replace " ,
btn_class : " default " ,
modal_type : " upload "
)
end
2020-05-24 23:13:21 +05:30
def delete_blob_link ( project = @project , ref = @ref , path = @path , blob : )
2018-03-27 19:54:05 +05:30
modify_file_button (
2016-01-14 18:37:52 +05:30
project ,
ref ,
path ,
2020-05-24 23:13:21 +05:30
blob : blob ,
2019-07-07 11:18:12 +05:30
label : _ ( " Delete " ) ,
2016-01-14 18:37:52 +05:30
action : " delete " ,
2019-12-26 22:10:19 +05:30
btn_class : " default " ,
2016-01-14 18:37:52 +05:30
modal_type : " remove "
)
2015-12-23 02:04:40 +05:30
end
2017-08-17 22:00:37 +05:30
def can_modify_blob? ( blob , project = @project , ref = @ref )
! blob . stored_externally? && can_edit_tree? ( project , ref )
2015-04-26 12:48:37 +05:30
end
def leave_edit_message
2019-07-07 11:18:12 +05:30
_ ( " Leave edit mode? All unsaved changes will be lost. " )
2015-04-26 12:48:37 +05:30
end
def editing_preview_title ( filename )
2015-09-11 14:41:01 +05:30
if Gitlab :: MarkupHelper . previewable? ( filename )
2019-07-07 11:18:12 +05:30
_ ( 'Preview' )
2015-04-26 12:48:37 +05:30
else
2019-07-07 11:18:12 +05:30
_ ( 'Preview changes' )
2015-04-26 12:48:37 +05:30
end
end
# Return an image icon depending on the file mode and extension
#
# mode - File unix mode
# mode - File name
def blob_icon ( mode , name )
2021-01-03 14:25:43 +05:30
sprite_icon ( file_type_icon_class ( 'file' , mode , name ) )
2014-09-02 18:07:02 +05:30
end
2015-12-23 02:04:40 +05:30
2018-11-18 11:00:15 +05:30
def blob_raw_url ( ** kwargs )
2017-08-17 22:00:37 +05:30
if @build && @entry
2018-11-18 11:00:15 +05:30
raw_project_job_artifacts_url ( @project , @build , path : @entry . path , ** kwargs )
2017-08-17 22:00:37 +05:30
elsif @snippet
2020-01-01 13:55:28 +05:30
gitlab_raw_snippet_url ( @snippet )
2017-08-17 22:00:37 +05:30
elsif @blob
2018-11-18 11:00:15 +05:30
project_raw_url ( @project , @id , ** kwargs )
2015-12-23 02:04:40 +05:30
end
end
2016-04-02 18:10:28 +05:30
2018-11-18 11:00:15 +05:30
def blob_raw_path ( ** kwargs )
blob_raw_url ( ** kwargs , only_path : true )
2018-03-17 18:26:18 +05:30
end
2016-04-02 18:10:28 +05:30
# SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
2017-08-17 22:00:37 +05:30
def sanitize_svg_data ( data )
Gitlab :: Sanitizers :: SVG . clean ( data )
2016-04-02 18:10:28 +05:30
end
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
def ref_project
@ref_project || = @target_project || @project
end
2018-11-20 20:47:30 +05:30
def template_dropdown_names ( items )
grouped = items . group_by ( & :category )
categories = grouped . keys
categories . each_with_object ( { } ) do | category , hash |
hash [ category ] = grouped [ category ] . map do | item |
2018-12-05 23:21:45 +05:30
{ name : item . name , id : item . key }
2018-11-20 20:47:30 +05:30
end
end
end
private :template_dropdown_names
2018-12-13 13:39:08 +05:30
def licenses_for_select ( project )
2018-12-05 23:21:45 +05:30
@licenses_for_select || = template_dropdown_names ( TemplateFinder . build ( :licenses , project ) . execute )
end
2018-12-13 13:39:08 +05:30
def gitignore_names ( project )
2018-12-05 23:21:45 +05:30
@gitignore_names || = template_dropdown_names ( TemplateFinder . build ( :gitignores , project ) . execute )
2016-06-22 15:30:34 +05:30
end
2016-06-02 11:05:42 +05:30
2018-12-13 13:39:08 +05:30
def gitlab_ci_ymls ( project )
2018-12-05 23:21:45 +05:30
@gitlab_ci_ymls || = template_dropdown_names ( TemplateFinder . build ( :gitlab_ci_ymls , project ) . execute )
2017-08-17 22:00:37 +05:30
end
2020-10-24 23:57:45 +05:30
def metrics_dashboard_ymls ( project )
@metrics_dashboard_ymls || = template_dropdown_names ( TemplateFinder . build ( :metrics_dashboard_ymls , project ) . execute )
end
2018-12-13 13:39:08 +05:30
def dockerfile_names ( project )
2018-12-05 23:21:45 +05:30
@dockerfile_names || = template_dropdown_names ( TemplateFinder . build ( :dockerfiles , project ) . execute )
2016-09-13 17:45:13 +05:30
end
2018-12-13 13:39:08 +05:30
def blob_editor_paths ( project )
2016-09-13 17:45:13 +05:30
{
'relative-url-root' = > Rails . application . config . relative_url_root ,
'assets-prefix' = > Gitlab :: Application . config . assets . prefix ,
2018-12-13 13:39:08 +05:30
'blob-filename' = > @blob && @blob . path ,
2019-02-15 15:39:39 +05:30
'project-id' = > project . id ,
'is-markdown' = > @blob && @blob . path && Gitlab :: MarkupHelper . gitlab_markdown? ( @blob . path )
2016-09-13 17:45:13 +05:30
}
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
def copy_file_path_button ( file_path )
2019-12-21 20:55:43 +05:30
clipboard_button ( text : file_path , gfm : " ` #{ file_path } ` " , class : 'btn-clipboard btn-transparent' , title : _ ( 'Copy file path' ) )
2017-08-17 22:00:37 +05:30
end
def copy_blob_source_button ( blob )
return unless blob . rendered_as_text? ( ignore_errors : false )
2019-12-21 20:55:43 +05:30
clipboard_button ( target : " .blob-content[data-blob-id=' #{ blob . id } '] " , class : " btn btn-sm js-copy-blob-source-btn " , title : _ ( " Copy file contents " ) )
2017-08-17 22:00:37 +05:30
end
def open_raw_blob_button ( blob )
return if blob . empty?
2019-02-15 15:39:39 +05:30
return if blob . binary? || blob . stored_externally?
2017-09-10 17:25:29 +05:30
2019-07-07 11:18:12 +05:30
title = _ ( 'Open raw' )
2020-01-01 13:55:28 +05:30
link_to sprite_icon ( 'doc-code' ) ,
external_storage_url_or_path ( blob_raw_path ) ,
class : 'btn btn-sm has-tooltip' ,
target : '_blank' ,
rel : 'noopener noreferrer' ,
aria : { label : title } ,
title : title ,
data : { container : 'body' }
2018-11-18 11:00:15 +05:30
end
def download_blob_button ( blob )
return if blob . empty?
2017-08-17 22:00:37 +05:30
2019-07-07 11:18:12 +05:30
title = _ ( 'Download' )
2020-01-01 13:55:28 +05:30
link_to sprite_icon ( 'download' ) ,
external_storage_url_or_path ( blob_raw_path ( inline : false ) ) ,
download : @path ,
class : 'btn btn-sm has-tooltip' ,
target : '_blank' ,
rel : 'noopener noreferrer' ,
aria : { label : title } ,
title : title ,
data : { container : 'body' }
2017-08-17 22:00:37 +05:30
end
def blob_render_error_reason ( viewer )
case viewer . render_error
2017-09-10 17:25:29 +05:30
when :collapsed
" it is larger than #{ number_to_human_size ( viewer . collapse_limit ) } "
2017-08-17 22:00:37 +05:30
when :too_large
2017-09-10 17:25:29 +05:30
" it is larger than #{ number_to_human_size ( viewer . size_limit ) } "
2017-08-17 22:00:37 +05:30
when :server_side_but_stored_externally
case viewer . blob . external_storage
when :lfs
'it is stored in LFS'
when :build_artifact
'it is stored as a job artifact'
else
'it is stored externally'
end
end
end
def blob_render_error_options ( viewer )
error = viewer . render_error
options = [ ]
2017-09-10 17:25:29 +05:30
if error == :collapsed
2018-06-27 16:04:02 +05:30
options << link_to ( 'load it anyway' , url_for ( safe_params . merge ( viewer : viewer . type , expanded : true , format : nil ) ) )
2017-08-17 22:00:37 +05:30
end
# If the error is `:server_side_but_stored_externally`, the simple viewer will show the same error,
# so don't bother switching.
if viewer . rich? && viewer . blob . rendered_as_text? && error != :server_side_but_stored_externally
options << link_to ( 'view the source' , '#' , class : 'js-blob-viewer-switch-btn' , data : { viewer : 'simple' } )
end
2017-09-10 17:25:29 +05:30
options << link_to ( 'download it' , blob_raw_path , target : '_blank' , rel : 'noopener noreferrer' )
options
end
def contribution_options ( project )
options = [ ]
if can? ( current_user , :create_issue , project )
options << link_to ( " submit an issue " , new_project_issue_path ( project ) )
end
2018-05-09 12:01:36 +05:30
merge_project = merge_request_source_project_for_project ( @project )
2017-09-10 17:25:29 +05:30
if merge_project
options << link_to ( " create a merge request " , project_new_merge_request_path ( project ) )
end
2017-08-17 22:00:37 +05:30
options
end
2018-03-27 19:54:05 +05:30
def readable_blob ( options , path , project , ref )
blob = options . delete ( :blob )
blob || = project . repository . blob_at ( ref , path ) rescue nil
blob if blob & . readable_text?
end
def edit_blob_fork_params ( path )
{
to : path ,
notice : edit_in_new_fork_notice ,
notice_now : edit_in_new_fork_notice_now
}
end
def edit_modify_file_fork_params ( action )
{
to : request . fullpath ,
notice : edit_in_new_fork_notice_action ( action ) ,
notice_now : edit_in_new_fork_notice_now
}
end
def edit_fork_button_tag ( common_classes , project , label , params , action = 'edit' )
fork_path = project_forks_path ( project , namespace_key : current_user . namespace . id , continue : params )
button_tag label ,
class : " #{ common_classes } js-edit-blob-link-fork-toggler " ,
data : { action : action , fork_path : fork_path }
end
def edit_disabled_button_tag ( button_text , common_classes )
button_tag ( button_text , class : " #{ common_classes } disabled has-tooltip " , title : _ ( 'You can only edit files when you are on a branch' ) , data : { container : 'body' } )
end
2020-10-24 23:57:45 +05:30
def edit_link_tag ( link_text , edit_path , common_classes , data )
link_to link_text , edit_path , class : " #{ common_classes } btn-sm " , data : data
2018-03-27 19:54:05 +05:30
end
2020-10-24 23:57:45 +05:30
def edit_button_tag ( blob , common_classes , text , edit_path , project , ref , data )
2018-03-27 19:54:05 +05:30
if ! on_top_of_branch? ( project , ref )
edit_disabled_button_tag ( text , common_classes )
# This condition only applies to users who are logged in
elsif ! current_user || ( current_user && can_modify_blob? ( blob , project , ref ) )
2020-10-24 23:57:45 +05:30
edit_link_tag ( text , edit_path , common_classes , data )
2018-05-09 12:01:36 +05:30
elsif can? ( current_user , :fork_project , project ) && can? ( current_user , :create_merge_request_in , project )
2018-03-27 19:54:05 +05:30
edit_fork_button_tag ( common_classes , project , text , edit_blob_fork_params ( edit_path ) )
end
end
2020-04-08 14:13:33 +05:30
def show_suggest_pipeline_creation_celebration?
experiment_enabled? ( :suggest_pipeline ) &&
@blob . path == Gitlab :: FileDetector :: PATTERNS [ :gitlab_ci ] &&
2020-10-24 23:57:45 +05:30
@blob . auxiliary_viewer & . valid? ( project : @project , sha : @commit . sha , user : current_user ) &&
2020-04-08 14:13:33 +05:30
@project . uses_default_ci_config? &&
cookies [ suggest_pipeline_commit_cookie_name ] . present?
end
def suggest_pipeline_commit_cookie_name
" suggest_gitlab_ci_yml_commit_ #{ @project . id } "
end
def human_access
@project . team . human_max_access ( current_user & . id ) . try ( :downcase )
end
2020-11-24 15:15:51 +05:30
def editing_ci_config?
@path . to_s . end_with? ( Ci :: Pipeline :: CONFIG_EXTENSION ) ||
@path . to_s == @project . ci_config_path_or_default
end
2014-09-02 18:07:02 +05:30
end