Merge remote-tracking branch 'parent/main' into upstream-20231204

This commit is contained in:
KMY 2023-12-04 12:04:52 +09:00
commit 94c2396a34
179 changed files with 1036 additions and 775 deletions

View file

@ -74,21 +74,22 @@ class Account < ApplicationRecord
URL_PREFIX_RE = %r{\Ahttp(s?)://[^/]+}
USERNAME_ONLY_RE = /\A#{USERNAME_RE}\z/i
include Attachmentable
include AccountAssociations
include AccountAvatar
include AccountFinderConcern
include AccountHeader
include AccountInteractions
include Paginable
include AccountCounters
include DomainNormalizable
include Attachmentable # Load prior to Avatar & Header concerns
include Account::Associations
include Account::Avatar
include Account::Counters
include Account::FinderConcern
include Account::Header
include Account::Interactions
include Account::Merging
include Account::Search
include Account::StatusesSearch
include Account::OtherSettings
include Account::MasterSettings
include DomainMaterializable
include AccountMerging
include AccountSearch
include AccountStatusesSearch
include AccountOtherSettings
include AccountMasterSettings
include DomainNormalizable
include Paginable
enum protocol: { ostatus: 0, activitypub: 1 }
enum suspension_origin: { local: 0, remote: 1 }, _prefix: true
@ -273,6 +274,9 @@ class Account < ApplicationRecord
suspended? && deletion_request.present?
end
alias unavailable? suspended?
alias permanently_unavailable? suspended_permanently?
def suspend!(date: Time.now.utc, origin: :local, block_email: true)
transaction do
create_deletion_request!

View file

@ -24,12 +24,12 @@ class Admin::ActionLog < ApplicationRecord
belongs_to :account
belongs_to :target, polymorphic: true, optional: true
default_scope -> { order('id desc') }
before_validation :set_human_identifier
before_validation :set_route_param
before_validation :set_permalink
scope :latest, -> { order(id: :desc) }
def action
super.to_sym
end

View file

@ -72,7 +72,7 @@ class Admin::ActionLogFilter
end
def results
scope = Admin::ActionLog.includes(:target)
scope = latest_action_logs.includes(:target)
params.each do |key, value|
next if key.to_s == 'page'
@ -88,14 +88,18 @@ class Admin::ActionLogFilter
def scope_for(key, value)
case key
when 'action_type'
Admin::ActionLog.where(ACTION_TYPE_MAP[value.to_sym])
latest_action_logs.where(ACTION_TYPE_MAP[value.to_sym])
when 'account_id'
Admin::ActionLog.where(account_id: value)
latest_action_logs.where(account_id: value)
when 'target_account_id'
account = Account.find_or_initialize_by(id: value)
Admin::ActionLog.where(target: [account, account.user].compact)
latest_action_logs.where(target: [account, account.user].compact)
else
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
end
end
def latest_action_logs
Admin::ActionLog.latest
end
end

View file

@ -32,7 +32,7 @@ class Admin::StatusFilter
def scope_for(key, _value)
case key.to_s
when 'media'
Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id).reorder('statuses.id desc')
Status.joins(:media_attachments).merge(@account.media_attachments).group(:id).reorder('statuses.id desc')
else
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountAssociations
module Account::Associations
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountAvatar
module Account::Avatar
extend ActiveSupport::Concern
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze

View file

