diff --git a/app/helpers/documentables_helper.rb b/app/helpers/documentables_helper.rb index ef1a2d6b9..98ce55b59 100644 --- a/app/helpers/documentables_helper.rb +++ b/app/helpers/documentables_helper.rb @@ -17,15 +17,11 @@ module DocumentablesHelper end def accepted_content_types_extensions(documentable_class) - documentable_class.accepted_content_types - .collect{ |content_type| ".#{content_type.split("/").last}" } - .join(",") + Setting.accepted_content_types_for("documents").map { |content_type| ".#{content_type}" }.join(",") end def documentable_humanized_accepted_content_types(documentable_class) - documentable_class.accepted_content_types - .collect{ |content_type| content_type.split("/").last } - .join(", ") + Setting.accepted_content_types_for("documents").join(", ") end def documentables_note(documentable) diff --git a/app/helpers/imageables_helper.rb b/app/helpers/imageables_helper.rb index 1a85362d8..7c8d87298 100644 --- a/app/helpers/imageables_helper.rb +++ b/app/helpers/imageables_helper.rb @@ -9,7 +9,7 @@ module ImageablesHelper end def imageable_max_file_size - bytes_to_megabytes(Image::MAX_IMAGE_SIZE) + bytes_to_megabytes(Setting["uploads.images.max_size"].to_i.megabytes) end def bytes_to_megabytes(bytes) @@ -17,19 +17,21 @@ module ImageablesHelper end def imageable_accepted_content_types - Image::ACCEPTED_CONTENT_TYPE + Setting["uploads.images.content_types"]&.split(" ") || [ "image/jpeg" ] end def imageable_accepted_content_types_extensions - Image::ACCEPTED_CONTENT_TYPE - .collect{ |content_type| ".#{content_type.split("/").last}" } - .join(",") + Setting.accepted_content_types_for("images").map do |content_type| + if content_type == "jpg" + ".jpg,.jpeg" + else + ".#{content_type}" + end + end.join(",") end def imageable_humanized_accepted_content_types - Image::ACCEPTED_CONTENT_TYPE - .collect{ |content_type| content_type.split("/").last } - .join(", ") + Setting.accepted_content_types_for("images").join(", ") end def imageables_note(_imageable) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 2eaf801c1..55634cf4b 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -13,9 +13,6 @@ class Budget include Imageable include Mappable include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] acts_as_votable acts_as_paranoid column: :hidden_at diff --git a/app/models/concerns/documentable.rb b/app/models/concerns/documentable.rb index 36e91ece7..9f49d9af9 100644 --- a/app/models/concerns/documentable.rb +++ b/app/models/concerns/documentable.rb @@ -7,16 +7,17 @@ module Documentable end module ClassMethods - attr_reader :max_documents_allowed, :max_file_size, :accepted_content_types - - private - - def documentable(options = {}) - @max_documents_allowed = options[:max_documents_allowed] - @max_file_size = options[:max_file_size] - @accepted_content_types = options[:accepted_content_types] + def max_documents_allowed + Setting["uploads.documents.max_amount"].to_i end + def max_file_size + Setting["uploads.documents.max_size"].to_i.megabytes + end + + def accepted_content_types + Setting["uploads.documents.content_types"]&.split(" ") || [ "application/pdf" ] + end end end diff --git a/app/models/dashboard/action.rb b/app/models/dashboard/action.rb index afe61c075..4dea153a7 100644 --- a/app/models/dashboard/action.rb +++ b/app/models/dashboard/action.rb @@ -1,13 +1,5 @@ class Dashboard::Action < ApplicationRecord include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf", - "image/jpeg", - "image/jpg", - "image/png", - "application/zip" ] - include Linkable acts_as_paranoid column: :hidden_at diff --git a/app/models/image.rb b/app/models/image.rb index eefcd3926..6929f5f96 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -2,12 +2,11 @@ class Image < ApplicationRecord include ImagesHelper include ImageablesHelper - TITLE_LENGTH_RANGE = 4..80 - MIN_SIZE = 475 - MAX_IMAGE_SIZE = 1.megabyte - ACCEPTED_CONTENT_TYPE = %w(image/jpeg image/jpg).freeze - - has_attached_file :attachment, styles: { large: "x#{MIN_SIZE}", medium: "300x300#", thumb: "140x245#" }, + has_attached_file :attachment, styles: { + large: "x#{Setting["uploads.images.min_height"]}", + medium: "300x300#", + thumb: "140x245#" + }, url: "/system/:class/:prefix/:style/:hash.:extension", hash_data: ":class/:style", use_timestamp: false, @@ -23,7 +22,8 @@ class Image < ApplicationRecord validate :attachment_presence validate :validate_attachment_content_type, if: -> { attachment.present? } validate :validate_attachment_size, if: -> { attachment.present? } - validates :title, presence: true, length: { in: TITLE_LENGTH_RANGE } + validates :title, presence: true + validate :validate_title_length validates :user_id, presence: true validates :imageable_id, presence: true, if: -> { persisted? } validates :imageable_type, presence: true, if: -> { persisted? } @@ -71,20 +71,38 @@ class Image < ApplicationRecord return true if imageable_class == Widget::Card dimensions = Paperclip::Geometry.from_file(attachment.queued_for_write[:original].path) - errors.add(:attachment, :min_image_width, required_min_width: MIN_SIZE) if dimensions.width < MIN_SIZE - errors.add(:attachment, :min_image_height, required_min_height: MIN_SIZE) if dimensions.height < MIN_SIZE + min_width = Setting["uploads.images.min_width"].to_i + min_height = Setting["uploads.images.min_height"].to_i + errors.add(:attachment, :min_image_width, required_min_width: min_width) if dimensions.width < min_width + errors.add(:attachment, :min_image_height, required_min_height: min_height) if dimensions.height < min_height end end def validate_attachment_size if imageable_class && - attachment_file_size > 1.megabytes + attachment_file_size > Setting["uploads.images.max_size"].to_i.megabytes errors.add(:attachment, I18n.t("images.errors.messages.in_between", min: "0 Bytes", max: "#{imageable_max_file_size} MB")) end end + def validate_title_length + if title.present? + + title_min_length = Setting["uploads.images.title.min_length"].to_i + title_max_length = Setting["uploads.images.title.max_length"].to_i + + if title.size < title_min_length + errors.add(:title, I18n.t("errors.messages.too_short", count: title_min_length)) + end + + if title.size > title_max_length + errors.add(:title, I18n.t("errors.messages.too_long", count: title_max_length)) + end + end + end + def validate_attachment_content_type if imageable_class && !attachment_of_valid_content_type? message = I18n.t("images.errors.messages.wrong_content_type", diff --git a/app/models/legislation/process.rb b/app/models/legislation/process.rb index 3d2c72c27..3f91ea27a 100644 --- a/app/models/legislation/process.rb +++ b/app/models/legislation/process.rb @@ -4,9 +4,6 @@ class Legislation::Process < ApplicationRecord include Milestoneable include Imageable include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] acts_as_paranoid column: :hidden_at acts_as_taggable_on :customs diff --git a/app/models/legislation/proposal.rb b/app/models/legislation/proposal.rb index d6fdf5eb3..879eeb27d 100644 --- a/app/models/legislation/proposal.rb +++ b/app/models/legislation/proposal.rb @@ -14,9 +14,6 @@ class Legislation::Proposal < ApplicationRecord include Imageable include Randomizable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] accepts_nested_attributes_for :documents, allow_destroy: true acts_as_votable diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 69d46149a..52f8ccb29 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -1,9 +1,6 @@ class Milestone < ApplicationRecord include Imageable include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] translates :title, :description, touch: true include Globalizable diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index cde5e00d1..aab7acb59 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -6,9 +6,6 @@ class Poll::Question::Answer < ApplicationRecord translates :description, touch: true include Globalizable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] accepts_nested_attributes_for :documents, allow_destroy: true belongs_to :question, class_name: "Poll::Question", foreign_key: "question_id" diff --git a/app/models/proposal.rb b/app/models/proposal.rb index deb829058..3b4fbd0e2 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -15,9 +15,6 @@ class Proposal < ApplicationRecord include Mappable include Notifiable include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] include EmbedVideosHelper include Relationable include Milestoneable diff --git a/app/models/setting.rb b/app/models/setting.rb index 12162db4e..afc363502 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -52,6 +52,11 @@ class Setting < ApplicationRecord setting.destroy if setting.present? end + def accepted_content_types_for(group) + mime_content_types = Setting["uploads.#{group}.content_types"]&.split(" ") || [] + Setting.mime_types[group].select { |_, content_type| mime_content_types.include?(content_type) }.keys + end + def mime_types { "images" => { diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 240313c32..87670d676 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -115,6 +115,8 @@ ignore_missing: - "activerecord.errors.models.direct_message.*" - "errors.messages.blank" - "errors.messages.taken" + - "errors.messages.too_short" + - "errors.messages.too_long" - "devise.failure.invalid" - "devise.registrations.destroyed" - "devise.password_expired.*" diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index df764b7ca..fde1615cd 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -148,6 +148,24 @@ describe Setting do end end + describe ".accepted_content_types_for" do + it "returns the formats accepted according to the setting value" do + Setting["uploads.images.content_types"] = "image/jpeg image/gif" + Setting["uploads.documents.content_types"] = "application/pdf application/msword" + + expect(Setting.accepted_content_types_for("images")).to eq ["jpg", "gif"] + expect(Setting.accepted_content_types_for("documents")).to eq ["pdf", "doc"] + end + + it "returns empty array if setting does't exist" do + Setting.remove("uploads.images.content_types") + Setting.remove("uploads.documents.content_types") + + expect(Setting.accepted_content_types_for("images")).to be_empty + expect(Setting.accepted_content_types_for("documents")).to be_empty + end + end + describe ".add_new_settings" do context "default settings with strings" do before do diff --git a/spec/shared/models/image_validations.rb b/spec/shared/models/image_validations.rb index 691d73bae..c2b02a636 100644 --- a/spec/shared/models/image_validations.rb +++ b/spec/shared/models/image_validations.rb @@ -41,7 +41,8 @@ shared_examples "image validations" do |imageable_factory| end it "is not valid for attachments larger than imageable max_file_size definition" do - allow(image).to receive(:attachment_file_size).and_return(Image::MAX_IMAGE_SIZE + 1.byte) + larger_size = Setting["uploads.images.max_size"].to_i.megabytes + 1.byte + allow(image).to receive(:attachment_file_size).and_return(larger_size) expect(image).not_to be_valid expect(image.errors[:attachment]).to include "must be in between 0 Bytes and 1 MB" @@ -67,4 +68,4 @@ shared_examples "image validations" do |imageable_factory| expect(image).not_to be_valid end -end \ No newline at end of file +end