Fix already-followed accounts in follow imports contributing to max follows limit

Fixes #28232
fixes/import-many-follows-overlap
Claire 2023-12-08 16:40:39 +01:00
parent 54db2006a9
commit 85abad2a86
2 changed files with 39 additions and 8 deletions

View File

@ -110,7 +110,7 @@ class Form::Import
when 'Languages' when 'Languages'
field&.split(',')&.map(&:strip)&.presence field&.split(',')&.map(&:strip)&.presence
when 'Account address' when 'Account address'
field.strip.gsub(/\A@/, '') field.strip.delete_prefix('@')
when '#domain', '#uri', 'List name' when '#domain', '#uri', 'List name'
field.strip field.strip
else else
@ -151,14 +151,29 @@ class Form::Import
errors.add(:data, I18n.t('imports.errors.over_rows_processing_limit', count: ROWS_PROCESSING_LIMIT)) if csv_row_count > ROWS_PROCESSING_LIMIT errors.add(:data, I18n.t('imports.errors.over_rows_processing_limit', count: ROWS_PROCESSING_LIMIT)) if csv_row_count > ROWS_PROCESSING_LIMIT
if type.to_sym == :following if type.to_sym == :following
base_limit = FollowLimitValidator.limit_for_account(current_account) follows_limit = FollowLimitValidator.limit_for_account(current_account)
limit = base_limit errors.add(:data, I18n.t('users.follow_limit_reached', limit: follows_limit)) if follows_count_after_import > follows_limit
limit -= current_account.following_count unless overwrite
errors.add(:data, I18n.t('users.follow_limit_reached', limit: base_limit)) if csv_row_count > limit
end end
rescue CSV::MalformedCSVError => e rescue CSV::MalformedCSVError => e
errors.add(:data, I18n.t('imports.errors.invalid_csv_file', error: e.message)) errors.add(:data, I18n.t('imports.errors.invalid_csv_file', error: e.message))
rescue EmptyFileError rescue EmptyFileError
errors.add(:data, I18n.t('imports.errors.empty')) errors.add(:data, I18n.t('imports.errors.empty'))
end end
def follows_count_after_import
return csv_row_count if overwrite
accts = parsed_rows.pluck('acct').compact.map(&:downcase).uniq.map do |acct|
username, domain = acct.split('@')
if domain.nil? || TagManager.instance.local_domain?(domain)
username.downcase
else
"#{username.downcase}@#{TagManager.instance.normalize_domain(domain)}"
end
end
current_follows = current_account.following.select(:username, :domain).map { |account| account.acct.downcase }
(current_follows + accts).uniq.size
end
end end

View File

@ -67,17 +67,33 @@ RSpec.describe Form::Import do
end end
end end
context 'when importing more follows than allowed' do context 'when the combination of existing follows and imported follows goes above the limit' do
let(:import_type) { 'following' } let(:import_type) { 'following' }
let(:import_file) { 'imports.txt' } let(:import_file) { 'imports.txt' }
before do before do
allow(FollowLimitValidator).to receive(:limit_for_account).with(account).and_return(1) account.follow!(Fabricate(:account))
allow(FollowLimitValidator).to receive(:limit_for_account).with(account).and_return(2)
end end
it 'has errors' do it 'has errors' do
subject.validate subject.validate
expect(subject.errors[:data]).to include(I18n.t('users.follow_limit_reached', limit: 1)) expect(subject.errors[:data]).to include(I18n.t('users.follow_limit_reached', limit: 2))
end
end
context 'when the combination of existing follows and imported follows falls within the limit' do
let(:import_type) { 'following' }
let(:import_file) { 'imports.txt' }
before do
account.follow!(Fabricate(:account, username: 'user', domain: 'example.com'))
allow(FollowLimitValidator).to receive(:limit_for_account).with(account).and_return(2)
end
it 'is valid' do
subject.validate
expect(subject).to be_valid
end end
end end