@ -1,12 +1,12 @@
# frozen_string_literal: true
module AccountCounters
module Account::Counters
extend ActiveSupport::Concern
ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze
included do
has_one :account_stat, inverse_of: :account
has_one :account_stat, inverse_of: :account, dependent: nil
after_save :save_account_stat
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountFinderConcern
module Account::FinderConcern
extend ActiveSupport::Concern
class_methods do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountHeader
module Account::Header
extend ActiveSupport::Concern
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountInteractions
module Account::Interactions
extend ActiveSupport::Concern
class_methods do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountMasterSettings
module Account::MasterSettings
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountMerging
module Account::Merging
extend ActiveSupport::Concern
def merge_with!(other_account)

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountOtherSettings
module Account::OtherSettings
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountSearch
module Account::Search
extend ActiveSupport::Concern
DISALLOWED_TSQUERY_CHARACTERS = /['?\\:]/

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module AccountStatusesSearch
module Account::StatusesSearch
extend ActiveSupport::Concern
included do

View file

@ -5,7 +5,7 @@ module Remotable
class_methods do
def remotable_attachment(attachment_name, limit, suppress_errors: true, download_on_assign: true, attribute_name: nil)
attribute_name ||= "#{attachment_name}_remote_url".to_sym
attribute_name ||= :"#{attachment_name}_remote_url"
define_method("download_#{attachment_name}!") do |url = nil|
url ||= self[attribute_name]

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module StatusSafeReblogInsert
module Status::SafeReblogInsert
extend ActiveSupport::Concern
class_methods do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module StatusSearchConcern
module Status::SearchConcern
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module StatusSnapshotConcern
module Status::SnapshotConcern
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module StatusThreadingConcern
module Status::ThreadingConcern
extend ActiveSupport::Concern
def ancestors(limit, account = nil)

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module HasUserSettings
module User::HasSettings
extend ActiveSupport::Concern
included do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module LdapAuthenticable
module User::LdapAuthenticable
extend ActiveSupport::Concern
class_methods do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module Omniauthable
module User::Omniauthable
extend ActiveSupport::Concern
TEMP_EMAIL_PREFIX = 'change@me'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
module PamAuthenticable
module User::PamAuthenticable
extend ActiveSupport::Concern
included do

View file

@ -15,7 +15,7 @@
class Conversation < ApplicationRecord
validates :uri, uniqueness: true, if: :uri?
has_many :statuses
has_many :statuses, dependent: nil
belongs_to :ancestor_status, class_name: 'Status', inverse_of: :owned_conversation, optional: true
def local?

View file

@ -39,7 +39,7 @@ class CustomEmoji < ApplicationRecord
IMAGE_MIME_TYPES = %w(image/png image/gif image/webp image/jpeg).freeze
belongs_to :category, class_name: 'CustomEmojiCategory', optional: true
has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false
has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false, dependent: nil
has_many :emoji_reactions, inverse_of: :custom_emoji, dependent: :destroy
has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false

View file

@ -11,7 +11,7 @@
#
class CustomEmojiCategory < ApplicationRecord
has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category
has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category, dependent: nil
validates :name, presence: true, uniqueness: true
end

View file

@ -40,7 +40,7 @@ class DomainBlock < ApplicationRecord
validates :domain, presence: true, uniqueness: true, domain: true
has_many :accounts, foreign_key: :domain, primary_key: :domain, inverse_of: false
has_many :accounts, foreign_key: :domain, primary_key: :domain, inverse_of: false, dependent: nil
delegate :count, to: :accounts, prefix: true
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }

View file

@ -20,7 +20,7 @@ class Invite < ApplicationRecord
include Expireable
belongs_to :user, inverse_of: :invites
has_many :users, inverse_of: :invite
has_many :users, inverse_of: :invite, dependent: nil
scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }

View file

@ -210,13 +210,11 @@ class MediaAttachment < ApplicationRecord
validates :thumbnail, absence: true, if: -> { local? && !audio_or_video? }
scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) }
scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) }
scope :local, -> { where(remote_url: '') }
scope :remote, -> { where.not(remote_url: '') }
scope :cached, -> { remote.where.not(file_file_name: nil) }
scope :local_attached, -> { attached.where(remote_url: '') }
default_scope { order(id: :asc) }
scope :local, -> { where(remote_url: '') }
scope :ordered, -> { order(id: :asc) }
scope :remote, -> { where.not(remote_url: '') }
scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) }
attr_accessor :skip_download

View file

@ -131,25 +131,25 @@ class Report < ApplicationRecord
Admin::ActionLog.where(
target_type: 'Report',
target_id: id
).unscope(:order).arel,
).arel,
Admin::ActionLog.where(
target_type: 'Account',
target_id: target_account_id
).unscope(:order).arel,
).arel,
Admin::ActionLog.where(
target_type: 'Status',
target_id: status_ids
).unscope(:order).arel,
).arel,
Admin::ActionLog.where(
target_type: 'AccountWarning',
target_id: AccountWarning.where(report_id: id).select(:id)
).unscope(:order).arel,
).arel,
].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) }
Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table))
Admin::ActionLog.latest.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table))
end
private

View file

