2014-09-02 18:07:02 +05:30
module BlobHelper
2016-08-24 12:49:21 +05:30
def highlight ( blob_name , blob_content , repository : nil , plain : false )
highlighted = Gitlab :: Highlight . highlight ( blob_name , blob_content , plain : plain , repository : repository )
raw %( <pre class="code highlight"><code> #{ highlighted } </code></pre> )
2014-09-02 18:07:02 +05:30
end
def no_highlight_files
2015-04-26 12:48:37 +05:30
%w( credits changelog news copying copyright license authors )
end
2017-08-17 22:00:37 +05:30
def edit_path ( project = @project , ref = @ref , path = @path , options = { } )
namespace_project_edit_blob_path ( project . namespace , project ,
tree_join ( ref , path ) ,
options [ :link_opts ] )
end
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
def edit_blob_link ( project = @project , ref = @ref , path = @path , options = { } )
2016-09-13 17:45:13 +05:30
blob = options . delete ( :blob )
blob || = project . repository . blob_at ( ref , path ) rescue nil
2016-01-14 18:37:52 +05:30
2016-09-13 17:45:13 +05:30
return unless blob
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
common_classes = " btn js-edit-blob #{ options [ :extra_class ] } "
2016-01-14 18:37:52 +05:30
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 'Edit' , class : " #{ common_classes } disabled has-tooltip " , title : " You can only edit files when you are on a branch " , data : { container : 'body' }
# This condition applies to anonymous or users who can edit directly
elsif ! current_user || ( current_user && can_modify_blob? ( blob , project , ref ) )
link_to 'Edit' , edit_path ( project , ref , path , options ) , class : " #{ common_classes } btn-sm "
elsif current_user && can? ( current_user , :fork_project , project )
2016-01-14 18:37:52 +05:30
continue_params = {
2017-08-17 22:00:37 +05:30
to : edit_path ( project , ref , path , options ) ,
2016-01-14 18:37:52 +05:30
notice : edit_in_new_fork_notice ,
notice_now : edit_in_new_fork_notice_now
}
2016-04-02 18:10:28 +05:30
fork_path = namespace_project_forks_path ( project . namespace , project , namespace_key : current_user . namespace . id , continue : continue_params )
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
button_tag 'Edit' ,
class : " #{ common_classes } js-edit-blob-link-fork-toggler " ,
data : { action : 'edit' , fork_path : fork_path }
2016-01-14 18:37:52 +05:30
end
end
def modify_file_link ( project = @project , ref = @ref , path = @path , label : , action : , btn_class : , modal_type : )
return unless current_user
blob = project . repository . blob_at ( ref , path ) rescue nil
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'
2016-01-14 18:37:52 +05:30
elsif can? ( current_user , :fork_project , project )
continue_params = {
2017-08-17 22:00:37 +05:30
to : request . fullpath ,
2016-01-14 18:37:52 +05:30
notice : edit_in_new_fork_notice + " Try to #{ action } this file again. " ,
notice_now : edit_in_new_fork_notice_now
}
2016-04-02 18:10:28 +05:30
fork_path = namespace_project_forks_path ( project . namespace , project , namespace_key : current_user . namespace . id , continue : continue_params )
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
button_tag label ,
class : " #{ common_classes } js-edit-blob-link-fork-toggler " ,
data : { action : action , fork_path : fork_path }
2016-01-14 18:37:52 +05:30
end
end
def replace_blob_link ( project = @project , ref = @ref , path = @path )
modify_file_link (
project ,
ref ,
path ,
label : " Replace " ,
action : " replace " ,
btn_class : " default " ,
modal_type : " upload "
)
end
def delete_blob_link ( project = @project , ref = @ref , path = @path )
modify_file_link (
project ,
ref ,
path ,
label : " Delete " ,
action : " delete " ,
btn_class : " remove " ,
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
" Leave edit mode? \n All unsaved changes will be lost. "
end
def editing_preview_title ( filename )
2015-09-11 14:41:01 +05:30
if Gitlab :: MarkupHelper . previewable? ( filename )
2015-04-26 12:48:37 +05:30
'Preview'
else
2017-08-17 22:00:37 +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 )
icon ( " #{ file_type_icon_class ( 'file' , mode , name ) } fw " )
2014-09-02 18:07:02 +05:30
end
2015-12-23 02:04:40 +05:30
2017-08-17 22:00:37 +05:30
def blob_raw_url
if @build && @entry
raw_namespace_project_build_artifacts_path ( @project . namespace , @project , @build , path : @entry . path )
elsif @snippet
if @snippet . project_id
raw_namespace_project_snippet_path ( @project . namespace , @project , @snippet )
else
raw_snippet_path ( @snippet )
end
elsif @blob
namespace_project_raw_path ( @project . namespace , @project , @id )
2015-12-23 02:04:40 +05:30
end
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
# 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 )
if blob . text?
'text/plain; charset=utf-8'
elsif blob . image?
blob . content_type
else
'application/octet-stream'
end
end
def cached_blob?
stale = stale? ( etag : @blob . id ) # The #stale? method sets cache headers.
# Because we are opionated we set the cache headers ourselves.
response . cache_control [ :public ] = @project . public?
2017-08-17 22:00:37 +05:30
response . cache_control [ :max_age ] =
if @ref && @commit && @ref == @commit . id
# This is a link to a commit by its commit SHA. That means that the blob
# is immutable. The only reason to invalidate the cache is if the commit
# was deleted or if the user lost access to the repository.
Blob :: CACHE_TIME_IMMUTABLE
else
# A branch or tag points at this blob. That means that the expected blob
# value may change over time.
Blob :: CACHE_TIME
end
2016-06-02 11:05:42 +05:30
response . etag = @blob . id
! stale
end
def licenses_for_select
return @licenses_for_select if defined? ( @licenses_for_select )
licenses = Licensee :: License . all
@licenses_for_select = {
2016-06-22 15:30:34 +05:30
Popular : licenses . select ( & :featured ) . map { | license | { name : license . name , id : license . key } } ,
Other : licenses . reject ( & :featured ) . map { | license | { name : license . name , id : license . key } }
2016-06-02 11:05:42 +05:30
}
end
2016-09-13 17:45:13 +05:30
def ref_project
@ref_project || = @target_project || @project
end
2016-06-02 11:05:42 +05:30
def gitignore_names
2016-09-13 17:45:13 +05:30
@gitignore_names || = Gitlab :: Template :: GitignoreTemplate . dropdown_names
2016-06-22 15:30:34 +05:30
end
2016-06-02 11:05:42 +05:30
2016-06-22 15:30:34 +05:30
def gitlab_ci_ymls
2017-08-17 22:00:37 +05:30
@gitlab_ci_ymls || = Gitlab :: Template :: GitlabCiYmlTemplate . dropdown_names ( params [ :context ] )
end
def dockerfile_names
@dockerfile_names || = Gitlab :: Template :: DockerfileTemplate . dropdown_names
2016-09-13 17:45:13 +05:30
end
def blob_editor_paths
{
'relative-url-root' = > Rails . application . config . relative_url_root ,
'assets-prefix' = > Gitlab :: Application . config . assets . prefix ,
'blob-language' = > @blob && @blob . language . try ( :ace_mode )
}
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
def copy_file_path_button ( file_path )
clipboard_button ( text : file_path , gfm : " ` #{ file_path } ` " , class : 'btn-clipboard btn-transparent prepend-left-5' , title : 'Copy file path to clipboard' )
end
def copy_blob_source_button ( blob )
return unless blob . rendered_as_text? ( ignore_errors : false )
clipboard_button ( target : " .blob-content[data-blob-id=' #{ blob . id } '] " , class : " btn btn-sm js-copy-blob-source-btn " , title : " Copy source to clipboard " )
end
def open_raw_blob_button ( blob )
return if blob . empty?
if blob . raw_binary? || blob . stored_externally?
icon = icon ( 'download' )
title = 'Download'
else
icon = icon ( 'file-code-o' )
title = 'Open raw'
end
link_to icon , blob_raw_url , class : 'btn btn-sm has-tooltip' , target : '_blank' , rel : 'noopener noreferrer' , title : title , data : { container : 'body' }
end
def blob_render_error_reason ( viewer )
case viewer . render_error
when :too_large
max_size =
if viewer . absolutely_too_large?
viewer . absolute_max_size
elsif viewer . too_large?
viewer . max_size
end
" it is larger than #{ number_to_human_size ( max_size ) } "
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 = [ ]
if error == :too_large && viewer . can_override_max_size?
options << link_to ( 'load it anyway' , url_for ( params . merge ( viewer : viewer . type , override_max_size : true , format : nil ) ) )
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
options << link_to ( 'download it' , blob_raw_url , target : '_blank' , rel : 'noopener noreferrer' )
options
end
2014-09-02 18:07:02 +05:30
end