2018-08-18 11:19:57 +00:00
# frozen_string_literal: true
2014-06-07 12:46:58 +00:00
module BlobHelper
2018-09-06 04:34:25 +00:00
def highlight ( file_name , file_content , language : nil , plain : false )
highlighted = Gitlab :: Highlight . highlight ( file_name , file_content , plain : plain , language : language )
2018-01-15 15:00:58 +00:00
2016-07-15 05:43:49 +00:00
raw %( <pre class="code highlight"><code> #{ highlighted } </code></pre> )
2014-06-07 12:46:58 +00:00
end
def no_highlight_files
2014-12-03 11:50:00 +00:00
%w( credits changelog news copying copyright license authors )
2014-06-07 12:46:58 +00:00
end
2015-01-26 23:03:14 +00:00
2017-12-21 15:05:47 +00:00
def edit_blob_path ( project = @project , ref = @ref , path = @path , options = { } )
2017-06-29 17:06:35 +00:00
project_edit_blob_path ( project ,
2018-02-09 07:59:03 +00:00
tree_join ( ref , path ) ,
options [ :link_opts ] )
2017-04-06 16:36:38 +00:00
end
2018-02-23 15:52:18 +00:00
def ide_edit_path ( project = @project , ref = @ref , path = @path , options = { } )
2018-05-23 09:36:41 +00:00
segments = [ ide_path , 'project' , project . full_path , 'edit' , ref ]
segments . concat ( [ '-' , path ] ) if path . present?
File . join ( segments )
2018-02-23 15:52:18 +00:00
end
2018-02-22 12:54:19 +00:00
def edit_blob_button ( project = @project , ref = @ref , path = @path , options = { } )
2018-02-08 13:12:44 +00:00
return unless blob = readable_blob ( options , path , project , ref )
2015-12-18 09:03:34 +00:00
2017-04-06 16:36:38 +00:00
common_classes = " btn js-edit-blob #{ options [ :extra_class ] } "
2015-12-18 09:03:34 +00:00
2018-02-23 08:09:32 +00:00
edit_button_tag ( blob ,
common_classes ,
2018-02-23 15:04:31 +00:00
_ ( 'Edit' ) ,
2018-02-23 08:09:32 +00:00
edit_blob_path ( project , ref , path , options ) ,
project ,
ref )
2015-12-18 09:03:34 +00:00
end
2018-03-20 17:00:56 +00:00
def ide_edit_button ( project = @project , ref = @ref , path = @path , options = { } )
return unless blob = readable_blob ( options , path , project , ref )
edit_button_tag ( blob ,
'btn btn-default' ,
_ ( 'Web IDE' ) ,
ide_edit_path ( project , ref , path , options ) ,
project ,
ref )
end
2018-02-23 15:04:31 +00:00
def modify_file_button ( project = @project , ref = @ref , path = @path , label : , action : , btn_class : , modal_type : )
2015-12-18 09:03:34 +00:00
return unless current_user
blob = project . repository . blob_at ( ref , path ) rescue nil
return unless blob
2017-04-10 20:51:24 +00:00
common_classes = " btn btn- #{ btn_class } "
2016-01-21 21:46:49 +00:00
if ! on_top_of_branch? ( project , ref )
2017-04-10 20:51:24 +00:00
button_tag label , class : " #{ common_classes } disabled has-tooltip " , title : " You can only #{ action } files when you are on a branch " , data : { container : 'body' }
2017-05-02 22:45:50 +00:00
elsif blob . stored_externally?
2017-04-10 20:51:24 +00:00
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' }
2017-04-17 19:03:17 +00:00
elsif can_modify_blob? ( blob , project , ref )
2017-04-10 20:51:24 +00:00
button_tag label , class : " #{ common_classes } " , 'data-target' = > " # modal- #{ modal_type } -blob " , 'data-toggle' = > 'modal'
2018-04-06 16:27:12 +00:00
elsif can? ( current_user , :fork_project , project ) && can? ( current_user , :create_merge_request_in , project )
2018-02-15 11:03:37 +00:00
edit_fork_button_tag ( common_classes , project , label , edit_modify_file_fork_params ( action ) , action )
2015-12-18 09:03:34 +00:00
end
end
def replace_blob_link ( project = @project , ref = @ref , path = @path )
2018-02-23 15:04:31 +00:00
modify_file_button (
2015-12-18 09:03:34 +00:00
project ,
ref ,
path ,
label : " Replace " ,
action : " replace " ,
btn_class : " default " ,
modal_type : " upload "
)
end
def delete_blob_link ( project = @project , ref = @ref , path = @path )
2018-02-23 15:04:31 +00:00
modify_file_button (
2015-12-18 09:03:34 +00:00
project ,
ref ,
path ,
label : " Delete " ,
action : " delete " ,
btn_class : " remove " ,
modal_type : " remove "
)
end
2017-04-17 19:03:17 +00:00
def can_modify_blob? ( blob , project = @project , ref = @ref )
2017-05-02 22:45:50 +00:00
! blob . stored_externally? && can_edit_tree? ( project , ref )
2015-01-26 23:03:14 +00:00
end
def leave_edit_message
" Leave edit mode? \n All unsaved changes will be lost. "
end
def editing_preview_title ( filename )
2015-05-12 23:40:11 +00:00
if Gitlab :: MarkupHelper . previewable? ( filename )
2015-01-26 23:03:14 +00:00
'Preview'
else
2017-04-06 13:55:11 +00:00
'Preview changes'
2015-01-26 23:03:14 +00:00
end
end
2014-10-04 10:29:18 +00:00
# Return an image icon depending on the file mode and extension
#
# mode - File unix mode
# mode - File name
def blob_icon ( mode , name )
icon ( " #{ file_type_icon_class ( 'file' , mode , name ) } fw " )
end
2015-12-07 14:03:50 +00:00
2018-07-13 01:24:11 +00:00
def blob_raw_url ( ** kwargs )
2017-05-02 22:42:37 +00:00
if @build && @entry
2018-07-13 01:24:11 +00:00
raw_project_job_artifacts_url ( @project , @build , path : @entry . path , ** kwargs )
2017-05-02 22:42:37 +00:00
elsif @snippet
2017-04-13 16:47:28 +00:00
if @snippet . project_id
2018-07-13 01:24:11 +00:00
raw_project_snippet_url ( @project , @snippet , ** kwargs )
2017-04-13 16:47:28 +00:00
else
2018-07-13 01:24:11 +00:00
raw_snippet_url ( @snippet , ** kwargs )
2017-04-13 16:47:28 +00:00
end
elsif @blob
2018-07-13 01:24:11 +00:00
project_raw_url ( @project , @id , ** kwargs )
2017-04-13 16:47:28 +00:00
end
2017-04-13 17:21:07 +00:00
end
2018-07-13 01:24:11 +00:00
def blob_raw_path ( ** kwargs )
blob_raw_url ( ** kwargs , only_path : true )
2017-12-11 16:23:29 +00:00
end
2015-09-13 03:54:06 +00:00
# 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-04-13 17:21:07 +00:00
def sanitize_svg_data ( data )
Gitlab :: Sanitizers :: SVG . clean ( data )
2015-09-13 03:54:06 +00:00
end
2016-02-24 10:53:30 +00:00
# If we blindly set the 'real' content type when serving a Git blob we
# are enabling XSS attacks. An attacker could upload e.g. a Javascript
# file to a Git repository, trick the browser of a victim into
# downloading the blob, and then the 'application/javascript' content
# type would tell the browser to execute the attacker's Javascript. By
# overriding the content type and setting it to 'text/plain' (in the
# example of Javascript) we tell the browser of the victim not to
# execute untrusted data.
def safe_content_type ( blob )
2018-10-17 15:47:05 +00:00
if blob . extension == 'svg'
blob . mime_type
elsif blob . text?
2016-02-24 10:53:30 +00:00
'text/plain; charset=utf-8'
elsif blob . image?
blob . content_type
else
'application/octet-stream'
end
end
2016-03-03 16:59:47 +00:00
2018-10-17 15:47:05 +00:00
def content_disposition ( blob , inline )
return 'attachment' if blob . extension == 'svg'
inline ? 'inline' : 'attachment'
end
2016-06-24 19:43:46 +00:00
def ref_project
@ref_project || = @target_project || @project
end
2018-09-05 13:49:14 +00:00
def template_dropdown_names ( items )
2018-08-28 13:14:39 +00:00
grouped = items . group_by ( & :category )
categories = grouped . keys
categories . each_with_object ( { } ) do | category , hash |
hash [ category ] = grouped [ category ] . map do | item |
2018-10-02 23:00:38 +00:00
{ name : item . name , id : item . key }
2018-08-28 13:14:39 +00:00
end
end
end
2018-09-05 13:49:14 +00:00
private :template_dropdown_names
2018-08-28 13:14:39 +00:00
2018-10-05 16:21:21 +00:00
def licenses_for_select ( project )
2018-10-02 23:00:38 +00:00
@licenses_for_select || = template_dropdown_names ( TemplateFinder . build ( :licenses , project ) . execute )
end
2018-10-05 16:21:21 +00:00
def gitignore_names ( project )
2018-10-02 23:00:38 +00:00
@gitignore_names || = template_dropdown_names ( TemplateFinder . build ( :gitignores , project ) . execute )
2016-06-02 16:20:08 +00:00
end
2016-05-12 00:38:43 +00:00
2018-10-05 16:21:21 +00:00
def gitlab_ci_ymls ( project )
2018-10-02 23:00:38 +00:00
@gitlab_ci_ymls || = template_dropdown_names ( TemplateFinder . build ( :gitlab_ci_ymls , project ) . execute )
2016-04-29 14:25:03 +00:00
end
2016-08-19 15:17:14 +00:00
2018-10-05 16:21:21 +00:00
def dockerfile_names ( project )
2018-10-02 23:00:38 +00:00
@dockerfile_names || = template_dropdown_names ( TemplateFinder . build ( :dockerfiles , project ) . execute )
2016-11-02 15:41:32 +00:00
end
2018-10-05 16:21:21 +00:00
def blob_editor_paths ( project )
2016-08-19 15:17:14 +00:00
{
'relative-url-root' = > Rails . application . config . relative_url_root ,
'assets-prefix' = > Gitlab :: Application . config . assets . prefix ,
2018-08-03 13:24:26 +00:00
'blob-filename' = > @blob && @blob . path ,
2018-10-02 23:00:38 +00:00
'project-id' = > project . id
2016-08-19 15:17:14 +00:00
}
end
2017-03-14 17:58:52 +00:00
def copy_file_path_button ( file_path )
2017-04-06 21:10:14 +00:00
clipboard_button ( text : file_path , gfm : " ` #{ file_path } ` " , class : 'btn-clipboard btn-transparent prepend-left-5' , title : 'Copy file path to clipboard' )
2017-03-14 17:58:52 +00:00
end
2017-04-13 17:13:31 +00:00
def copy_blob_source_button ( blob )
2017-04-13 17:11:52 +00:00
return unless blob . rendered_as_text? ( ignore_errors : false )
2017-04-13 17:13:31 +00:00
clipboard_button ( target : " .blob-content[data-blob-id=' #{ blob . id } '] " , class : " btn btn-sm js-copy-blob-source-btn " , title : " Copy source to clipboard " )
2017-03-14 17:58:52 +00:00
end
2017-04-13 17:11:52 +00:00
def open_raw_blob_button ( blob )
2017-05-02 22:45:50 +00:00
return if blob . empty?
2018-07-13 01:24:11 +00:00
return if blob . raw_binary? || blob . stored_externally?
2018-07-18 01:19:53 +00:00
2018-07-13 01:24:11 +00:00
title = 'Open raw'
link_to icon ( 'file-code-o' ) , blob_raw_path , class : 'btn btn-sm has-tooltip' , target : '_blank' , rel : 'noopener noreferrer' , title : title , data : { container : 'body' }
2017-03-14 17:58:52 +00:00
end
2017-04-13 17:08:39 +00:00
2018-07-12 02:23:00 +00:00
def download_blob_button ( blob )
2018-07-09 01:55:36 +00:00
return if blob . empty?
2018-07-18 03:16:30 +00:00
2018-07-09 01:55:36 +00:00
title = 'Download'
2018-07-13 01:24:11 +00:00
link_to sprite_icon ( 'download' ) , blob_raw_path ( inline : false ) , download : @path , class : 'btn btn-sm has-tooltip' , target : '_blank' , rel : 'noopener noreferrer' , title : title , data : { container : 'body' }
2018-07-09 01:55:36 +00:00
end
2017-04-26 20:48:49 +00:00
def blob_render_error_reason ( viewer )
case viewer . render_error
2017-05-26 23:27:30 +00:00
when :collapsed
" it is larger than #{ number_to_human_size ( viewer . collapse_limit ) } "
2017-04-13 17:08:39 +00:00
when :too_large
2017-05-26 23:27:30 +00:00
" it is larger than #{ number_to_human_size ( viewer . size_limit ) } "
2017-05-02 22:45:50 +00:00
when :server_side_but_stored_externally
case viewer . blob . external_storage
when :lfs
'it is stored in LFS'
2017-05-02 22:42:37 +00:00
when :build_artifact
'it is stored as a job artifact'
2017-05-02 22:45:50 +00:00
else
'it is stored externally'
end
2017-04-13 17:08:39 +00:00
end
end
2017-04-21 18:22:04 +00:00
2017-04-26 20:48:49 +00:00
def blob_render_error_options ( viewer )
2017-05-02 22:45:50 +00:00
error = viewer . render_error
2017-04-21 18:22:04 +00:00
options = [ ]
2017-05-26 23:27:30 +00:00
if error == :collapsed
2018-04-08 04:35:30 +00:00
options << link_to ( 'load it anyway' , url_for ( safe_params . merge ( viewer : viewer . type , expanded : true , format : nil ) ) )
2017-04-21 18:22:04 +00:00
end
2017-05-02 22:45:50 +00:00
# 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
2017-04-21 18:33:48 +00:00
options << link_to ( 'view the source' , '#' , class : 'js-blob-viewer-switch-btn' , data : { viewer : 'simple' } )
2017-04-21 18:22:04 +00:00
end
2017-08-03 12:29:35 +00:00
options << link_to ( 'download it' , blob_raw_path , target : '_blank' , rel : 'noopener noreferrer' )
2017-04-21 18:22:04 +00:00
options
end
2017-05-13 17:06:51 +00:00
def contribution_options ( project )
options = [ ]
if can? ( current_user , :create_issue , project )
2017-06-29 17:06:35 +00:00
options << link_to ( " submit an issue " , new_project_issue_path ( project ) )
2017-05-13 17:06:51 +00:00
end
2018-04-06 16:27:12 +00:00
merge_project = merge_request_source_project_for_project ( @project )
2017-05-13 17:06:51 +00:00
if merge_project
2017-06-29 17:06:35 +00:00
options << link_to ( " create a merge request " , project_new_merge_request_path ( project ) )
2017-05-13 17:06:51 +00:00
end
options
end
2018-02-05 15:25:31 +00:00
2018-02-08 13:12:44 +00:00
def readable_blob ( options , path , project , ref )
2018-02-05 15:25:31 +00:00
blob = options . delete ( :blob )
blob || = project . repository . blob_at ( ref , path ) rescue nil
2018-02-08 13:12:44 +00:00
blob if blob & . readable_text?
2018-02-05 15:25:31 +00:00
end
2018-02-15 08:44:08 +00:00
def edit_blob_fork_params ( path )
{
2018-02-22 12:54:19 +00:00
to : path ,
notice : edit_in_new_fork_notice ,
notice_now : edit_in_new_fork_notice_now
2018-02-05 15:25:31 +00:00
}
2018-02-09 09:32:28 +00:00
end
2018-02-15 08:44:08 +00:00
def edit_modify_file_fork_params ( action )
{
2018-02-22 12:54:19 +00:00
to : request . fullpath ,
notice : edit_in_new_fork_notice_action ( action ) ,
notice_now : edit_in_new_fork_notice_now
2018-02-09 09:32:28 +00:00
}
2018-02-15 08:44:08 +00:00
end
2018-02-15 11:03:37 +00:00
def edit_fork_button_tag ( common_classes , project , label , params , action = 'edit' )
2018-02-15 08:44:08 +00:00
fork_path = project_forks_path ( project , namespace_key : current_user . namespace . id , continue : params )
2018-02-09 09:32:28 +00:00
2018-02-15 11:03:37 +00:00
button_tag label ,
2018-02-05 15:25:31 +00:00
class : " #{ common_classes } js-edit-blob-link-fork-toggler " ,
2018-02-15 11:03:37 +00:00
data : { action : action , fork_path : fork_path }
2018-02-05 15:25:31 +00:00
end
2018-02-08 10:58:47 +00:00
2018-02-22 12:54:19 +00:00
def edit_disabled_button_tag ( button_text , common_classes )
2018-02-08 10:58:47 +00:00
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
def edit_link_tag ( link_text , edit_path , common_classes )
link_to link_text , edit_path , class : " #{ common_classes } btn-sm "
end
2018-02-23 08:09:32 +00:00
def edit_button_tag ( blob , common_classes , text , edit_path , project , ref )
if ! on_top_of_branch? ( project , ref )
edit_disabled_button_tag ( text , common_classes )
# This condition only applies to users who are logged in
2018-02-23 15:52:18 +00:00
elsif ! current_user || ( current_user && can_modify_blob? ( blob , project , ref ) )
2018-02-23 08:09:32 +00:00
edit_link_tag ( text , edit_path , common_classes )
2018-04-06 12:18:58 +00:00
elsif can? ( current_user , :fork_project , project ) && can? ( current_user , :create_merge_request_in , project )
2018-02-23 12:58:27 +00:00
edit_fork_button_tag ( common_classes , project , text , edit_blob_fork_params ( edit_path ) )
2018-02-23 08:09:32 +00:00
end
end
2014-06-07 12:46:58 +00:00
end