@ -36,14 +36,14 @@
require 'ostruct'
class Status < ApplicationRecord
include Cacheable
include Discard::Model
include Paginable
include Cacheable
include StatusThreadingConcern
include StatusSnapshotConcern
include RateLimitable
include StatusSafeReblogInsert
include StatusSearchConcern
include Status::SafeReblogInsert
include Status::SearchConcern
include Status::SnapshotConcern
include Status::ThreadingConcern
include DtlHelper
rate_limit by: :account, family: :statuses
@ -78,13 +78,11 @@ class Status < ApplicationRecord
has_many :bookmarks, inverse_of: :status, dependent: :destroy
has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
has_many :reblogged_by_accounts, through: :reblogs, class_name: 'Account', source: :account
has_many :quotes, foreign_key: 'quote_of_id', class_name: 'Status', inverse_of: :quote
has_many :quotes, foreign_key: 'quote_of_id', class_name: 'Status', inverse_of: :quote, dependent: nil
has_many :quoted_by_accounts, through: :quotes, class_name: 'Account', source: :account
has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread
has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread, dependent: nil
has_many :mentions, dependent: :destroy, inverse_of: :status
has_many :mentioned_accounts, through: :mentions, source: :account, class_name: 'Account'
has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status
has_many :silent_mentions, -> { silent }, class_name: 'Mention', inverse_of: :status
has_many :media_attachments, dependent: :nullify
has_many :reference_objects, class_name: 'StatusReference', inverse_of: :status, dependent: :destroy
has_many :references, through: :reference_objects, class_name: 'Status', source: :target_status
@ -95,6 +93,10 @@ class Status < ApplicationRecord
has_many :bookmark_categories, class_name: 'BookmarkCategory', through: :bookmark_category_relationships, source: :bookmark_category
has_many :joined_bookmark_categories, class_name: 'BookmarkCategory', through: :bookmark_category_relationships, source: :bookmark_category
# The `dependent` option is enabled by the initial `mentions` association declaration
has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent
has_many :silent_mentions, -> { silent }, class_name: 'Mention', inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent
# Those associations are used for the private search index
has_many :local_mentioned, -> { merge(Account.local) }, through: :active_mentions, source: :account
has_many :local_favorited, -> { merge(Account.local) }, through: :favourites, source: :account
@ -106,11 +108,13 @@ class Status < ApplicationRecord
has_and_belongs_to_many :tags
has_one :preview_cards_status, inverse_of: :status # Because of a composite primary key, the dependent option cannot be used
# Because of a composite primary key, the `dependent` option cannot be used on this association
has_one :preview_cards_status, inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent
has_one :notification, as: :activity, dependent: :destroy
has_one :status_stat, inverse_of: :status
has_one :status_stat, inverse_of: :status, dependent: nil
has_one :poll, inverse_of: :status, dependent: :destroy
has_one :trend, class_name: 'StatusTrend', inverse_of: :status
has_one :trend, class_name: 'StatusTrend', inverse_of: :status, dependent: nil
has_one :scheduled_expiration_status, inverse_of: :status, dependent: :destroy
has_one :circle_status, inverse_of: :status, dependent: :destroy
has_many :list_status, inverse_of: :status, dependent: :destroy

View file

@ -37,7 +37,7 @@ class Trends::History
end
def uses
with_redis { |redis| redis.get(key_for(:uses))&.to_i || 0 }
with_redis { |redis| redis.get(key_for(:uses)).to_i }
end
def add(account_id)

View file

@ -53,9 +53,12 @@ class User < ApplicationRecord
filtered_languages
)
include Redisable
include LanguagesHelper
include HasUserSettings
include Redisable
include User::HasSettings
include User::LdapAuthenticable
include User::Omniauthable
include User::PamAuthenticable
# The home and list feeds will be stored in Redis for this amount
# of time, and status fan-out to followers will include only people
@ -77,22 +80,18 @@ class User < ApplicationRecord
devise :registerable, :recoverable, :validatable,
:confirmable
include Omniauthable
include PamAuthenticable
include LdapAuthenticable
belongs_to :account, inverse_of: :user
belongs_to :invite, counter_cache: :uses, optional: true
belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true
belongs_to :role, class_name: 'UserRole', optional: true
accepts_nested_attributes_for :account
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
has_many :backups, inverse_of: :user
has_many :invites, inverse_of: :user
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: nil
has_many :backups, inverse_of: :user, dependent: nil
has_many :invites, inverse_of: :user, dependent: nil
has_many :markers, inverse_of: :user, dependent: :destroy
has_many :webauthn_credentials, dependent: :destroy
has_many :ips, class_name: 'UserIp', inverse_of: :user
has_many :ips, class_name: 'UserIp', inverse_of: :user, dependent: nil
has_one :invite_request, class_name: 'UserInviteRequest', inverse_of: :user, dependent: :destroy
accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text }
@ -252,7 +251,7 @@ class User < ApplicationRecord
end
def functional_or_moved?
confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial?
confirmed? && approved? && !disabled? && !account.unavailable? && !account.memorial?
end
def unconfirmed?

View file

@ -51,7 +51,7 @@ class UserRole < ApplicationRecord
invite_users
).freeze,
moderation: %w(
moderation: %i(
view_dashboard
view_audit_log
manage_users
@ -67,7 +67,7 @@ class UserRole < ApplicationRecord
manage_sensitive_words
).freeze,
administration: %w(
administration: %i(
manage_settings
manage_rules
manage_roles
@ -76,7 +76,7 @@ class UserRole < ApplicationRecord
manage_announcements
).freeze,
devops: %w(
devops: %i(
view_devops
).freeze,

View file

@ -62,7 +62,7 @@ class UserSettings::Setting
def key
if namespace
"#{namespace}.#{name}".to_sym
:"#{namespace}.#{name}"
else
name
end

View file

@ -19,7 +19,7 @@ class Web::PushSubscription < ApplicationRecord
belongs_to :user, optional: true
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', optional: true
has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription
has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription, dependent: nil
validates :endpoint, presence: true
validates :key_p256dh, presence: true