Merge remote-tracking branch 'parent/main' into upstream-20240117
This commit is contained in:
commit
5d79bd078c
150 changed files with 2982 additions and 1485 deletions
|
@ -114,25 +114,27 @@ class Account < ApplicationRecord
|
|||
validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? }
|
||||
|
||||
# Remote user validations, also applies to internal actors
|
||||
validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type == 'Application') && will_save_change_to_username? }
|
||||
validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type_application?) && will_save_change_to_username? }
|
||||
|
||||
# Remote user validations
|
||||
validates :uri, presence: true, unless: :local?, on: :create
|
||||
|
||||
# Local user validations
|
||||
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
|
||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
|
||||
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && !actor_type_application? }
|
||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && !actor_type_application? }
|
||||
validates :display_name, length: { maximum: DISPLAY_NAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_display_name? }
|
||||
validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? }
|
||||
validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? }
|
||||
validates_with EmptyProfileFieldNamesValidator, if: -> { local? && will_save_change_to_fields? }
|
||||
with_options on: :create do
|
||||
validates :uri, absence: true, if: :local?
|
||||
validates :inbox_url, absence: true, if: :local?
|
||||
validates :shared_inbox_url, absence: true, if: :local?
|
||||
validates :followers_url, absence: true, if: :local?
|
||||
with_options on: :create, if: :local? do
|
||||
validates :followers_url, absence: true
|
||||
validates :inbox_url, absence: true
|
||||
validates :shared_inbox_url, absence: true
|
||||
validates :uri, absence: true
|
||||
end
|
||||
|
||||
validates :domain, exclusion: { in: [''] }
|
||||
|
||||
normalizes :username, with: ->(username) { username.squish }
|
||||
|
||||
scope :without_internal, -> { where(id: 1...) }
|
||||
|
@ -194,7 +196,7 @@ class Account < ApplicationRecord
|
|||
end
|
||||
|
||||
def remote?
|
||||
domain.present?
|
||||
!domain.nil?
|
||||
end
|
||||
|
||||
def moved?
|
||||
|
@ -215,6 +217,10 @@ class Account < ApplicationRecord
|
|||
self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'
|
||||
end
|
||||
|
||||
def actor_type_application?
|
||||
actor_type == 'Application'
|
||||
end
|
||||
|
||||
def group?
|
||||
actor_type == 'Group'
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@ class AccountWarning < ApplicationRecord
|
|||
suspend: 4_000,
|
||||
}, suffix: :action
|
||||
|
||||
APPEAL_WINDOW = 20.days
|
||||
RECENT_PERIOD = 3.months.freeze
|
||||
|
||||
normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
|
||||
|
@ -50,6 +51,10 @@ class AccountWarning < ApplicationRecord
|
|||
overruled_at.present?
|
||||
end
|
||||
|
||||
def appeal_eligible?
|
||||
created_at >= APPEAL_WINDOW.ago
|
||||
end
|
||||
|
||||
def to_log_human_identifier
|
||||
target_account.acct
|
||||
end
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
# updated_at :datetime not null
|
||||
#
|
||||
class Appeal < ApplicationRecord
|
||||
MAX_STRIKE_AGE = 20.days
|
||||
|
||||
TEXT_LENGTH_LIMIT = 2_000
|
||||
|
||||
belongs_to :account
|
||||
|
@ -68,6 +66,6 @@ class Appeal < ApplicationRecord
|
|||
private
|
||||
|
||||
def validate_time_frame
|
||||
errors.add(:base, I18n.t('strikes.errors.too_late')) if strike.created_at < MAX_STRIKE_AGE.ago
|
||||
errors.add(:base, I18n.t('strikes.errors.too_late')) unless strike.appeal_eligible?
|
||||
end
|
||||
end
|
||||
|
|
99
app/models/concerns/status/visibility.rb
Normal file
99
app/models/concerns/status/visibility.rb
Normal file
|
@ -0,0 +1,99 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Status::Visibility
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
enum :visibility,
|
||||
{ public: 0, unlisted: 1, private: 2, direct: 3, limited: 4, public_unlisted: 10, login: 11 },
|
||||
suffix: :visibility,
|
||||
validate: true
|
||||
enum :searchability,
|
||||
{ public: 0, private: 1, direct: 2, limited: 3, unsupported: 4, public_unlisted: 10 },
|
||||
suffix: :searchability
|
||||
enum :limited_scope,
|
||||
{ none: 0, mutual: 1, circle: 2, personal: 3, reply: 4 },
|
||||
suffix: :limited
|
||||
|
||||
scope :unset_searchability, -> { where(searchability: nil, reblog_of_id: nil) }
|
||||
scope :distributable_visibility, -> { where(visibility: %i(public unlisted)) }
|
||||
scope :distributable_visibility_for_anonymous, -> { where(visibility: %i(public public_unlisted unlisted)) }
|
||||
scope :list_eligible_visibility, -> { where(visibility: %i(public unlisted private)) }
|
||||
scope :not_direct_visibility, -> { where.not(visibility: :direct) }
|
||||
|
||||
validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?
|
||||
|
||||
before_validation :set_visibility, unless: :visibility?
|
||||
before_validation :set_searchability
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def selectable_visibilities
|
||||
selectable_all_visibilities - %w(mutual circle reply direct)
|
||||
end
|
||||
|
||||
def selectable_all_visibilities
|
||||
vs = %w(public public_unlisted login unlisted private mutual circle reply direct)
|
||||
vs -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility
|
||||
vs -= %w(public) unless Setting.enable_public_visibility
|
||||
vs
|
||||
end
|
||||
|
||||
def selectable_reblog_visibilities
|
||||
%w(unset) + selectable_visibilities
|
||||
end
|
||||
|
||||
def all_visibilities
|
||||
visibilities.keys
|
||||
end
|
||||
|
||||
def selectable_searchabilities
|
||||
ss = searchabilities.keys - %w(unsupported)
|
||||
ss -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility
|
||||
ss
|
||||
end
|
||||
|
||||
def selectable_searchabilities_for_search
|
||||
searchabilities.keys - %w(public_unlisted unsupported)
|
||||
end
|
||||
|
||||
def all_searchabilities
|
||||
searchabilities.keys - %w(unlisted login unsupported)
|
||||
end
|
||||
end
|
||||
|
||||
def hidden?
|
||||
!distributable?
|
||||
end
|
||||
|
||||
def distributable?
|
||||
public_visibility? || unlisted_visibility? || public_unlisted_visibility?
|
||||
end
|
||||
|
||||
alias sign? distributable?
|
||||
|
||||
private
|
||||
|
||||
def set_visibility
|
||||
self.visibility ||= reblog.visibility if reblog?
|
||||
self.visibility ||= visibility_from_account
|
||||
end
|
||||
|
||||
def visibility_from_account
|
||||
account.locked? ? :private : :public
|
||||
end
|
||||
|
||||
def set_searchability
|
||||
return if searchability.nil?
|
||||
|
||||
self.searchability = if %w(public public_unlisted login unlisted).include?(visibility)
|
||||
searchability
|
||||
elsif ['limited', 'direct'].include?(visibility)
|
||||
searchability == 'limited' ? :limited : :direct
|
||||
elsif visibility == 'private'
|
||||
['public', 'public_unlisted'].include?(searchability) ? :private : searchability
|
||||
else
|
||||
:direct
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ class DomainBlock < ApplicationRecord
|
|||
include DomainNormalizable
|
||||
include DomainMaterializable
|
||||
|
||||
enum :severity, { silence: 0, suspend: 1, noop: 2 }
|
||||
enum :severity, { silence: 0, suspend: 1, noop: 2 }, validate: true
|
||||
|
||||
validates :domain, presence: true, uniqueness: true, domain: true
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class Invite < ApplicationRecord
|
|||
|
||||
validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }
|
||||
|
||||
before_validation :set_code
|
||||
before_validation :set_code, on: :create
|
||||
|
||||
def valid_for_use?
|
||||
(max_uses.nil? || uses < max_uses) && !expired? && user&.functional?
|
||||
|
|
|
@ -24,7 +24,7 @@ class IpBlock < ApplicationRecord
|
|||
sign_up_requires_approval: 5000,
|
||||
sign_up_block: 5500,
|
||||
no_access: 9999,
|
||||
}, prefix: true
|
||||
}, prefix: true, validate: true
|
||||
|
||||
validates :ip, :severity, presence: true
|
||||
validates :ip, uniqueness: true
|
||||
|
|
|
@ -89,22 +89,32 @@ class NotificationGroup < ActiveModelSerializers::Model
|
|||
binds = [
|
||||
account_id,
|
||||
SAMPLE_ACCOUNTS_SIZE,
|
||||
pagination_range.begin,
|
||||
pagination_range.end,
|
||||
ActiveRecord::Relation::QueryAttribute.new('group_keys', group_keys, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(ActiveModel::Type::String.new)),
|
||||
pagination_range.begin || 0,
|
||||
]
|
||||
binds << pagination_range.end unless pagination_range.end.nil?
|
||||
|
||||
upper_bound_cond = begin
|
||||
if pagination_range.end.nil?
|
||||
''
|
||||
elsif pagination_range.exclude_end?
|
||||
'AND id < $5'
|
||||
else
|
||||
'AND id <= $5'
|
||||
end
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connection.select_all(<<~SQL.squish, 'grouped_notifications', binds).cast_values.to_h { |k, *values| [k, values] }
|
||||
SELECT
|
||||
groups.group_key,
|
||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1),
|
||||
array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT $2),
|
||||
(SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4) AS notifications_count,
|
||||
array(SELECT activity_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 AND activity_type = 'EmojiReaction'),
|
||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $3 ORDER BY id ASC LIMIT 1) AS min_id,
|
||||
(SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1)
|
||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1),
|
||||
array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT $2),
|
||||
(SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond}) AS notifications_count,
|
||||
array(SELECT activity_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} AND activity_type = 'EmojiReaction'),
|
||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $4 ORDER BY id ASC LIMIT 1) AS min_id,
|
||||
(SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1)
|
||||
FROM
|
||||
unnest($5::text[]) AS groups(group_key);
|
||||
unnest($3::text[]) AS groups(group_key);
|
||||
SQL
|
||||
else
|
||||
binds = [
|
||||
|
|
|
@ -45,6 +45,7 @@ class Status < ApplicationRecord
|
|||
include Status::SearchConcern
|
||||
include Status::SnapshotConcern
|
||||
include Status::ThreadingConcern
|
||||
include Status::Visibility
|
||||
include DtlHelper
|
||||
|
||||
MEDIA_ATTACHMENTS_LIMIT = 4
|
||||
|
@ -62,10 +63,6 @@ class Status < ApplicationRecord
|
|||
update_index('statuses', :proper)
|
||||
update_index('public_statuses', :proper)
|
||||
|
||||
enum :visibility, { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4, public_unlisted: 10, login: 11 }, suffix: :visibility, validate: true
|
||||
enum :searchability, { public: 0, private: 1, direct: 2, limited: 3, unsupported: 4, public_unlisted: 10 }, suffix: :searchability
|
||||
enum :limited_scope, { none: 0, mutual: 1, circle: 2, personal: 3, reply: 4 }, suffix: :limited
|
||||
|
||||
belongs_to :application, class_name: 'Doorkeeper::Application', optional: true
|
||||
|
||||
belongs_to :account, inverse_of: :statuses
|
||||
|
@ -130,7 +127,6 @@ class Status < ApplicationRecord
|
|||
validates_with StatusLengthValidator
|
||||
validates_with DisallowedHashtagsValidator
|
||||
validates :reblog, uniqueness: { scope: :account }, if: :reblog?
|
||||
validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?
|
||||
|
||||
accepts_nested_attributes_for :poll
|
||||
|
||||
|
@ -159,11 +155,6 @@ class Status < ApplicationRecord
|
|||
scope :tagged_with_none, lambda { |tag_ids|
|
||||
where('NOT EXISTS (SELECT * FROM statuses_tags forbidden WHERE forbidden.status_id = statuses.id AND forbidden.tag_id IN (?))', tag_ids)
|
||||
}
|
||||
scope :unset_searchability, -> { where(searchability: nil, reblog_of_id: nil) }
|
||||
scope :distributable_visibility, -> { where(visibility: %i(public public_unlisted login unlisted)) }
|
||||
scope :distributable_visibility_for_anonymous, -> { where(visibility: %i(public public_unlisted unlisted)) }
|
||||
scope :list_eligible_visibility, -> { where(visibility: %i(public public_unlisted login unlisted private)) }
|
||||
scope :not_direct_visibility, -> { where.not(visibility: :direct) }
|
||||
|
||||
after_create_commit :trigger_create_webhooks
|
||||
after_update_commit :trigger_update_webhooks
|
||||
|
@ -176,8 +167,6 @@ class Status < ApplicationRecord
|
|||
|
||||
before_validation :prepare_contents, if: :local?
|
||||
before_validation :set_reblog
|
||||
before_validation :set_visibility
|
||||
before_validation :set_searchability
|
||||
before_validation :set_conversation
|
||||
before_validation :set_local
|
||||
|
||||
|
@ -305,16 +294,6 @@ class Status < ApplicationRecord
|
|||
PreviewCardsStatus.where(status_id: id).delete_all
|
||||
end
|
||||
|
||||
def hidden?
|
||||
!distributable?
|
||||
end
|
||||
|
||||
def distributable?
|
||||
public_visibility? || unlisted_visibility? || public_unlisted_visibility?
|
||||
end
|
||||
|
||||
alias sign? distributable?
|
||||
|
||||
def with_media?
|
||||
media_attachments.any?
|
||||
end
|
||||
|
@ -521,39 +500,6 @@ class Status < ApplicationRecord
|
|||
end
|
||||
|
||||
class << self
|
||||
def selectable_visibilities
|
||||
selectable_all_visibilities - %w(mutual circle reply direct)
|
||||
end
|
||||
|
||||
def selectable_all_visibilities
|
||||
vs = %w(public public_unlisted login unlisted private mutual circle reply direct)
|
||||
vs -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility
|
||||
vs -= %w(public) unless Setting.enable_public_visibility
|
||||
vs
|
||||
end
|
||||
|
||||
def selectable_reblog_visibilities
|
||||
%w(unset) + selectable_visibilities
|
||||
end
|
||||
|
||||
def all_visibilities
|
||||
visibilities.keys
|
||||
end
|
||||
|
||||
def selectable_searchabilities
|
||||
ss = searchabilities.keys - %w(unsupported)
|
||||
ss -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility
|
||||
ss
|
||||
end
|
||||
|
||||
def selectable_searchabilities_for_search
|
||||
searchabilities.keys - %w(public_unlisted unsupported)
|
||||
end
|
||||
|
||||
def all_searchabilities
|
||||
searchabilities.keys - %w(unlisted login unsupported)
|
||||
end
|
||||
|
||||
def favourites_map(status_ids, account_id)
|
||||
Favourite.select(:status_id).where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true }
|
||||
end
|
||||
|
@ -660,25 +606,6 @@ class Status < ApplicationRecord
|
|||
update_column(:poll_id, poll.id) if association(:poll).loaded? && poll.present?
|
||||
end
|
||||
|
||||
def set_visibility
|
||||
self.visibility = reblog.visibility if reblog? && visibility.nil?
|
||||
self.visibility = (account.locked? ? :private : :public) if visibility.nil?
|
||||
end
|
||||
|
||||
def set_searchability
|
||||
return if searchability.nil?
|
||||
|
||||
self.searchability = if %w(public public_unlisted login unlisted).include?(visibility)
|
||||
searchability
|
||||
elsif visibility == 'limited' || visibility == 'direct'
|
||||
searchability == 'limited' ? :limited : :direct
|
||||
elsif visibility == 'private'
|
||||
searchability == 'public' || searchability == 'public_unlisted' ? :private : searchability
|
||||
else
|
||||
:direct
|
||||
end
|
||||
end
|
||||
|
||||
def set_conversation
|
||||
self.thread = thread.reblog if thread&.reblog?
|
||||
|
||||
|
|
|
@ -36,11 +36,11 @@ class Tag < ApplicationRecord
|
|||
has_one :trend, class_name: 'TagTrend', inverse_of: :tag, dependent: :destroy
|
||||
|
||||
HASHTAG_SEPARATORS = "_\u00B7\u30FB\u200c"
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_ONE = "[[:word:]_][[:word:]#{HASHTAG_SEPARATORS}]*[[:alpha:]#{HASHTAG_SEPARATORS}]"
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_TWO = "[[:word:]#{HASHTAG_SEPARATORS}]*[[:word:]_]"
|
||||
HASHTAG_FIRST_SEQUENCE = "(#{HASHTAG_FIRST_SEQUENCE_CHUNK_ONE}#{HASHTAG_FIRST_SEQUENCE_CHUNK_TWO})"
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_ONE = "[[:word:]_][[:word:]#{HASHTAG_SEPARATORS}]*[[:alpha:]#{HASHTAG_SEPARATORS}]".freeze
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_TWO = "[[:word:]#{HASHTAG_SEPARATORS}]*[[:word:]_]".freeze
|
||||
HASHTAG_FIRST_SEQUENCE = "(#{HASHTAG_FIRST_SEQUENCE_CHUNK_ONE}#{HASHTAG_FIRST_SEQUENCE_CHUNK_TWO})".freeze
|
||||
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
|
||||
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"
|
||||
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}".freeze
|
||||
|
||||
HASHTAG_RE = %r{(?<![=/)\p{Alnum}])#(#{HASHTAG_NAME_PAT})}
|
||||
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
||||
|
|
|
@ -16,7 +16,7 @@ class Trends::Links < Trends::Base
|
|||
class Query < Trends::Query
|
||||
def to_arel
|
||||
scope = PreviewCard.joins(:trend).reorder(score: :desc)
|
||||
scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present?
|
||||
scope = scope.reorder(language_order_clause, score: :desc) if preferred_languages.present?
|
||||
scope = scope.merge(PreviewCardTrend.allowed) if @allowed
|
||||
scope = scope.offset(@offset) if @offset.present?
|
||||
scope = scope.limit(@limit) if @limit.present?
|
||||
|
@ -25,8 +25,8 @@ class Trends::Links < Trends::Base
|
|||
|
||||
private
|
||||
|
||||
def language_order_clause
|
||||
Arel::Nodes::Case.new.when(PreviewCardTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
||||
def trend_class
|
||||
PreviewCardTrend
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -94,6 +94,16 @@ class Trends::Query
|
|||
to_arel.to_a
|
||||
end
|
||||
|
||||
def language_order_clause
|
||||
Arel::Nodes::Case.new.when(language_is_preferred).then(1).else(0).desc
|
||||
end
|
||||
|
||||
def language_is_preferred
|
||||
trend_class
|
||||
.arel_table[:language]
|
||||
.in(preferred_languages)
|
||||
end
|
||||
|
||||
def preferred_languages
|
||||
if @account&.chosen_languages.present?
|
||||
@account.chosen_languages
|
||||
|
|
|
@ -15,7 +15,7 @@ class Trends::Statuses < Trends::Base
|
|||
class Query < Trends::Query
|
||||
def to_arel
|
||||
scope = Status.joins(:trend).reorder(score: :desc)
|
||||
scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present?
|
||||
scope = scope.reorder(language_order_clause, score: :desc) if preferred_languages.present?
|
||||
scope = scope.merge(StatusTrend.allowed) if @allowed
|
||||
scope = scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) if @account.present?
|
||||
scope = scope.offset(@offset) if @offset.present?
|
||||
|
@ -25,8 +25,8 @@ class Trends::Statuses < Trends::Base
|
|||
|
||||
private
|
||||
|
||||
def language_order_clause
|
||||
Arel::Nodes::Case.new.when(StatusTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
||||
def trend_class
|
||||
StatusTrend
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ class Trends::Tags < Trends::Base
|
|||
|
||||
class Query < Trends::Query
|
||||
def to_arel
|
||||
scope = Tag.joins(:trend).reorder(language_order_clause.desc, score: :desc)
|
||||
scope = Tag.joins(:trend).reorder(score: :desc)
|
||||
scope = scope.reorder(language_order_clause, score: :desc) if preferred_languages.present?
|
||||
scope = scope.merge(TagTrend.allowed) if @allowed
|
||||
scope = scope.offset(@offset) if @offset.present?
|
||||
scope = scope.limit(@limit) if @limit.present?
|
||||
|
@ -24,8 +25,8 @@ class Trends::Tags < Trends::Base
|
|||
|
||||
private
|
||||
|
||||
def language_order_clause
|
||||
Arel::Nodes::Case.new.when(TagTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
||||
def trend_class
|
||||
TagTrend
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ class UserRole < ApplicationRecord
|
|||
NOBODY_POSITION = -1
|
||||
|
||||
POSITION_LIMIT = (2**31) - 1
|
||||
CSS_COLORS = /\A#?(?:[A-F0-9]{3}){1,2}\z/i # CSS-style hex colors
|
||||
|
||||
module Flags
|
||||
NONE = 0
|
||||
|
@ -95,7 +96,7 @@ class UserRole < ApplicationRecord
|
|||
attr_writer :current_account
|
||||
|
||||
validates :name, presence: true, unless: :everyone?
|
||||
validates :color, format: { with: /\A#?(?:[A-F0-9]{3}){1,2}\z/i }, unless: -> { color.blank? }
|
||||
validates :color, format: { with: CSS_COLORS }, if: :color?
|
||||
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
|
||||
|
||||
validate :validate_permissions_elevation
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
# Table name: web_push_subscriptions
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# endpoint :string not null
|
||||
# key_p256dh :string not null
|
||||
# key_auth :string not null
|
||||
# data :json
|
||||
# endpoint :string not null
|
||||
# key_auth :string not null
|
||||
# key_p256dh :string not null
|
||||
# standard :boolean default(FALSE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# access_token_id :bigint(8)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue