Add a limit so that users can't upload more if they already have more than 250 images queued for upload. For example, if you upload a Pixiv post that has 200 images, then you'll have 200 queued images for upload. This will go down as the images are processed. If you exceed the limit, then trying to create new uploads will return an error. This is to prevent single users from overwhelming the site by uploading too many images at once, thereby preventing other users from uploading because the job queue is backed up and can't process new uploads by other users until existing uploads are finished.
111 lines
2.6 KiB
Ruby
111 lines
2.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class UploadMediaAsset < ApplicationRecord
|
|
extend Memoist
|
|
|
|
attr_accessor :file
|
|
|
|
belongs_to :upload
|
|
belongs_to :media_asset, optional: true
|
|
has_one :post, through: :media_asset
|
|
|
|
after_create :async_process_upload!
|
|
after_save :update_upload_status, if: :saved_change_to_status?
|
|
|
|
# XXX there are ~150 old assets with blank source urls because the source went bad id before the image url could be saved.
|
|
validates :source_url, format: { with: %r{\A(https?|file)://}i, message: "is not a valid URL" }
|
|
validates :page_url, format: { with: %r{\A(https?)://}i, message: "is not a valid URL" }, allow_nil: true
|
|
|
|
enum status: {
|
|
pending: 0,
|
|
processing: 100,
|
|
active: 200,
|
|
failed: 300,
|
|
}
|
|
|
|
scope :unfinished, -> { where(status: %w[pending processing]) }
|
|
scope :finished, -> { where(status: %w[active failed]) }
|
|
|
|
def self.visible(user)
|
|
if user.is_admin?
|
|
all
|
|
else
|
|
where(upload: { uploader: user })
|
|
end
|
|
end
|
|
|
|
def self.search(params)
|
|
q = search_attributes(params, :id, :created_at, :updated_at, :status, :source_url, :page_url, :error, :upload, :media_asset, :post)
|
|
|
|
if params[:is_posted].to_s.truthy?
|
|
q = q.where.associated(:post)
|
|
elsif params[:is_posted].to_s.falsy?
|
|
q = q.where.missing(:post)
|
|
end
|
|
|
|
case params[:order]
|
|
when "id_desc"
|
|
q = q.order(id: :desc)
|
|
when "id_asc"
|
|
q = q.order(id: :asc)
|
|
else
|
|
q.apply_default_order(params)
|
|
end
|
|
end
|
|
|
|
def loading?
|
|
pending? || processing?
|
|
end
|
|
|
|
def finished?
|
|
active? || failed?
|
|
end
|
|
|
|
def file_upload?
|
|
source_url.starts_with?("file://")
|
|
end
|
|
|
|
def source_strategy
|
|
return nil if source_url.blank?
|
|
Sources::Strategies.find(source_url, page_url)
|
|
end
|
|
|
|
def async_process_upload!
|
|
if file.present?
|
|
process_upload!
|
|
else
|
|
ProcessUploadMediaAssetJob.perform_later(self)
|
|
end
|
|
end
|
|
|
|
def process_upload!
|
|
update!(status: :processing)
|
|
|
|
if file.present?
|
|
media_file = MediaFile.open(file)
|
|
else
|
|
media_file = source_strategy.download_file!(source_url)
|
|
end
|
|
|
|
MediaAsset.upload!(media_file) do |media_asset|
|
|
update!(media_asset: media_asset)
|
|
end
|
|
|
|
update!(status: :active)
|
|
rescue Exception => e
|
|
update!(status: :failed, error: e.message)
|
|
end
|
|
|
|
def update_upload_status
|
|
upload.with_lock do
|
|
if upload.upload_media_assets.all?(&:failed?)
|
|
upload.update!(status: "error", error: upload.upload_media_assets.map(&:error).join("; "))
|
|
elsif upload.upload_media_assets.all?(&:finished?)
|
|
upload.update!(status: "completed")
|
|
end
|
|
end
|
|
end
|
|
|
|
memoize :source_strategy
|
|
end
|