Change lists to reflect added and removed users retroactively (#32930)

This commit is contained in:
Eugen Rochko 2024-11-19 11:04:12 +01:00 committed by GitHub
parent f2976ec9a4
commit 2b5faa2ba3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 157 additions and 25 deletions

View file

@ -15,17 +15,12 @@ class Api::V1::Lists::AccountsController < Api::BaseController
end end
def create def create
ApplicationRecord.transaction do AddAccountsToListService.new.call(@list, Account.find(account_ids))
list_accounts.each do |account|
@list.accounts << account
end
end
render_empty render_empty
end end
def destroy def destroy
ListAccount.where(list: @list, account_id: account_ids).destroy_all RemoveAccountsFromListService.new.call(@list, Account.where(id: account_ids))
render_empty render_empty
end end
@ -43,10 +38,6 @@ class Api::V1::Lists::AccountsController < Api::BaseController
end end
end end
def list_accounts
Account.find(account_ids)
end
def account_ids def account_ids
Array(resource_params[:account_ids]) Array(resource_params[:account_ids])
end end

View file

@ -33,8 +33,15 @@ class FollowRequest < ApplicationRecord
def authorize! def authorize!
follow = account.follow!(target_account, reblogs: show_reblogs, notify: notify, languages: languages, uri: uri, bypass_limit: true) follow = account.follow!(target_account, reblogs: show_reblogs, notify: notify, languages: languages, uri: uri, bypass_limit: true)
ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id)
MergeWorker.perform_async(target_account.id, account.id) if account.local? if account.local?
ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id)
MergeWorker.perform_async(target_account.id, account.id, 'home')
MergeWorker.push_bulk(List.where(account: account).joins(:list_accounts).where(list_accounts: { account_id: target_account.id }).pluck(:id)) do |list_id|
[target_account.id, list_id, 'list']
end
end
destroy! destroy!
end end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
class AddAccountsToListService < BaseService
def call(list, accounts)
@list = list
@accounts = accounts
return if @accounts.empty?
update_list!
merge_into_list!
end
private
def update_list!
ApplicationRecord.transaction do
@accounts.each do |account|
@list.accounts << account
end
end
end
def merge_into_list!
MergeWorker.push_bulk(merge_account_ids) do |account_id|
[account_id, @list.id, 'list']
end
end
def merge_account_ids
ListAccount.where(list: @list, account: @accounts).where.not(follow_id: nil).pluck(:account_id)
end
end

View file

@ -81,7 +81,10 @@ class FollowService < BaseService
follow = @source_account.follow!(@target_account, **follow_options.merge(rate_limit: @options[:with_rate_limit], bypass_limit: @options[:bypass_limit])) follow = @source_account.follow!(@target_account, **follow_options.merge(rate_limit: @options[:with_rate_limit], bypass_limit: @options[:bypass_limit]))
LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name, 'follow') LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name, 'follow')
MergeWorker.perform_async(@target_account.id, @source_account.id) MergeWorker.perform_async(@target_account.id, @source_account.id, 'home')
MergeWorker.push_bulk(List.where(account: @source_account).joins(:list_accounts).where(list_accounts: { account_id: @target_account.id }).pluck(:id)) do |list_id|
[@target_account.id, list_id, 'list']
end
follow follow
end end

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
class RemoveAccountsFromListService < BaseService
def call(list, accounts)
@list = list
@accounts = accounts
return if @accounts.empty?
unmerge_from_list!
update_list!
end
private
def update_list!
ListAccount.where(list: @list, account: @accounts).destroy_all
end
def unmerge_from_list!
UnmergeWorker.push_bulk(unmerge_account_ids) do |account_id|
[account_id, @list.id, 'list']
end
end
def unmerge_account_ids
ListAccount.where(list: @list, account: @accounts).where.not(follow_id: nil).pluck(:account_id)
end
end

View file

@ -31,7 +31,13 @@ class UnfollowService < BaseService
create_notification(follow) if !@target_account.local? && @target_account.activitypub? create_notification(follow) if !@target_account.local? && @target_account.activitypub?
create_reject_notification(follow) if @target_account.local? && !@source_account.local? && @source_account.activitypub? create_reject_notification(follow) if @target_account.local? && !@source_account.local? && @source_account.activitypub?
UnmergeWorker.perform_async(@target_account.id, @source_account.id) unless @options[:skip_unmerge]
unless @options[:skip_unmerge]
UnmergeWorker.perform_async(@target_account.id, @source_account.id, 'home')
UnmergeWorker.push_bulk(List.where(account: @source_account).joins(:list_accounts).where(list_accounts: { account_id: @target_account.id }).pluck(:list_id)) do |list_id|
[@target_account.id, list_id, 'list']
end
end
follow follow
end end

