uploads: fix broken tests.

* Fix broken upload tests.
* Fix uploads to return an error if both a file and a source are given
  at the same time, or if neither are given. Also fix the error message
  in this case so that it doesn't include "base" at the start of the string.
* Fix uploads to percent-encode any Unicode characters in the source URL.
* Add a max filesize validation to media assets.
This commit is contained in:
evazion
2022-01-29 04:38:47 -06:00
parent 5d0c14d2bd
commit 11b7bcac91
9 changed files with 248 additions and 611 deletions

View File

@@ -110,7 +110,13 @@ export default class FileUploadComponent {
async onError(e) {
let errors = e.originalEvent.detail[0].errors;
let message = Object.keys(errors).map(attribute => {
return errors[attribute].map(error => `${capitalize(attribute)} ${error}`);
return errors[attribute].map(error => {
if (attribute === "base") {
return `${error}`;
} else {
return `${capitalize(attribute)} ${error}`;
}
});
}).join("; ");
Utility.error(message);

View File

@@ -35,6 +35,7 @@ class MediaAsset < ApplicationRecord
validates :md5, uniqueness: { conditions: -> { where(status: [:processing, :active]) } }
validates :file_ext, inclusion: { in: %w[jpg png gif mp4 webm swf zip], message: "Not an image or video" }
validates :file_size, numericality: { less_than_or_equal_to: Danbooru.config.max_file_size }
validates :duration, numericality: { less_than_or_equal_to: MAX_VIDEO_DURATION, message: "must be less than #{MAX_VIDEO_DURATION} seconds", allow_nil: true }, on: :create # XXX should allow admins to bypass
validate :validate_resolution, on: :create
@@ -228,7 +229,7 @@ class MediaAsset < ApplicationRecord
# failed state, then mark the asset as failed so the user can try the upload again later.
if !media_asset.active?
media_asset.update!(status: :failed)
raise Error, "Upload failed, try again (upload was stuck in 'processing' state)"
raise Error, "Upload failed, try again (timed out while waiting for file to be processed)"
end
media_asset

View File

@@ -11,8 +11,11 @@ class Upload < ApplicationRecord
has_many :upload_media_assets, dependent: :destroy
has_many :media_assets, through: :upload_media_assets
normalize :source, :normalize_source
validates :source, format: { with: %r{\Ahttps?://}i, message: "is not a valid URL" }, if: -> { source.present? }
validates :referer_url, format: { with: %r{\Ahttps?://}i, message: "is not a valid URL" }, if: -> { referer_url.present? }
validate :validate_file_and_source, on: :create
after_create :async_process_upload!
@@ -46,6 +49,31 @@ class Upload < ApplicationRecord
end
end
concerning :ValidationMethods do
def validate_file_and_source
if file.present? && source.present?
errors.add(:base, "Can't give both a file and a source")
elsif file.blank? && source.blank?
errors.add(:base, "No file or source given")
end
end
end
concerning :SourceMethods do
class_methods do
# percent-encode unicode characters in the URL
def normalize_source(url)
return nil if url.nil?
Addressable::URI.normalized_encode(url)
end
end
def source_strategy
return nil if source.blank?
Sources::Strategies.find(source, referer_url)
end
end
def self.search(params)
q = search_attributes(params, :id, :created_at, :updated_at, :source, :referer_url, :uploader, :status, :backtrace, :upload_media_assets, :media_assets)
q.apply_default_order(params)
@@ -54,8 +82,10 @@ class Upload < ApplicationRecord
def async_process_upload!
if file.present?
ProcessUploadJob.perform_now(self)
else
elsif source.present?
ProcessUploadJob.perform_later(self)
else
raise "No file or source given" # Should never happen
end
end
@@ -68,19 +98,13 @@ class Upload < ApplicationRecord
strategy = Sources::Strategies.find(source, referer_url)
media_file = strategy.download_file!(strategy.image_url)
else
raise "No file or source provided"
raise "No file or source given" # Should never happen
end
media_asset = MediaAsset.upload!(media_file)
update!(media_assets: [media_asset], status: "completed")
rescue Exception => e
update!(status: "error: #{e.message}", backtrace: e.backtrace.join("\n"))
raise
end
def source_strategy
return nil if source.blank?
Sources::Strategies.find(source, referer_url)
end
def self.available_includes