Features of AVIF include: * Lossless and lossy compression. * High dynamic range (HDR) images * Wide color gamut images (i.e. 10- and 12-bit color depths) * Transparency (through alpha planes). * Animations (with an optional cover image). * Auxiliary image sequences, where the file contains a single primary image and a short secondary video, like Apple's Live Photos. * Metadata rotation, mirroring, and cropping. The AVIF format is still relatively new and some of these features aren't well supported by browsers or other software: * Animated AVIFs aren't supported by Firefox or by libvips. * HDR images aren't supported by Firefox. * Rotated, mirrored, and cropped AVIFs aren't supported by Firefox or Chrome. * Image grids, where the file contains multiple images that are tiled together into one big image, aren't supported by Firefox. * AVIF as a whole has only been supported for a year or two by Chrome and Firefox, and less than a year by Safari. For these reasons, only basic AVIFs that don't use animation, rotation, cropping, or image grids can be uploaded.
42 lines
1.8 KiB
Ruby
42 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Define a custom validator for user names.
|
|
#
|
|
# @example
|
|
# validates :name, user_name: true
|
|
#
|
|
# @see https://guides.rubyonrails.org/active_record_validations.html#custom-validators
|
|
class UserNameValidator < ActiveModel::EachValidator
|
|
ALLOWED_PUNCTUATION = "_.-" # All other punctuation characters are forbidden
|
|
|
|
def validate_each(rec, attr, name)
|
|
forbidden_characters = name.delete(ALLOWED_PUNCTUATION).chars.grep(/[[:punct:]]/).uniq
|
|
|
|
if rec.new_record? && User.find_by_name(name).present?
|
|
rec.errors.add(attr, "already exists")
|
|
elsif name.length <= 1
|
|
rec.errors.add(attr, "must be more than 1 character long")
|
|
elsif name.length >= 25
|
|
rec.errors.add(attr, "must be less than 25 characters long")
|
|
elsif name =~ /[[:space:]]/
|
|
rec.errors.add(attr, "can't contain whitespace")
|
|
elsif name =~ /\A[[:punct:]]/
|
|
rec.errors.add(attr, "can't start with '#{name.first}'")
|
|
elsif name =~ /[[:punct:]]\z/
|
|
rec.errors.add(attr, "can't end with '#{name.last}'")
|
|
elsif name =~ /\.(html|json|xml|atom|rss|txt|js|css|csv|png|jpg|jpeg|gif|png|avif|webp|mp4|webm|zip|pdf|exe|sitemap)\z/i
|
|
rec.errors.add(attr, "can't end with a file extension")
|
|
elsif name =~ /__/
|
|
rec.errors.add(attr, "can't contain multiple underscores in a row")
|
|
elsif forbidden_characters.present?
|
|
rec.errors.add(attr, "can't contain #{forbidden_characters.map { |c| "'#{c}'" }.to_sentence}")
|
|
elsif name !~ /\A([a-zA-Z0-9]|\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}|[#{ALLOWED_PUNCTUATION}])+\z/
|
|
rec.errors.add(attr, "must contain only basic letters or numbers")
|
|
elsif name =~ /\Auser_\d+\z/i
|
|
rec.errors.add(attr, "can't be the same as a deleted user")
|
|
elsif name =~ Regexp.union(Danbooru.config.user_name_blacklist)
|
|
rec.errors.add(attr, "is not allowed")
|
|
end
|
|
end
|
|
end
|