From 5cb27e9fa74c7234195e10ade933e8a475cff403 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 13 Apr 2017 12:21:07 -0500 Subject: [PATCH] Add rich blob viewers --- app/helpers/blob_helper.rb | 9 ++++++--- app/models/blob.rb | 8 ++++++++ app/models/blob_viewer/binary_stl.rb | 10 ++++++++++ app/models/blob_viewer/image.rb | 12 ++++++++++++ app/models/blob_viewer/markup.rb | 10 ++++++++++ app/models/blob_viewer/notebook.rb | 12 ++++++++++++ app/models/blob_viewer/pdf.rb | 12 ++++++++++++ app/models/blob_viewer/rich.rb | 11 +++++++++++ app/models/blob_viewer/server_side.rb | 11 +++++++++++ app/models/blob_viewer/sketch.rb | 12 ++++++++++++ app/models/blob_viewer/svg.rb | 12 ++++++++++++ app/models/blob_viewer/text_stl.rb | 10 ++++++++++ app/views/projects/blob/_image.html.haml | 2 -- app/views/projects/blob/_svg.html.haml | 9 --------- app/views/projects/blob/viewers/_image.html.haml | 2 ++ app/views/projects/blob/viewers/_markup.html.haml | 3 +++ .../projects/blob/{ => viewers}/_notebook.html.haml | 2 +- app/views/projects/blob/{ => viewers}/_pdf.html.haml | 2 +- .../projects/blob/{ => viewers}/_sketch.html.haml | 2 +- app/views/projects/blob/{ => viewers}/_stl.html.haml | 2 +- app/views/projects/blob/viewers/_svg.html.haml | 4 ++++ 21 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 app/models/blob_viewer/binary_stl.rb create mode 100644 app/models/blob_viewer/image.rb create mode 100644 app/models/blob_viewer/markup.rb create mode 100644 app/models/blob_viewer/notebook.rb create mode 100644 app/models/blob_viewer/pdf.rb create mode 100644 app/models/blob_viewer/rich.rb create mode 100644 app/models/blob_viewer/server_side.rb create mode 100644 app/models/blob_viewer/sketch.rb create mode 100644 app/models/blob_viewer/svg.rb create mode 100644 app/models/blob_viewer/text_stl.rb delete mode 100644 app/views/projects/blob/_image.html.haml delete mode 100644 app/views/projects/blob/_svg.html.haml create mode 100644 app/views/projects/blob/viewers/_image.html.haml create mode 100644 app/views/projects/blob/viewers/_markup.html.haml rename app/views/projects/blob/{ => viewers}/_notebook.html.haml (57%) rename app/views/projects/blob/{ => viewers}/_pdf.html.haml (57%) rename app/views/projects/blob/{ => viewers}/_sketch.html.haml (74%) rename app/views/projects/blob/{ => viewers}/_stl.html.haml (83%) create mode 100644 app/views/projects/blob/viewers/_svg.html.haml diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 36b16421e8f..ade9e19cea8 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -134,12 +134,15 @@ module BlobHelper end end + def blob_raw_url + namespace_project_raw_path(@project.namespace, @project, @id) + end + # 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. - def sanitize_svg(blob) - blob.data = Gitlab::Sanitizers::SVG.clean(blob.data) - blob + def sanitize_svg_data(data) + Gitlab::Sanitizers::SVG.clean(data) end # If we blindly set the 'real' content type when serving a Git blob we diff --git a/app/models/blob.rb b/app/models/blob.rb index 2b2425a926e..26ee2c883a0 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -6,6 +6,14 @@ class Blob < SimpleDelegator MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte RICH_VIEWERS = [ + BlobViewer::Image, + BlobViewer::PDF, + BlobViewer::Sketch, + BlobViewer::BinarySTL, + BlobViewer::TextSTL, + BlobViewer::Notebook, + BlobViewer::SVG, + BlobViewer::Markup, ].freeze attr_reader :project diff --git a/app/models/blob_viewer/binary_stl.rb b/app/models/blob_viewer/binary_stl.rb new file mode 100644 index 00000000000..6cb54d49d86 --- /dev/null +++ b/app/models/blob_viewer/binary_stl.rb @@ -0,0 +1,10 @@ +module BlobViewer + class BinarySTL < Base + include Rich + include ClientSide + + self.partial_name = 'stl' + self.extensions = %w(stl) + self.text_based = false + end +end diff --git a/app/models/blob_viewer/image.rb b/app/models/blob_viewer/image.rb new file mode 100644 index 00000000000..b78f82df38f --- /dev/null +++ b/app/models/blob_viewer/image.rb @@ -0,0 +1,12 @@ +module BlobViewer + class Image < Base + include Rich + include ClientSide + + self.partial_name = 'image' + self.extensions = UploaderHelper::IMAGE_EXT + self.text_based = false + self.switcher_icon = 'picture-o' + self.switcher_title = 'image' + end +end diff --git a/app/models/blob_viewer/markup.rb b/app/models/blob_viewer/markup.rb new file mode 100644 index 00000000000..34740661320 --- /dev/null +++ b/app/models/blob_viewer/markup.rb @@ -0,0 +1,10 @@ +module BlobViewer + class Markup < Base + include Rich + include ServerSide + + self.partial_name = 'markup' + self.extensions = Gitlab::MarkupHelper::EXTENSIONS + self.text_based = true + end +end diff --git a/app/models/blob_viewer/notebook.rb b/app/models/blob_viewer/notebook.rb new file mode 100644 index 00000000000..c5231f1e691 --- /dev/null +++ b/app/models/blob_viewer/notebook.rb @@ -0,0 +1,12 @@ +module BlobViewer + class Notebook < Base + include Rich + include ClientSide + + self.partial_name = 'notebook' + self.extensions = %w(ipynb) + self.text_based = true + self.switcher_icon = 'file-text-o' + self.switcher_title = 'notebook' + end +end diff --git a/app/models/blob_viewer/pdf.rb b/app/models/blob_viewer/pdf.rb new file mode 100644 index 00000000000..1067388c72a --- /dev/null +++ b/app/models/blob_viewer/pdf.rb @@ -0,0 +1,12 @@ +module BlobViewer + class PDF < Base + include Rich + include ClientSide + + self.partial_name = 'pdf' + self.extensions = %w(pdf) + self.text_based = false + self.switcher_icon = 'file-pdf-o' + self.switcher_title = 'PDF' + end +end diff --git a/app/models/blob_viewer/rich.rb b/app/models/blob_viewer/rich.rb new file mode 100644 index 00000000000..be373dbc948 --- /dev/null +++ b/app/models/blob_viewer/rich.rb @@ -0,0 +1,11 @@ +module BlobViewer + module Rich + extend ActiveSupport::Concern + + included do + self.type = :rich + self.switcher_icon = 'file-text-o' + self.switcher_title = 'rendered file' + end + end +end diff --git a/app/models/blob_viewer/server_side.rb b/app/models/blob_viewer/server_side.rb new file mode 100644 index 00000000000..899107d02ea --- /dev/null +++ b/app/models/blob_viewer/server_side.rb @@ -0,0 +1,11 @@ +module BlobViewer + module ServerSide + extend ActiveSupport::Concern + + included do + self.client_side = false + self.max_size = 2.megabytes + self.absolute_max_size = 5.megabytes + end + end +end diff --git a/app/models/blob_viewer/sketch.rb b/app/models/blob_viewer/sketch.rb new file mode 100644 index 00000000000..3de94efe67d --- /dev/null +++ b/app/models/blob_viewer/sketch.rb @@ -0,0 +1,12 @@ +module BlobViewer + class Sketch < Base + include Rich + include ClientSide + + self.partial_name = 'sketch' + self.extensions = %w(sketch) + self.text_based = false + self.switcher_icon = 'file-image-o' + self.switcher_title = 'preview' + end +end diff --git a/app/models/blob_viewer/svg.rb b/app/models/blob_viewer/svg.rb new file mode 100644 index 00000000000..5fd11a98462 --- /dev/null +++ b/app/models/blob_viewer/svg.rb @@ -0,0 +1,12 @@ +module BlobViewer + class SVG < Base + include Rich + include ServerSide + + self.partial_name = 'svg' + self.extensions = %w(svg) + self.text_based = true + self.switcher_icon = 'picture-o' + self.switcher_title = 'image' + end +end diff --git a/app/models/blob_viewer/text_stl.rb b/app/models/blob_viewer/text_stl.rb new file mode 100644 index 00000000000..1b238777c32 --- /dev/null +++ b/app/models/blob_viewer/text_stl.rb @@ -0,0 +1,10 @@ +module BlobViewer + class TextSTL < Base + include Rich + include ClientSide + + self.partial_name = 'stl' + self.extensions = %w(stl) + self.text_based = true + end +end diff --git a/app/views/projects/blob/_image.html.haml b/app/views/projects/blob/_image.html.haml deleted file mode 100644 index 73877d730f5..00000000000 --- a/app/views/projects/blob/_image.html.haml +++ /dev/null @@ -1,2 +0,0 @@ -.file-content.image_file - %img{ src: namespace_project_raw_path(@project.namespace, @project, @id), alt: blob.name } diff --git a/app/views/projects/blob/_svg.html.haml b/app/views/projects/blob/_svg.html.haml deleted file mode 100644 index 93be58fc658..00000000000 --- a/app/views/projects/blob/_svg.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -- if blob.size_within_svg_limits? - -# We need to scrub SVG but we cannot do so in the RawController: it would - -# be wrong/strange if RawController modified the data. - - blob.load_all_data!(@repository) - - blob = sanitize_svg(blob) - .file-content.image_file - %img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}", alt: blob.name } -- else - = render 'too_large' diff --git a/app/views/projects/blob/viewers/_image.html.haml b/app/views/projects/blob/viewers/_image.html.haml new file mode 100644 index 00000000000..640d59b3174 --- /dev/null +++ b/app/views/projects/blob/viewers/_image.html.haml @@ -0,0 +1,2 @@ +.file-content.image_file + %img{ src: blob_raw_url, alt: viewer.blob.name } diff --git a/app/views/projects/blob/viewers/_markup.html.haml b/app/views/projects/blob/viewers/_markup.html.haml new file mode 100644 index 00000000000..ae8f3e05687 --- /dev/null +++ b/app/views/projects/blob/viewers/_markup.html.haml @@ -0,0 +1,3 @@ +- blob = viewer.blob +.file-content.wiki + = render_markup(blob.name, blob.data) diff --git a/app/views/projects/blob/_notebook.html.haml b/app/views/projects/blob/viewers/_notebook.html.haml similarity index 57% rename from app/views/projects/blob/_notebook.html.haml rename to app/views/projects/blob/viewers/_notebook.html.haml index ab1cf933944..2399fb16265 100644 --- a/app/views/projects/blob/_notebook.html.haml +++ b/app/views/projects/blob/viewers/_notebook.html.haml @@ -2,4 +2,4 @@ = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('notebook_viewer') -.file-content#js-notebook-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } +.file-content#js-notebook-viewer{ data: { endpoint: blob_raw_url } } diff --git a/app/views/projects/blob/_pdf.html.haml b/app/views/projects/blob/viewers/_pdf.html.haml similarity index 57% rename from app/views/projects/blob/_pdf.html.haml rename to app/views/projects/blob/viewers/_pdf.html.haml index 58dc88e3bf7..1dd179c4fdc 100644 --- a/app/views/projects/blob/_pdf.html.haml +++ b/app/views/projects/blob/viewers/_pdf.html.haml @@ -2,4 +2,4 @@ = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('pdf_viewer') -.file-content#js-pdf-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } +.file-content#js-pdf-viewer{ data: { endpoint: blob_raw_url } } diff --git a/app/views/projects/blob/_sketch.html.haml b/app/views/projects/blob/viewers/_sketch.html.haml similarity index 74% rename from app/views/projects/blob/_sketch.html.haml rename to app/views/projects/blob/viewers/_sketch.html.haml index dad9369cb2a..49f716c2c59 100644 --- a/app/views/projects/blob/_sketch.html.haml +++ b/app/views/projects/blob/viewers/_sketch.html.haml @@ -2,6 +2,6 @@ = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('sketch_viewer') -.file-content#js-sketch-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } +.file-content#js-sketch-viewer{ data: { endpoint: blob_raw_url } } .js-loading-icon.text-center.prepend-top-default.append-bottom-default.js-loading-icon{ 'aria-label' => 'Loading Sketch preview' } = icon('spinner spin 2x', 'aria-hidden' => 'true'); diff --git a/app/views/projects/blob/_stl.html.haml b/app/views/projects/blob/viewers/_stl.html.haml similarity index 83% rename from app/views/projects/blob/_stl.html.haml rename to app/views/projects/blob/viewers/_stl.html.haml index a9332a0eeb6..e4e9d746176 100644 --- a/app/views/projects/blob/_stl.html.haml +++ b/app/views/projects/blob/viewers/_stl.html.haml @@ -2,7 +2,7 @@ = page_specific_javascript_bundle_tag('stl_viewer') .file-content.is-stl-loading - .text-center#js-stl-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } + .text-center#js-stl-viewer{ data: { endpoint: blob_raw_url } } = icon('spinner spin 2x', class: 'prepend-top-default append-bottom-default', 'aria-hidden' => 'true', 'aria-label' => 'Loading') .text-center.prepend-top-default.append-bottom-default.stl-controls .btn-group diff --git a/app/views/projects/blob/viewers/_svg.html.haml b/app/views/projects/blob/viewers/_svg.html.haml new file mode 100644 index 00000000000..62f647581b6 --- /dev/null +++ b/app/views/projects/blob/viewers/_svg.html.haml @@ -0,0 +1,4 @@ +- blob = viewer.blob +- data = sanitize_svg_data(blob.data) +.file-content.image_file + %img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(data)}", alt: blob.name }