diff --git a/app/assets/javascripts/markdown_area.js.coffee b/app/assets/javascripts/markdown_area.js.coffee index def5d12a820f..96e48a04bf4e 100644 --- a/app/assets/javascripts/markdown_area.js.coffee +++ b/app/assets/javascripts/markdown_area.js.coffee @@ -1,6 +1,9 @@ formatLink = (str) -> - "![" + str.alt + "](" + str.url + ")" - + text = "[" + str.alt + "](" + str.url + ")" + if str.is_image + text = "!" + text + text + $(document).ready -> alertClass = "alert alert-danger alert-dismissable div-dropzone-alert" alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\"" @@ -10,7 +13,7 @@ $(document).ready -> iconPicture = "" iconSpinner = "" btnAlert = "" - project_image_path_upload = window.project_image_path_upload or null + project_file_path_upload = window.project_file_path_upload or null $("textarea.markdown-area").wrap "
" @@ -23,13 +26,12 @@ $(document).ready -> dropzone = $(".div-dropzone").dropzone( - url: project_image_path_upload + url: project_file_path_upload dictDefaultMessage: "" clickable: true - paramName: "markdown_img" + paramName: "markdown_file" maxFilesize: 10 uploadMultiple: false - acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png" headers: "X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content") diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 9e14af620481..c5b5ad54f38c 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -162,12 +162,12 @@ def unarchive end end - def upload_image - link_to_image = ::Projects::ImageService.new(repository, params, root_url).execute + def upload_file + link_to_file = ::Projects::FileService.new(repository, params, root_url).execute respond_to do |format| - if link_to_image - format.json { render json: { link: link_to_image } } + if link_to_file + format.json { render json: { link: link_to_file } } else format.json { render json: "Invalid file.", status: :unprocessable_entity } end @@ -176,13 +176,8 @@ def upload_image private - def upload_path - base_dir = FileUploader.generate_dir - File.join(repository.path_with_namespace, base_dir) - end - - def accepted_images - %w(png jpg jpeg gif) + def invalid_file(error) + render json: { message: error.message }, status: :internal_server_error end def set_title diff --git a/app/services/projects/file_service.rb b/app/services/projects/file_service.rb new file mode 100644 index 000000000000..a621c474dff1 --- /dev/null +++ b/app/services/projects/file_service.rb @@ -0,0 +1,49 @@ +module Projects + class FileService < BaseService + include Rails.application.routes.url_helpers + def initialize(repository, params, root_url) + @repository, @params, @root_url = repository, params.dup, root_url + end + + def execute + uploader = FileUploader.new('uploads', upload_path, accepted_files) + file = @params['markdown_file'] + + if file + alt = file.original_filename + uploader.store!(file) + link = { + 'alt' => File.basename(alt, '.*'), + 'url' => File.join(@root_url, uploader.url), + 'is_image' => image?(file) + } + else + link = nil + end + end + + protected + + def accepted_files + # insert accepted mime types here (e.g %w(jpg jpeg gif png)) + nil + end + + def accepted_images + %w(jpg jpeg gif png) + end + + def image?(file) + accepted_images.map { |format| file.content_type.include? format }.any? + end + + def upload_path + base_dir = FileUploader.generate_dir + File.join(@repository.path_with_namespace, base_dir) + end + + def correct_mime_type?(file) + accepted_files.map { |format| image.content_type.include? format }.any? + end + end +end diff --git a/app/services/projects/image_service.rb b/app/services/projects/image_service.rb deleted file mode 100644 index c79ddddd9720..000000000000 --- a/app/services/projects/image_service.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Projects - class ImageService < BaseService - include Rails.application.routes.url_helpers - def initialize(repository, params, root_url) - @repository, @params, @root_url = repository, params.dup, root_url - end - - def execute - uploader = FileUploader.new('uploads', upload_path, accepted_images) - image = @params['markdown_img'] - - if image && correct_mime_type?(image) - alt = image.original_filename - uploader.store!(image) - link = { - 'alt' => File.basename(alt, '.*'), - 'url' => File.join(@root_url, uploader.url) - } - else - link = nil - end - end - - protected - - def upload_path - base_dir = FileUploader.generate_dir - File.join(@repository.path_with_namespace, base_dir) - end - - def accepted_images - %w(png jpg jpeg gif) - end - - def correct_mime_type?(image) - accepted_images.map{ |format| image.content_type.include? format }.any? - end - end -end diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index 0fa987c93f64..260cd21106cc 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -21,7 +21,7 @@ def cache_dir end def extension_white_list - @allowed_extensions + @allowed_extensions || super end def store!(file) diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml index d29a79731006..7f414b44275c 100644 --- a/app/views/projects/issues/_form.html.haml +++ b/app/views/projects/issues/_form.html.haml @@ -23,7 +23,7 @@ = f.text_area :description, class: 'form-control js-gfm-input markdown-area', rows: 14 .col-sm-12.hint .pull-left Issues are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. - .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .clearfix .error-alert %hr @@ -97,4 +97,4 @@ e.preventDefault(); }); - window.project_image_path_upload = "#{upload_image_project_path @project}"; + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml index 9ef232b52688..1ba2904917f4 100644 --- a/app/views/projects/merge_requests/_form.html.haml +++ b/app/views/projects/merge_requests/_form.html.haml @@ -25,7 +25,7 @@ = f.text_area :description, class: "form-control js-gfm-input markdown-area", rows: 14 .col-sm-12.hint .pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. - .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .clearfix .error-alert %hr @@ -103,4 +103,4 @@ } }); - window.project_image_path_upload = "#{upload_image_project_path @project}"; + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 01bc10421bd9..b40f86abea58 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -26,7 +26,7 @@ = f.text_area :description, class: "form-control js-gfm-input markdown-area", rows: 10 .col-sm-12.hint .pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. - .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .clearfix .error-alert .form-group @@ -85,4 +85,4 @@ e.preventDefault(); }); - window.project_image_path_upload = "#{upload_image_project_path @project}"; + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index 979c27daa2b9..dda78ea2a861 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -24,7 +24,7 @@ = f.text_area :description, maxlength: 2000, class: "form-control markdown-area", rows: 10 .hint .pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. - .pull-left Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-left Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .clearfix .error-alert .col-md-6 @@ -50,4 +50,4 @@ onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } }).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val())); - window.project_image_path_upload = "#{upload_image_project_path @project}"; + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml index b62aada3a9a0..073c3e9a385e 100644 --- a/app/views/projects/notes/_form.html.haml +++ b/app/views/projects/notes/_form.html.haml @@ -18,7 +18,7 @@ .light.clearfix .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'} - .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .note-preview-holder.hide .js-note-preview @@ -38,4 +38,4 @@ = f.file_field :attachment, class: "js-note-attachment-input hidden" :javascript - window.project_image_path_upload = "#{upload_image_project_path @project}"; + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 0a24e36ae848..46321e747bb0 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -25,7 +25,7 @@ = f.text_area :content, class: 'form-control js-gfm-input markdown-area', rows: 18 .col-sm-12.hint .pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'} - .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .clearfix .error-alert .form-group @@ -41,5 +41,4 @@ = link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel" :javascript - window.project_image_path_upload = "#{upload_image_project_path @project}"; - + window.project_file_path_upload = "#{upload_file_project_path @project}"; diff --git a/config/routes.rb b/config/routes.rb index 67ff66757e63..b4d1d5374545 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -168,7 +168,7 @@ post :fork post :archive post :unarchive - post :upload_image + post :upload_file get :autocomplete_sources get :import put :retry_import diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 944df5314bd0..c1e82ddfc545 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -6,37 +6,40 @@ let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } - describe "POST #upload_image" do + describe "POST #upload_file" do before do sign_in(user) project.team << [user, :developer] end - context "without params['markdown_img']" do + context "without params['markdown_file']" do it "returns an error" do - post :upload_image, id: project.to_param, format: :json + post :upload_file, id: project.to_param, format: :json expect(response.status).to eq(422) end end - context "with invalid file" do + context "with valid image" do before do - post :upload_image, id: project.to_param, markdown_img: txt, format: :json + post :upload_file, id: project.to_param, markdown_file: jpg, format: :json end - it "returns an error" do - expect(response.status).to eq(422) + it "returns a content with original filename, new link, and correct type." do + expect(response.body).to match "\"alt\":\"rails_sample\"" + expect(response.body).to match "\"url\":\"http://test.host/uploads/#{project.path_with_namespace}" + expect(response.body).to match "\"is_image\": true end end - context "with valid file" do + context "with valid non-image file" do before do - post :upload_image, id: project.to_param, markdown_img: jpg, format: :json + post :upload_file, id: project.to_param, markdown_file: txt, format: :json end - it "returns a content with original filename and new link." do - expect(response.body).to match "\"alt\":\"rails_sample\"" + it "returns a content with original filename, new link, and correct type." do + expect(response.body).to match "\"alt\":\"doc_sample\"" expect(response.body).to match "\"url\":\"http://test.host/uploads/#{project.path_with_namespace}" + expect(response.body).to match "\"is_image\": false end end end diff --git a/spec/services/projects/image_service_spec.rb b/spec/services/projects/file_service_spec.rb similarity index 65% rename from spec/services/projects/image_service_spec.rb rename to spec/services/projects/file_service_spec.rb index 070c21698cf5..24f053750fb3 100644 --- a/spec/services/projects/image_service_spec.rb +++ b/spec/services/projects/file_service_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -describe Projects::ImageService do +describe Projects::FileService do before(:each) { enable_observers } after(:each) { disable_observers } - describe 'Image service' do + describe 'File service' do before do @user = create :user @project = create :project, creator_id: @user.id, namespace: @user.namespace @@ -13,12 +13,14 @@ context 'for valid gif file' do before do gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') - @link_to_image = upload_image(@project.repository, { 'markdown_img' => gif }, "http://test.example/") + @link_to_image = upload_image(@project.repository, { 'markdown_file' => gif }, "http://test.example/") end it { expect(@link_to_image).to have_key("alt") } it { expect(@link_to_image).to have_key("url") } + it { expect(@link_to_image).to have_key("is_image") } it { expect(@link_to_image).to have_value("banana_sample") } + it { expect(@link_to_image["is_image"]).to equal(true) } it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") } it { expect(@link_to_image["url"]).to match("banana_sample.gif") } end @@ -26,12 +28,14 @@ context 'for valid png file' do before do png = fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png') - @link_to_image = upload_image(@project.repository, { 'markdown_img' => png }, "http://test.example/") + @link_to_image = upload_image(@project.repository, { 'markdown_file' => png }, "http://test.example/") end it { expect(@link_to_image).to have_key("alt") } it { expect(@link_to_image).to have_key("url") } it { expect(@link_to_image).to have_value("dk") } + it { expect(@link_to_image).to have_key("is_image") } + it { expect(@link_to_image["is_image"]).to equal(true) } it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") } it { expect(@link_to_image["url"]).to match("dk.png") } end @@ -39,12 +43,14 @@ context 'for valid jpg file' do before do jpg = fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') - @link_to_image = upload_image(@project.repository, { 'markdown_img' => jpg }, "http://test.example/") + @link_to_image = upload_image(@project.repository, { 'markdown_file' => jpg }, "http://test.example/") end it { expect(@link_to_image).to have_key("alt") } it { expect(@link_to_image).to have_key("url") } + it { expect(@link_to_image).to have_key("is_image") } it { expect(@link_to_image).to have_value("rails_sample") } + it { expect(@link_to_image["is_image"]).to equal(true) } it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") } it { expect(@link_to_image["url"]).to match("rails_sample.jpg") } end @@ -52,14 +58,20 @@ context 'for txt file' do before do txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') - @link_to_image = upload_image(@project.repository, { 'markdown_img' => txt }, "http://test.example/") + @link_to_image = upload_image(@project.repository, { 'markdown_file' => txt }, "http://test.example/") end - it { expect(@link_to_image).to be_nil } + it { expect(@link_to_image).to have_key("alt") } + it { expect(@link_to_image).to have_key("url") } + it { expect(@link_to_image).to have_key("is_image") } + it { expect(@link_to_image).to have_value("doc_sample") } + it { expect(@link_to_image["is_image"]).to equal(false) } + it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") } + it { expect(@link_to_image["url"]).to match("doc_sample.txt") } end end def upload_image(repository, params, root_url) - Projects::ImageService.new(repository, params, root_url).execute + Projects::FileService.new(repository, params, root_url).execute end end