From f9475e299c6f6b363d5ea302f1295a3ea0bf9adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Tue, 4 Sep 2018 10:39:08 +0000 Subject: Uploads to wiki stored inside the wiki git repository --- lib/api/entities.rb | 22 +++++++++++++ lib/api/wikis.rb | 31 +++++++++++++++++++ lib/banzai/filter/wiki_link_filter.rb | 10 +++--- lib/banzai/filter/wiki_link_filter/rewriter.rb | 21 ++++++++++--- lib/gitlab/file_markdown_link_builder.rb | 21 +++++++++++++ lib/gitlab/file_type_detection.rb | 43 ++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 lib/gitlab/file_markdown_link_builder.rb create mode 100644 lib/gitlab/file_type_detection.rb (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 59042d2b568..624eda3f5dd 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -10,6 +10,28 @@ module API expose :content end + class WikiAttachment < Grape::Entity + include Gitlab::FileMarkdownLinkBuilder + + expose :file_name + expose :file_path + expose :branch + expose :link do + expose :file_path, as: :url + expose :markdown do |_entity| + self.markdown_link + end + end + + def filename + object.file_name + end + + def secure_url + object.file_path + end + end + class UserSafe < Grape::Entity expose :id, :name, :username end diff --git a/lib/api/wikis.rb b/lib/api/wikis.rb index b3fc4e876ad..e86ebc573f2 100644 --- a/lib/api/wikis.rb +++ b/lib/api/wikis.rb @@ -1,6 +1,14 @@ module API class Wikis < Grape::API helpers do + def commit_params(attrs) + { + file_name: attrs[:file][:filename], + file_content: File.read(attrs[:file][:tempfile]), + branch_name: attrs[:branch] + } + end + params :wiki_page_params do requires :content, type: String, desc: 'Content of a wiki page' requires :title, type: String, desc: 'Title of a wiki page' @@ -84,6 +92,29 @@ module API status 204 WikiPages::DestroyService.new(user_project, current_user).execute(wiki_page) end + + desc 'Upload an attachment to the wiki repository' do + detail 'This feature was introduced in GitLab 11.3.' + success Entities::WikiAttachment + end + params do + requires :file, type: File, desc: 'The attachment file to be uploaded' + optional :branch, type: String, desc: 'The name of the branch' + end + post ":id/wikis/attachments", requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do + authorize! :create_wiki, user_project + + result = ::Wikis::CreateAttachmentService.new(user_project, + current_user, + commit_params(declared_params(include_missing: false))).execute + + if result[:status] == :success + status(201) + present OpenStruct.new(result[:result]), with: Entities::WikiAttachment + else + render_api_error!(result[:message], 400) + end + end end end end diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb index 870721f895d..1728a442533 100644 --- a/lib/banzai/filter/wiki_link_filter.rb +++ b/lib/banzai/filter/wiki_link_filter.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'uri' - module Banzai module Filter # HTML filter that "fixes" links to pages/files in a wiki. @@ -13,8 +11,12 @@ module Banzai def call return doc unless project_wiki? - doc.search('a:not(.gfm)').each do |el| - process_link_attr el.attribute('href') + doc.search('a:not(.gfm)').each { |el| process_link_attr(el.attribute('href')) } + doc.search('video').each { |el| process_link_attr(el.attribute('src')) } + doc.search('img').each do |el| + attr = el.attribute('data-src') || el.attribute('src') + + process_link_attr(attr) end doc diff --git a/lib/banzai/filter/wiki_link_filter/rewriter.rb b/lib/banzai/filter/wiki_link_filter/rewriter.rb index 072d24e5a11..4bf80aff418 100644 --- a/lib/banzai/filter/wiki_link_filter/rewriter.rb +++ b/lib/banzai/filter/wiki_link_filter/rewriter.rb @@ -10,11 +10,16 @@ module Banzai def apply_rules # Special case: relative URLs beginning with `/uploads/` refer to - # user-uploaded files and will be handled elsewhere. - return @uri.to_s if @uri.relative? && @uri.path.starts_with?('/uploads/') + # user-uploaded files will be handled elsewhere. + return @uri.to_s if public_upload? + + # Special case: relative URLs beginning with Wikis::CreateAttachmentService::ATTACHMENT_PATH + # refer to user-uploaded files to the wiki repository. + unless repository_upload? + apply_file_link_rules! + apply_hierarchical_link_rules! + end - apply_file_link_rules! - apply_hierarchical_link_rules! apply_relative_link_rules! @uri.to_s end @@ -39,6 +44,14 @@ module Banzai @uri = Addressable::URI.parse(link) end end + + def public_upload? + @uri.relative? && @uri.path.starts_with?('/uploads/') + end + + def repository_upload? + @uri.relative? && @uri.path.starts_with?(Wikis::CreateAttachmentService::ATTACHMENT_PATH) + end end end end diff --git a/lib/gitlab/file_markdown_link_builder.rb b/lib/gitlab/file_markdown_link_builder.rb new file mode 100644 index 00000000000..5386656efe7 --- /dev/null +++ b/lib/gitlab/file_markdown_link_builder.rb @@ -0,0 +1,21 @@ +# Builds the markdown link of a file +# It needs the methods filename and secure_url (final destination url) to be defined. +module Gitlab + module FileMarkdownLinkBuilder + include FileTypeDetection + + def markdown_link + return unless name = markdown_name + + markdown = "[#{name.gsub(']', '\\]')}](#{secure_url})" + markdown.prepend("!") if image_or_video? || dangerous? + markdown + end + + def markdown_name + return unless filename.present? + + image_or_video? ? File.basename(filename, File.extname(filename)) : filename + end + end +end diff --git a/lib/gitlab/file_type_detection.rb b/lib/gitlab/file_type_detection.rb new file mode 100644 index 00000000000..25ee07cf940 --- /dev/null +++ b/lib/gitlab/file_type_detection.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +# File helpers methods. +# It needs the method filename to be defined. +module Gitlab + module FileTypeDetection + IMAGE_EXT = %w[png jpg jpeg gif bmp tiff ico].freeze + # We recommend using the .mp4 format over .mov. Videos in .mov format can + # still be used but you really need to make sure they are served with the + # proper MIME type video/mp4 and not video/quicktime or your videos won't play + # on IE >= 9. + # http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html + VIDEO_EXT = %w[mp4 m4v mov webm ogv].freeze + # These extension types can contain dangerous code and should only be embedded inline with + # proper filtering. They should always be tagged as "Content-Disposition: attachment", not "inline". + DANGEROUS_EXT = %w[svg].freeze + + def image? + extension_match?(IMAGE_EXT) + end + + def video? + extension_match?(VIDEO_EXT) + end + + def image_or_video? + image? || video? + end + + def dangerous? + extension_match?(DANGEROUS_EXT) + end + + private + + def extension_match?(extensions) + return false unless filename + + extension = File.extname(filename).delete('.') + extensions.include?(extension.downcase) + end + end +end -- cgit v1.2.3