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

This commit is contained in:
KMY 2024-11-13 08:17:38 +09:00
commit 910eafda63
177 changed files with 1625 additions and 659 deletions

View file

@ -94,6 +94,8 @@ class Account < ApplicationRecord
include Account::Interactions
include Account::Merging
include Account::Search
include Account::Sensitizes
include Account::Silences
include Account::StatusesSearch
include Account::OtherSettings
include Account::MasterSettings
@ -136,9 +138,6 @@ class Account < ApplicationRecord
scope :remote, -> { where.not(domain: nil) }
scope :local, -> { where(domain: nil) }
scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
scope :silenced, -> { where.not(silenced_at: nil) }
scope :sensitized, -> { where.not(sensitized_at: nil) }
scope :without_silenced, -> { where(silenced_at: nil) }
scope :without_instance_actor, -> { where.not(id: INSTANCE_ACTOR_ID) }
scope :recent, -> { reorder(id: :desc) }
scope :bots, -> { where(actor_type: AUTOMATED_ACTOR_TYPES) }
@ -271,30 +270,6 @@ class Account < ApplicationRecord
ResolveAccountService.new.call(acct) unless local?
end
def silenced?
silenced_at.present?
end
def silence!(date = Time.now.utc)
update!(silenced_at: date)
end
def unsilence!
update!(silenced_at: nil)
end
def sensitized?
sensitized_at.present?
end
def sensitize!(date = Time.now.utc)
update!(sensitized_at: date)
end
def unsensitize!
update!(sensitized_at: nil)
end
def memorialize!
update!(memorial: true)
end

View file

@ -136,7 +136,7 @@ class AccountStatusesCleanupPolicy < ApplicationRecord
end
def without_direct_scope
Status.where.not(visibility: :direct)
Status.not_direct_visibility
end
def old_enough_scope(max_id = nil)

View file

@ -33,6 +33,7 @@ class Admin::ActionLogFilter
create_domain_block: { target_type: 'DomainBlock', action: 'create' }.freeze,
create_email_domain_block: { target_type: 'EmailDomainBlock', action: 'create' }.freeze,
create_ip_block: { target_type: 'IpBlock', action: 'create' }.freeze,
create_relay: { target_type: 'Relay', action: 'create' }.freeze,
create_unavailable_domain: { target_type: 'UnavailableDomain', action: 'create' }.freeze,
create_user_role: { target_type: 'UserRole', action: 'create' }.freeze,
create_canonical_email_block: { target_type: 'CanonicalEmailBlock', action: 'create' }.freeze,
@ -42,6 +43,7 @@ class Admin::ActionLogFilter
destroy_domain_allow: { target_type: 'DomainAllow', action: 'destroy' }.freeze,
destroy_domain_block: { target_type: 'DomainBlock', action: 'destroy' }.freeze,
destroy_ip_block: { target_type: 'IpBlock', action: 'destroy' }.freeze,
destroy_relay: { target_type: 'Relay', action: 'destroy' }.freeze,
destroy_email_domain_block: { target_type: 'EmailDomainBlock', action: 'destroy' }.freeze,
destroy_instance: { target_type: 'Instance', action: 'destroy' }.freeze,
destroy_unavailable_domain: { target_type: 'UnavailableDomain', action: 'destroy' }.freeze,
@ -51,8 +53,10 @@ class Admin::ActionLogFilter
disable_2fa_user: { target_type: 'User', action: 'disable_2fa' }.freeze,
disable_custom_emoji: { target_type: 'CustomEmoji', action: 'disable' }.freeze,
disable_user: { target_type: 'User', action: 'disable' }.freeze,
disable_relay: { target_type: 'Relay', action: 'disable' }.freeze,
enable_custom_emoji: { target_type: 'CustomEmoji', action: 'enable' }.freeze,
enable_user: { target_type: 'User', action: 'enable' }.freeze,
enable_relay: { target_type: 'Relay', action: 'enable' }.freeze,
memorialize_account: { target_type: 'Account', action: 'memorialize' }.freeze,
promote_user: { target_type: 'User', action: 'promote' }.freeze,
remove_avatar_user: { target_type: 'User', action: 'remove_avatar' }.freeze,

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).group(:id).reorder('statuses.id desc')
Status.joins(:media_attachments).merge(@account.media_attachments).group(:id).recent
else
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
end

View file

@ -21,6 +21,9 @@
class BulkImport < ApplicationRecord
self.inheritance_column = false
ARCHIVE_PERIOD = 1.week
CONFIRM_PERIOD = 10.minutes
belongs_to :account
has_many :rows, class_name: 'BulkImportRow', inverse_of: :bulk_import, dependent: :delete_all
@ -42,6 +45,9 @@ class BulkImport < ApplicationRecord
validates :type, presence: true
scope :archival_completed, -> { where(created_at: ..ARCHIVE_PERIOD.ago) }
scope :confirmation_missed, -> { state_unconfirmed.where(created_at: ..CONFIRM_PERIOD.ago) }
def self.progress!(bulk_import_id, imported: false)
# Use `increment_counter` so that the incrementation is done atomically in the database
BulkImport.increment_counter(:processed_items, bulk_import_id)

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Account::Sensitizes
extend ActiveSupport::Concern
included do
scope :sensitized, -> { where.not(sensitized_at: nil) }
end
def sensitized?
sensitized_at.present?
end
def sensitize!(date = Time.now.utc)
update!(sensitized_at: date)
end
def unsensitize!
update!(sensitized_at: nil)
end
end

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Account::Silences
extend ActiveSupport::Concern
included do
scope :silenced, -> { where.not(silenced_at: nil) }
scope :without_silenced, -> { where(silenced_at: nil) }
end
def silenced?
silenced_at.present?
end
def silence!(date = Time.now.utc)
update!(silenced_at: date)
end
def unsilence!
update!(silenced_at: nil)
end
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
module InetContainer
extend ActiveSupport::Concern
included do
scope :containing, ->(value) { where('ip >>= ?', value) }
scope :contained_by, ->(value) { where('ip <<= ?', value) }
end
end

