diff --git a/app/controllers/direct_uploads_controller.rb b/app/controllers/direct_uploads_controller.rb new file mode 100644 index 000000000..e6a8c139a --- /dev/null +++ b/app/controllers/direct_uploads_controller.rb @@ -0,0 +1,40 @@ +class DirectUploadsController < ApplicationController + + def destroy_upload + @document = Document.new(cached_attachment: params[:path]) + @document.set_attachment_from_cached_attachment + @document.cached_attachment = nil + @document.documentable = @documentable + + if @document.attachment.destroy + flash.now[:notice] = t "documents.actions.destroy.notice" + else + flash.now[:alert] = t "documents.actions.destroy.alert" + end + render :destroy + end + + def upload + @document = Document.new(document_params.merge(user: current_user)) + @document.documentable = @documentable + @document.valid? + + if @document.valid? + @document.attachment.save + @document.set_cached_attachment_from_attachment(URI(request.url)) + else + @document.attachment.destroy + end + end + + private + + def set_attachment_container_resource + @container_resource = params[:resource_type] + end + + def find_attachment_container_resource + @uplo = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id]) + end + +end \ No newline at end of file diff --git a/app/helpers/documentables_helper.rb b/app/helpers/documentables_helper.rb index 4db3cc450..409399665 100644 --- a/app/helpers/documentables_helper.rb +++ b/app/helpers/documentables_helper.rb @@ -12,8 +12,8 @@ module DocumentablesHelper bytes_to_mega(documentable.class.max_file_size) end - def accepted_content_types(documentable) - documentable.class.accepted_content_types + def accepted_content_types(documentable_class) + documentable_class.accepted_content_types end def accepted_content_types_extensions(documentable_class) @@ -22,15 +22,15 @@ module DocumentablesHelper .join(",") end - def documentable_humanized_accepted_content_types(documentable) - documentable.class.accepted_content_types + def documentable_humanized_accepted_content_types(documentable_class) + documentable_class.accepted_content_types .collect{ |content_type| content_type.split("/").last } .join(", ") end def documentables_note(documentable) t "documents.form.note", max_documents_allowed: max_documents_allowed(documentable), - accepted_content_types: documentable_humanized_accepted_content_types(documentable), + accepted_content_types: documentable_humanized_accepted_content_types(documentable.class), max_file_size: max_file_size(documentable) end diff --git a/app/models/direct_upload.rb b/app/models/direct_upload.rb new file mode 100644 index 000000000..b57618432 --- /dev/null +++ b/app/models/direct_upload.rb @@ -0,0 +1,28 @@ +class DirectUpload + include ActiveModel::Validations + + attr_accessor :resource, :resource_type, :resource_id, :resource_relation, + :attachment, :cached_attachment + + validates_presence_of :attachment, :resource_type, :resource_relation + validate :parent_resource_attachment_validations, + if: -> { attachment.present? && resource_type.present? && resource_relation.present? } + + def parent_resource_attachment_validations + # Proposal or Budget::Investment + resource = resource_type.constantize.find_or_initialize_by(id: resource_id) + + # Document or Image + relation = if resource.class.reflections[resource_relation].macro == :has_one + resource.send("build_#{resource_relation}", attachment: attachment) + else + resource.send(resource_relation).build(attachment: attachment) + end + relation.valid? + + if relation.errors.has_key? :attachment + errors[:attachment] = relation.errors[:attachment] + end + end + +end \ No newline at end of file diff --git a/app/models/document.rb b/app/models/document.rb index a08c6fe80..b66717943 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -50,9 +50,13 @@ class Document < ActiveRecord::Base private + def documentable_class + documentable_type.constantize if documentable_type.present? + end + def validate_attachment_size - if documentable.present? && - attachment_file_size > documentable.class.max_file_size + if documentable_class.present? && + attachment_file_size > documentable_class.max_file_size errors[:attachment] = I18n.t("documents.errors.messages.in_between", min: "0 Bytes", max: "#{max_file_size(documentable)} MB") @@ -60,11 +64,11 @@ class Document < ActiveRecord::Base end def validate_attachment_content_type - if documentable.present? && - !accepted_content_types(documentable).include?(attachment_content_type) + if documentable_class && + !accepted_content_types(documentable_class).include?(attachment_content_type) errors[:attachment] = I18n.t("documents.errors.messages.wrong_content_type", content_type: attachment_content_type, - accepted_content_types: documentable_humanized_accepted_content_types(documentable)) + accepted_content_types: documentable_humanized_accepted_content_types(documentable_class)) end end diff --git a/app/models/image.rb b/app/models/image.rb index 741b61eb3..c331a1886 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -66,6 +66,10 @@ class Image < ActiveRecord::Base attachment.reprocess! end + def imageable_class + imageable_type.constantize if imageable_type.present? + end + def validate_image_dimensions if attachment_of_valid_content_type? dimensions = Paperclip::Geometry.from_file(attachment.queued_for_write[:original].path) @@ -75,7 +79,7 @@ class Image < ActiveRecord::Base end def validate_attachment_size - if imageable.present? && + if imageable_class && attachment_file_size > 1.megabytes errors[:attachment] = I18n.t("images.errors.messages.in_between", min: "0 Bytes", @@ -84,7 +88,7 @@ class Image < ActiveRecord::Base end def validate_attachment_content_type - if imageable.present? && !attachment_of_valid_content_type? + if imageable_class && !attachment_of_valid_content_type? errors[:attachment] = I18n.t("images.errors.messages.wrong_content_type", content_type: attachment_content_type, accepted_content_types: imageable_humanized_accepted_content_types) diff --git a/app/views/documents/new.html.erb b/app/views/documents/new.html.erb index fa1b9a786..be300450e 100644 --- a/app/views/documents/new.html.erb +++ b/app/views/documents/new.html.erb @@ -1,4 +1,4 @@ -
+
<%= back_link_to params[:from] %> @@ -16,7 +16,7 @@
  • <%= t "documents.recommendation_two_html", - accepted_content_types: documentable_humanized_accepted_content_types(@document.documentable) %> + accepted_content_types: documentable_humanized_accepted_content_types(@document.documentable.class) %>
  • <%= t "documents.recommendation_three_html", diff --git a/spec/factories.rb b/spec/factories.rb index 3aa3a0e01..a53389fb9 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -819,4 +819,23 @@ LOREM_IPSUM association :author, factory: :user end + factory :direct_upload do + + trait :proposal do + resource_type "Proposal" + end + trait :budget_investment do + resource_type "Budget::Investment" + end + + trait :documents do + resource_relation "documents" + attachment { File.new("spec/fixtures/files/empty.pdf") } + end + trait :image do + resource_relation "image" + attachment { File.new("spec/fixtures/files/clippy.jpg") } + end + end + end diff --git a/spec/fixtures/files/clippy.jpeg b/spec/fixtures/files/clippy.jpeg new file mode 100644 index 000000000..1edb6659b Binary files /dev/null and b/spec/fixtures/files/clippy.jpeg differ diff --git a/spec/models/direct_upload_spec.rb b/spec/models/direct_upload_spec.rb new file mode 100644 index 000000000..b1bc9a3a9 --- /dev/null +++ b/spec/models/direct_upload_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +describe DirectUpload do + + it "should be valid for different kind of combinations when attachment is valid" do + expect(build(:direct_upload, :proposal, :documents)).to be_valid + expect(build(:direct_upload, :proposal, :image)).to be_valid + expect(build(:direct_upload, :budget_investment, :documents)).to be_valid + expect(build(:direct_upload, :budget_investment, :image)).to be_valid + end + + it "should not be valid for different kind of combinations when invalid atttachment content types" do + expect(build(:direct_upload, :proposal, :documents, attachment: File.new("spec/fixtures/files/clippy.png"))).not_to be_valid + expect(build(:direct_upload, :proposal, :image, attachment: File.new("spec/fixtures/files/empty.pdf"))).not_to be_valid + expect(build(:direct_upload, :budget_investment, :documents, attachment: File.new("spec/fixtures/files/clippy.png"))).not_to be_valid + expect(build(:direct_upload, :budget_investment, :image, attachment: File.new("spec/fixtures/files/empty.pdf"))).not_to be_valid + end + +end \ No newline at end of file diff --git a/spec/models/image_spec.rb b/spec/models/image_spec.rb new file mode 100644 index 000000000..cf19257cd --- /dev/null +++ b/spec/models/image_spec.rb @@ -0,0 +1,8 @@ +require 'rails_helper' + +describe Image do + + it_behaves_like "image validations", "budget_investment_image" + it_behaves_like "image validations", "proposal_image" + +end diff --git a/spec/shared/features/documentable.rb b/spec/shared/features/documentable.rb index 6e892a943..aef4e33c8 100644 --- a/spec/shared/features/documentable.rb +++ b/spec/shared/features/documentable.rb @@ -296,7 +296,7 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path, from: send(documentable_path, arguments)) expect(page).to have_content "You can upload up to a maximum of #{max_file_size(documentable)} documents." - expect(page).to have_content "You can upload #{documentable_humanized_accepted_content_types(documentable)} files." + expect(page).to have_content "You can upload #{documentable_humanized_accepted_content_types(documentable.class)} files." expect(page).to have_content "You can upload files up to #{max_file_size(documentable)} MB." end diff --git a/spec/shared/models/document_validations.rb b/spec/shared/models/document_validations.rb index 3226129a3..bbcb73832 100644 --- a/spec/shared/models/document_validations.rb +++ b/spec/shared/models/document_validations.rb @@ -5,7 +5,7 @@ shared_examples "document validations" do |documentable_factory| let!(:document) { build(:document, documentable_factory.to_sym) } let!(:documentable) { document.documentable } let!(:maxfilesize) { max_file_size(document.documentable) } - let!(:acceptedcontenttypes) { accepted_content_types(document.documentable) } + let!(:acceptedcontenttypes) { accepted_content_types(document.documentable.class) } it "should be valid" do expect(document).to be_valid diff --git a/spec/shared/models/image_validations.rb b/spec/shared/models/image_validations.rb new file mode 100644 index 000000000..b25886c68 --- /dev/null +++ b/spec/shared/models/image_validations.rb @@ -0,0 +1,70 @@ +shared_examples "image validations" do |imageable_factory| + include ImagesHelper + include ImageablesHelper + + let!(:image) { build(:image, imageable_factory.to_sym) } + let!(:imageable) { image.imageable } + let!(:acceptedcontenttypes) { imageable_accepted_content_types } + + it "should be valid" do + expect(image).to be_valid + end + + it "should not be valid without a title" do + image.title = nil + + expect(image).to_not be_valid + end + + it "should not be valid without an attachment" do + image.attachment = nil + + expect(image).to_not be_valid + end + + it "should be valid for all accepted content types" do + acceptedcontenttypes.each do |content_type| + extension = content_type.split("/").last + image.attachment = File.new("spec/fixtures/files/clippy.#{extension}") + + expect(image).to be_valid + end + end + + it "should not be valid for png and gif image content types" do + ["gif", "png"].each do |content_type| + extension = content_type.split("/").last + image.attachment = File.new("spec/fixtures/files/clippy.#{extension}") + + expect(image).not_to be_valid + end + end + + it "should not be valid for attachments larger than imageable max_file_size definition" do + image.stub(:attachment_file_size).and_return(Image::MAX_IMAGE_SIZE + 1.byte) + + expect(image).to_not be_valid + expect(image.errors[:attachment]).to include "must be in between 0 Bytes and 1 MB" + end + + it "should not be valid without a user_id" do + image.user_id = nil + + expect(image).to_not be_valid + end + + it "should not be valid without a imageable_id" do + image.save + image.imageable_id = nil + + expect(image).to_not be_valid + end + + it "should not be valid without a imageable_type" do + image.save + image.imageable_type = nil + + expect(image).to_not be_valid + end + +end \ No newline at end of file