Merge commit '9e04007020' into upstream-20240725

This commit is contained in:
KMY 2024-07-25 13:06:26 +09:00
commit a99f174d98
322 changed files with 8093 additions and 1586 deletions

View file

@ -5,6 +5,14 @@ class Admin::ActionLogFilter
action_type
account_id
target_account_id
target_domain
).freeze
INSTANCE_TARGET_TYPES = %w(
DomainBlock
DomainAllow
Instance
UnavailableDomain
).freeze
ACTION_TYPE_MAP = {
@ -99,6 +107,9 @@ class Admin::ActionLogFilter
when 'target_account_id'
account = Account.find_or_initialize_by(id: value)
latest_action_logs.where(target: [account, account.user].compact)
when 'target_domain'
normalized_domain = TagManager.instance.normalize_domain(value)
latest_action_logs.where(human_identifier: normalized_domain, target_type: INSTANCE_TARGET_TYPES)
else
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
end

View file

@ -34,6 +34,7 @@ class Notification < ApplicationRecord
'AccountWarning' => :moderation_warning,
}.freeze
# Please update app/javascript/api_types/notification.ts if you change this
PROPERTIES = {
mention: {
filterable: true,
@ -166,31 +167,51 @@ class Notification < ApplicationRecord
end
end
def paginate_groups(limit, pagination_order)
raise ArgumentError unless %i(asc desc).include?(pagination_order)
query = reorder(id: pagination_order)
unscoped
.with_recursive(
grouped_notifications: [
# Base case: fetching one notification and annotating it with visited groups
query
.select('notifications.*', "ARRAY[COALESCE(notifications.group_key, 'ungrouped-' || notifications.id)] AS groups")
.limit(1),
# Recursive case, always yielding at most one annotated notification
unscoped
.from(
[
# Expose the working table as `wt`, but quit early if we've reached the limit
unscoped
.select('id', 'groups')
.from('grouped_notifications')
.where('array_length(grouped_notifications.groups, 1) < :limit', limit: limit)
.arel.as('wt'),
# Recursive query, using `LATERAL` so we can refer to `wt`
query
.where(pagination_order == :desc ? 'notifications.id < wt.id' : 'notifications.id > wt.id')
.where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(wt.groups)")
.limit(1)
.arel.lateral('notifications'),
]
)
.select('notifications.*', "array_append(wt.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))"),
]
)
.from('grouped_notifications AS notifications')
.order(id: pagination_order)
.limit(limit)
end
# This returns notifications from the request page, but with at most one notification per group.
# Notifications that have no `group_key` each count as a separate group.
def paginate_groups_by_max_id(limit, max_id: nil, since_id: nil)
query = reorder(id: :desc)
query = query.where(id: ...max_id) if max_id.present?
query = query.where(id: (since_id + 1)...) if since_id.present?
unscoped
.with_recursive(
grouped_notifications: [
query
.select('notifications.*', "ARRAY[COALESCE(notifications.group_key, 'ungrouped-' || notifications.id)] groups")
.limit(1),
query
.joins('CROSS JOIN grouped_notifications')
.where('array_length(grouped_notifications.groups, 1) < :limit', limit: limit)
.where('notifications.id < grouped_notifications.id')
.where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)")
.select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))")
.limit(1),
]
)
.from('grouped_notifications AS notifications')
.order(id: :desc)
.limit(limit)
query.paginate_groups(limit, :desc)
end
# Differs from :paginate_groups_by_max_id in that it gives the results immediately following min_id,
@ -200,25 +221,7 @@ class Notification < ApplicationRecord
query = reorder(id: :asc)
query = query.where(id: (min_id + 1)...) if min_id.present?
query = query.where(id: ...max_id) if max_id.present?
unscoped
.with_recursive(
grouped_notifications: [
query
.select('notifications.*', "ARRAY[COALESCE(notifications.group_key, 'ungrouped-' || notifications.id)] groups")
.limit(1),
query
.joins('CROSS JOIN grouped_notifications')
.where('array_length(grouped_notifications.groups, 1) < :limit', limit: limit)
.where('notifications.id > grouped_notifications.id')
.where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)")
.select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))")
.limit(1),
]
)
.from('grouped_notifications AS notifications')
.order(id: :asc)
.limit(limit)
query.paginate_groups(limit, :asc)
end
def to_a_grouped_paginated_by_id(limit, options = {})

View file

@ -3,13 +3,17 @@
class NotificationGroup < ActiveModelSerializers::Model
attributes :group_key, :sample_accounts, :notifications_count, :notification, :most_recent_notification_id
# Try to keep this consistent with `app/javascript/mastodon/models/notification_group.ts`
SAMPLE_ACCOUNTS_SIZE = 8
def self.from_notification(notification, max_id: nil)
if notification.group_key.present?
# TODO: caching and preloading
# TODO: caching, and, if caching, preloading
scope = notification.account.notifications.where(group_key: notification.group_key)
scope = scope.where(id: ..max_id) if max_id.present?
most_recent_notifications = scope.order(id: :desc).take(3)
# Ideally, we would not load accounts for each notification group
most_recent_notifications = scope.order(id: :desc).includes(:from_account).take(SAMPLE_ACCOUNTS_SIZE)
most_recent_id = most_recent_notifications.first.id
sample_accounts = most_recent_notifications.map(&:from_account)
notifications_count = scope.count

View file

@ -18,6 +18,7 @@
# category :integer default("other"), not null
# action_taken_at :datetime
# rule_ids :bigint(8) is an Array
# application_id :bigint(8)
#
class Report < ApplicationRecord
@ -31,6 +32,7 @@ class Report < ApplicationRecord
rate_limit by: :account, family: :reports
belongs_to :account
belongs_to :application, class_name: 'Doorkeeper::Application', optional: true
with_options class_name: 'Account' do
belongs_to :target_account