has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
+ validates_with FollowLimitValidator, on: :create
scope :recent, -> { reorder(id: :desc) }
has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
+ validates_with FollowLimitValidator, on: :create
def authorize!
account.follow!(target_account, reblogs: show_reblogs, uri: uri)
--- /dev/null
+# frozen_string_literal: true
+
+class FollowLimitValidator < ActiveModel::Validator
+ LIMIT = ENV.fetch('MAX_FOLLOWS_THRESHOLD', 7_500).to_i
+ RATIO = ENV.fetch('MAX_FOLLOWS_RATIO', 1.1).to_f
+
+ def validate(follow)
+ return if follow.account.nil? || !follow.account.local?
+ follow.errors.add(:base, I18n.t('users.follow_limit_reached', limit: self.class.limit_for_account(follow.account))) if limit_reached?(follow.account)
+ end
+
+ class << self
+ def limit_for_account(account)
+ if account.following_count < LIMIT
+ LIMIT
+ else
+ account.followers_count * RATIO
+ end
+ end
+ end
+
+ private
+
+ def limit_reached?(account)
+ account.following_count >= self.class.limit_for_account(account)
+ end
+end
end
def import_rows
- CSV.new(import_contents).reject(&:blank?)
+ rows = CSV.new(import_contents).reject(&:blank?)
+ rows = rows.take(FollowLimitValidator.limit_for_account(@import.account)) if @import.type == 'following'
+ rows
end
end
tips: Tips
title: Welcome aboard, %{name}!
users:
+ follow_limit_reached: You cannot follow more than %{limit} people
invalid_email: The e-mail address is invalid
invalid_otp_token: Invalid two-factor code
otp_lost_help_html: If you lost access to both, you may get in touch with %{email}
follow.valid?
expect(follow).to model_have_error_on_field(:target_account)
end
+
+ it 'is invalid if account already follows too many people' do
+ alice.update(following_count: FollowLimitValidator::LIMIT)
+
+ expect(subject).to_not be_valid
+ expect(subject).to model_have_error_on_field(:base)
+ end
+
+ it 'is valid if account is only on the brink of following too many people' do
+ alice.update(following_count: FollowLimitValidator::LIMIT - 1)
+
+ expect(subject).to be_valid
+ expect(subject).to_not model_have_error_on_field(:base)
+ end
end
describe 'recent' do