summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/models/blob.rb126
-rw-r--r--app/models/blob_viewer/base.rb81
2 files changed, 151 insertions, 56 deletions
diff --git a/app/models/blob.rb b/app/models/blob.rb
index c6315a6789f..2b2425a926e 100644
--- a/app/models/blob.rb
+++ b/app/models/blob.rb
@@ -3,8 +3,10 @@ class Blob < SimpleDelegator
CACHE_TIME = 60 # Cache raw blobs referred to by a (mutable) ref for 1 minute
CACHE_TIME_IMMUTABLE = 3600 # Cache blobs referred to by an immutable reference for 1 hour
- # The maximum size of an SVG that can be displayed.
- MAXIMUM_SVG_SIZE = 2.megabytes
+ MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte
+
+ RICH_VIEWERS = [
+ ].freeze
attr_reader :project
@@ -43,82 +45,94 @@ class Blob < SimpleDelegator
end
def no_highlighting?
- size && size > 1.megabyte
+ size && size > MAXIMUM_TEXT_HIGHLIGHT_SIZE
end
- def only_display_raw?
+ def too_large?
size && truncated?
end
- def extension
- extname.downcase.delete('.')
+ def raw_size
+ if valid_lfs_pointer?
+ lfs_size
+ else
+ size
+ end
end
- def svg?
- text? && language && language.name == 'SVG'
+ def raw_binary?
+ if valid_lfs_pointer?
+ !rich_viewer&.text_based?
+ else
+ binary?
+ end
end
- def pdf?
- extension == 'pdf'
+ def extension
+ @extension ||= extname.downcase.delete('.')
end
- def ipython_notebook?
- text? && language&.name == 'Jupyter Notebook'
+ def video?
+ UploaderHelper::VIDEO_EXT.include?(extension)
end
- def sketch?
- binary? && extension == 'sketch'
+ def readable_text?
+ text? && !valid_lfs_pointer? && !too_large?
end
- def stl?
- extension == 'stl'
+ def valid_lfs_pointer?
+ lfs_pointer? && project.lfs_enabled?
end
- def markup?
- text? && Gitlab::MarkupHelper.markup?(name)
+ def invalid_lfs_pointer?
+ lfs_pointer? && !project.lfs_enabled?
end
- def size_within_svg_limits?
- size <= MAXIMUM_SVG_SIZE
+ def simple_viewer_class
+ if empty?
+ BlobViewer::Empty
+ elsif raw_binary?
+ BlobViewer::Download
+ else # text
+ BlobViewer::Text
+ end
end
- def video?
- UploaderHelper::VIDEO_EXT.include?(extname.downcase.delete('.'))
- end
-
- def to_partial_path(project)
- if lfs_pointer?
- if project.lfs_enabled?
- 'download'
- else
- 'text'
- end
- elsif image?
- 'image'
- elsif svg?
- 'svg'
- elsif pdf?
- 'pdf'
- elsif ipython_notebook?
- 'notebook'
- elsif sketch?
- 'sketch'
- elsif stl?
- 'stl'
- elsif markup?
- if only_display_raw?
- 'too_large'
- else
- 'markup'
- end
- elsif text?
- if only_display_raw?
- 'too_large'
- else
- 'text'
- end
+ def rich_viewer_class
+ if invalid_lfs_pointer? || empty?
+ nil
else
- 'download'
+ rich_viewers_classes.find { |viewer_class| viewer_class.can_render?(self) }
+ end
+ end
+
+ def simple_viewer
+ @simple_viewer ||= simple_viewer_class.new(self)
+ end
+
+ def rich_viewer
+ return @rich_viewer if defined?(@rich_viewer)
+
+ @rich_viewer ||= rich_viewer_class&.new(self)
+ end
+
+ def rendered_as_text?(override_max_size: false)
+ simple_viewer.is_a?(BlobViewer::Text) && !simple_viewer.render_error(override_max_size: override_max_size)
+ end
+
+ def show_viewer_switcher?
+ simple_viewer.is_a?(BlobViewer::Text) && rich_viewer
+ end
+
+ private
+
+ def rich_viewers_classes
+ if valid_lfs_pointer?
+ RICH_VIEWERS
+ elsif binary?
+ RICH_VIEWERS.reject(&:text_based?)
+ else # text
+ RICH_VIEWERS.select(&:text_based?)
end
end
end
diff --git a/app/models/blob_viewer/base.rb b/app/models/blob_viewer/base.rb
new file mode 100644
index 00000000000..37acacc0019
--- /dev/null
+++ b/app/models/blob_viewer/base.rb
@@ -0,0 +1,81 @@
+module BlobViewer
+ class Base
+ class_attribute :partial_name, :type, :extensions, :client_side, :text_based, :switcher_icon, :switcher_title, :max_size, :absolute_max_size
+
+ delegate :partial_path, :rich?, :simple?, :client_side?, :text_based?, to: :class
+
+ attr_reader :blob
+
+ def initialize(blob)
+ @blob = blob
+ end
+
+ def self.partial_path
+ "projects/blob/viewers/#{partial_name}"
+ end
+
+ def self.rich?
+ type == :rich
+ end
+
+ def self.simple?
+ type == :simple
+ end
+
+ def self.client_side?
+ client_side
+ end
+
+ def server_side?
+ !client_side?
+ end
+
+ def self.text_based?
+ text_based
+ end
+
+ def self.can_render?(blob)
+ !extensions || extensions.include?(blob.extension)
+ end
+
+ def can_override_max_size?
+ too_large? && !too_large?(override_max_size: true)
+ end
+
+ def relevant_max_size
+ if too_large?(override_max_size: true)
+ absolute_max_size
+ elsif too_large?
+ max_size
+ end
+ end
+
+ def render_error(override_max_size: false)
+ if too_large?(override_max_size: override_max_size)
+ :too_large
+ elsif server_side_but_stored_in_lfs?
+ :server_side_but_stored_in_lfs
+ end
+ end
+
+ def prepare!
+ if server_side? && blob.project
+ blob.load_all_data!(blob.project.repository)
+ end
+ end
+
+ private
+
+ def too_large?(override_max_size: false)
+ if override_max_size
+ blob.raw_size > absolute_max_size
+ else
+ blob.raw_size > max_size
+ end
+ end
+
+ def server_side_but_stored_in_lfs?
+ !client_side? && blob.valid_lfs_pointer?
+ end
+ end
+end