From 03560bafc67a62be639812ef3aa32e89cfee6878 Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 28 Feb 2022 22:19:40 -0600 Subject: [PATCH] uploads: add limit to prevent users from submitting too many uploads at once. 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. --- app/models/upload.rb | 12 ++++++++++++ app/models/upload_media_asset.rb | 3 +++ app/models/user.rb | 4 +++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/models/upload.rb b/app/models/upload.rb index 511177edc..1a5ac9a8e 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -6,6 +6,9 @@ class Upload < ApplicationRecord MAX_FILES_PER_UPLOAD = 100 + # The maximum number of 'pending' or 'processing' media assets a single user can have at once. + MAX_QUEUED_ASSETS = 250 + attr_accessor :files belongs_to :uploader, class_name: "User" @@ -19,6 +22,7 @@ class Upload < ApplicationRecord 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 + validate :uploader_is_not_limited, on: :create after_create :async_process_upload! @@ -64,6 +68,14 @@ class Upload < ApplicationRecord errors.add(:base, "No file or source given") end end + + def uploader_is_not_limited + queued_asset_count = uploader.upload_media_assets.unfinished.count + + if queued_asset_count > MAX_QUEUED_ASSETS + errors.add(:base, "You have too many images queued for upload (queued: #{queued_asset_count}; limit: #{MAX_QUEUED_ASSETS}). Try again later.") + end + end end concerning :SourceMethods do diff --git a/app/models/upload_media_asset.rb b/app/models/upload_media_asset.rb index 43d1b6334..ac8514a8c 100644 --- a/app/models/upload_media_asset.rb +++ b/app/models/upload_media_asset.rb @@ -23,6 +23,9 @@ class UploadMediaAsset < ApplicationRecord 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 diff --git a/app/models/user.rb b/app/models/user.rb index e3c9442d4..714904faa 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -109,6 +109,7 @@ class User < ApplicationRecord validate :validate_custom_css, if: :custom_style_changed? before_validation :normalize_blacklisted_tags before_create :promote_to_owner_if_first_user + has_many :artist_versions, foreign_key: :updater_id has_many :artist_commentary_versions, foreign_key: :updater_id has_many :comments, foreign_key: :creator_id @@ -131,7 +132,6 @@ class User < ApplicationRecord has_many :purchased_upgrades, class_name: "UserUpgrade", foreign_key: :purchaser_id, dependent: :destroy has_many :user_events, dependent: :destroy has_one :active_ban, -> { active }, class_name: "Ban" - has_one :email_address, dependent: :destroy has_many :api_keys, dependent: :destroy has_many :note_versions, :foreign_key => "updater_id" @@ -145,6 +145,8 @@ class User < ApplicationRecord has_many :ip_bans, foreign_key: :creator_id has_many :tag_aliases, foreign_key: :creator_id has_many :tag_implications, foreign_key: :creator_id + has_many :uploads, foreign_key: :uploader_id, dependent: :destroy + has_many :upload_media_assets, through: :uploads, dependent: :destroy belongs_to :inviter, class_name: "User", optional: true accepts_nested_attributes_for :email_address, reject_if: :all_blank, allow_destroy: true