View file

@ -6,6 +6,12 @@ class UnmuteService < BaseService
account.unmute!(target_account) account.unmute!(target_account)
MergeWorker.perform_async(target_account.id, account.id) if account.following?(target_account) if account.following?(target_account)
MergeWorker.perform_async(target_account.id, account.id, 'home')
MergeWorker.push_bulk(List.where(account: account).joins(:list_accounts).where(list_accounts: { account_id: target_account.id }).pluck(:id)) do |list_id|
[target_account.id, list_id, 'list']
end
end
end end
end end

View file

@ -5,18 +5,42 @@ class MergeWorker
include Redisable include Redisable
include DatabaseHelper include DatabaseHelper
def perform(from_account_id, into_account_id) def perform(from_account_id, into_id, type = 'home')
with_primary do with_primary do
@from_account = Account.find(from_account_id) @from_account = Account.find(from_account_id)
end
case type
when 'home'
merge_into_home!(into_id)
when 'list'
merge_into_list!(into_id)
end
rescue ActiveRecord::RecordNotFound
true
end
private
def merge_into_home!(into_account_id)
with_primary do
@into_account = Account.find(into_account_id) @into_account = Account.find(into_account_id)
end end
with_read_replica do with_read_replica do
FeedManager.instance.merge_into_home(@from_account, @into_account) FeedManager.instance.merge_into_home(@from_account, @into_account)
end end
rescue ActiveRecord::RecordNotFound
true
ensure ensure
redis.del("account:#{into_account_id}:regeneration") redis.del("account:#{into_account_id}:regeneration")
end end
def merge_into_list!(into_list_id)
with_primary do
@into_list = List.find(into_list_id)
end
with_read_replica do
FeedManager.instance.merge_into_list(@from_account, @into_list)
end
end
end end

View file

@ -2,9 +2,18 @@
class MuteWorker class MuteWorker
include Sidekiq::Worker include Sidekiq::Worker
include DatabaseHelper
def perform(account_id, target_account_id) def perform(account_id, target_account_id)
FeedManager.instance.clear_from_home(Account.find(account_id), Account.find(target_account_id)) with_primary do
@account = Account.find(account_id)
@target_account = Account.find(target_account_id)
end
with_read_replica do
FeedManager.instance.clear_from_home(@account, @target_account)
FeedManager.instance.clear_from_lists(@account, @target_account)
end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
true true
end end

View file

@ -6,16 +6,40 @@ class UnmergeWorker
sidekiq_options queue: 'pull' sidekiq_options queue: 'pull'
def perform(from_account_id, into_account_id) def perform(from_account_id, into_id, type = 'home')
with_primary do with_primary do
@from_account = Account.find(from_account_id) @from_account = Account.find(from_account_id)
end
case type
when 'home'
unmerge_from_home!(into_id)
when 'list'
unmerge_from_list!(into_id)
end
rescue ActiveRecord::RecordNotFound
true
end
private
def unmerge_from_home!(into_account_id)
with_primary do
@into_account = Account.find(into_account_id) @into_account = Account.find(into_account_id)
end end
with_read_replica do with_read_replica do
FeedManager.instance.unmerge_from_home(@from_account, @into_account) FeedManager.instance.unmerge_from_home(@from_account, @into_account)
end end
rescue ActiveRecord::RecordNotFound end
true
def unmerge_from_list!(into_list_id)
with_primary do
@into_list = List.find(into_list_id)
end
with_read_replica do
FeedManager.instance.unmerge_from_list(@from_account, @into_list)
end
end end
end end

View file

@ -30,7 +30,7 @@ RSpec.describe FollowRequest do
follow_request.authorize! follow_request.authorize!
expect(account).to have_received(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true) expect(account).to have_received(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true)
expect(MergeWorker).to have_received(:perform_async).with(target_account.id, account.id) expect(MergeWorker).to have_received(:perform_async).with(target_account.id, account.id, 'home')
expect(follow_request).to have_received(:destroy!) expect(follow_request).to have_received(:destroy!)
end end

View file

@ -16,7 +16,7 @@ RSpec.describe UnmuteService do
it 'removes the account mute and sets up a merge' do it 'removes the account mute and sets up a merge' do
expect { subject.call(account, target_account) } expect { subject.call(account, target_account) }
.to remove_account_mute .to remove_account_mute
expect(MergeWorker).to have_enqueued_sidekiq_job(target_account.id, account.id) expect(MergeWorker).to have_enqueued_sidekiq_job(target_account.id, account.id, 'home')
end end
end end