0
0
Fork 0

Merge remote-tracking branch 'upstream/main'

This commit is contained in:
ASTRO:? 2025-03-14 20:25:34 +09:00
commit d564483d30
No known key found for this signature in database
GPG key ID: 2938B9B314D8EF8B
1796 changed files with 48111 additions and 29322 deletions

View file

@ -4,23 +4,26 @@ class DomainValidator < ActiveModel::EachValidator
MAX_DOMAIN_LENGTH = 256
MIN_LABEL_LENGTH = 1
MAX_LABEL_LENGTH = 63
ALLOWED_CHARACTERS_RE = /^[a-z0-9\-]+$/i
ALLOWED_CHARACTERS_RE = /^[a-z0-9-]+$/i
def validate_each(record, attribute, value)
return if value.blank?
(options[:multiline] ? value.split : [value]).each do |domain|
_, domain = domain.split('@') if options[:acct]
Array.wrap(value).each do |domain|
if options[:acct]
_, domain = domain.split('@')
next if domain.blank?
end
next if domain.blank?
record.errors.add(attribute, options[:multiline] ? :invalid_domain_on_line : :invalid, value: domain) unless compliant?(domain)
record.errors.add(attribute, value.is_a?(Enumerable) ? :invalid_domain_on_line : :invalid, value: domain) unless compliant?(domain)
end
end
private
def compliant?(value)
return false if value.blank?
uri = Addressable::URI.new
uri.host = value
uri.normalized_host.size < MAX_DOMAIN_LENGTH && uri.normalized_host.split('.').all? { |label| label.size.between?(MIN_LABEL_LENGTH, MAX_LABEL_LENGTH) && label =~ ALLOWED_CHARACTERS_RE }

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class EmptyProfileFieldNamesValidator < ActiveModel::Validator
def validate(account)
return if account.fields.empty?
account.errors.add(:fields, :fields_with_values_missing_labels) if fields_with_values_missing_names?(account)
end
private
def fields_with_values_missing_names?(account)
account.fields.any? { |field| field.name.blank? && field.value.present? }
end
end

View file

@ -1,9 +0,0 @@
# frozen_string_literal: true
class LinesValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank?
record.errors.add(attribute, :too_many_lines, limit: options[:maximum]) if options[:maximum].present? && value.split.size > options[:maximum]
end
end

View file

@ -8,7 +8,7 @@ class NoteLengthValidator < ActiveModel::EachValidator
private
def too_long?(value)
countable_text(value).mb_chars.grapheme_length > options[:maximum]
countable_text(value).each_grapheme_cluster.size > options[:maximum]
end
def countable_text(value)

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
class PollExpirationValidator < ActiveModel::Validator
MAX_EXPIRATION = 1.month.freeze
MIN_EXPIRATION = 5.minutes.freeze
def validate(poll)
# We have a `presence: true` check for this attribute already
return if poll.expires_at.nil?
current_time = Time.now.utc
poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_long')) if poll.expires_at - current_time > MAX_EXPIRATION
poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_short')) if (poll.expires_at - current_time).ceil < MIN_EXPIRATION
end
end

View file

@ -1,19 +1,13 @@
# frozen_string_literal: true
class PollValidator < ActiveModel::Validator
class PollOptionsValidator < ActiveModel::Validator
MAX_OPTIONS = 4
MAX_OPTION_CHARS = 50
MAX_EXPIRATION = 1.month.freeze
MIN_EXPIRATION = 5.minutes.freeze
def validate(poll)
current_time = Time.now.utc
poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1
poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS
poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }
poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.each_grapheme_cluster.size > MAX_OPTION_CHARS }
poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size
poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_long')) if poll.expires_at.nil? || poll.expires_at - current_time > MAX_EXPIRATION
poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_short')) if poll.expires_at.present? && (poll.expires_at - current_time).ceil < MIN_EXPIRATION
end
end

View file

@ -18,7 +18,7 @@ class StatusLengthValidator < ActiveModel::Validator
end
def countable_length(str)
str.mb_chars.grapheme_length
str.each_grapheme_cluster.size
end
def combined_text(status)