View file

@ -15,7 +15,9 @@ module Status::SafeReblogInsert
#
# The code is kept similar to ActiveRecord::Persistence code and calls it
# directly when we are not handling a reblog.
def _insert_record(values, returning)
#
# https://github.com/rails/rails/blob/v7.2.1.1/activerecord/lib/active_record/persistence.rb#L238-L263
def _insert_record(connection, values, returning)
return super unless values.is_a?(Hash) && values['reblog_of_id']&.value.present?
primary_key = self.primary_key
@ -30,14 +32,19 @@ module Status::SafeReblogInsert
# The following line departs from stock ActiveRecord
# Original code was:
# im.insert(values.transform_keys { |name| arel_table[name] })
# im = Arel::InsertManager.new(arel_table)
# Instead, we use a custom builder when a reblog is happening:
im = _compile_reblog_insert(values)
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value, returning: returning).tap do |result|
# Since we are using SELECT instead of VALUES, a non-error `nil` return is possible.
# For our purposes, it's equivalent to a foreign key constraint violation
raise ActiveRecord::InvalidForeignKey, "(reblog_of_id)=(#{values['reblog_of_id'].value}) is not present in table \"statuses\"" if result.nil?
with_connection do |_c|
connection.insert(
im, "#{self} Create", primary_key || false, primary_key_value,
returning: returning
).tap do |result|
# Since we are using SELECT instead of VALUES, a non-error `nil` return is possible.
# For our purposes, it's equivalent to a foreign key constraint violation
raise ActiveRecord::InvalidForeignKey, "(reblog_of_id)=(#{values['reblog_of_id'].value}) is not present in table \"statuses\"" if result.nil?
end
end
end

View file

@ -28,6 +28,8 @@ class EmailDomainBlock < ApplicationRecord
validates :domain, presence: true, uniqueness: true, domain: true
scope :parents, -> { where(parent_id: nil) }
# Used for adding multiple blocks at once
attr_accessor :other_domains

View file

@ -17,6 +17,7 @@ class IpBlock < ApplicationRecord
CACHE_KEY = 'blocked_ips'
include Expireable
include InetContainer
include Paginable
enum :severity, {

View file

@ -25,6 +25,10 @@ class Relay < ApplicationRecord
alias enabled? accepted?
def to_log_human_identifier
inbox_url
end
def enable!
activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)
payload = Oj.dump(follow_activity(activity_id))

View file

@ -15,6 +15,7 @@ class ScheduledStatus < ApplicationRecord
TOTAL_LIMIT = 300
DAILY_LIMIT = 25
MINIMUM_OFFSET = 5.minutes.freeze
belongs_to :account, inverse_of: :scheduled_statuses
has_many :media_attachments, inverse_of: :scheduled_status, dependent: :nullify
@ -26,7 +27,7 @@ class ScheduledStatus < ApplicationRecord
private
def validate_future_date
errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET
errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + MINIMUM_OFFSET
end
def validate_total_limit

View file

@ -30,6 +30,8 @@ class SessionActivation < ApplicationRecord
DEFAULT_SCOPES = %w(read write follow).freeze
scope :latest, -> { order(id: :desc) }
class << self
def active?(id)
id && exists?(session_id: id)
@ -48,7 +50,7 @@ class SessionActivation < ApplicationRecord
end
def purge_old
order('created_at desc').offset(Rails.configuration.x.max_session_activations).destroy_all
latest.offset(Rails.configuration.x.max_session_activations).destroy_all
end
def exclusive(id)

View file

@ -24,7 +24,7 @@ class SoftwareUpdate < ApplicationRecord
class << self
def check_enabled?
ENV['UPDATE_CHECK_URL'] != ''
Rails.configuration.x.mastodon.software_update_url.present?
end
def pending_to_a

View file

@ -163,6 +163,7 @@ class Status < ApplicationRecord
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

View file

@ -130,7 +130,7 @@ class User < ApplicationRecord
scope :signed_in_recently, -> { where(current_sign_in_at: ACTIVE_DURATION.ago..) }
scope :not_signed_in_recently, -> { where(current_sign_in_at: ...ACTIVE_DURATION.ago) }
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') }
scope :matches_ip, ->(value) { left_joins(:ips).merge(IpBlock.contained_by(value)).group('users.id') }
before_validation :sanitize_role
before_create :set_approved
@ -363,7 +363,7 @@ class User < ApplicationRecord
Doorkeeper::AccessGrant.by_resource_owner(self).update_all(revoked_at: Time.now.utc)
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
batch.update_all(revoked_at: Time.now.utc)
batch.touch_all(:revoked_at)
Web::PushSubscription.where(access_token_id: batch).delete_all
# Revoke each access token for the Streaming API, since `update_all``
@ -467,7 +467,7 @@ class User < ApplicationRecord
end
def sign_up_from_ip_requires_approval?
sign_up_ip.present? && IpBlock.severity_sign_up_requires_approval.exists?(['ip >>= ?', sign_up_ip.to_s])
sign_up_ip.present? && IpBlock.severity_sign_up_requires_approval.containing(sign_up_ip.to_s).exists?
end
def sign_up_email_requires_approval?

View file

@ -11,6 +11,7 @@
class UserIp < ApplicationRecord
include DatabaseViewRecord
include InetContainer
self.primary_key = :user_id