has_many :announcement_mutes, dependent: :destroy
end
- def follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false)
- rel = active_relationships.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit)
+ def follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false, bypass_limit: false)
+ rel = active_relationships.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit, bypass_follow_limit: bypass_limit)
.find_or_create_by!(target_account: other_account)
rel.show_reblogs = reblogs unless reblogs.nil?
rel
end
- def request_follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false)
- rel = follow_requests.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit)
+ def request_follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false, bypass_limit: false)
+ rel = follow_requests.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit, bypass_follow_limit: bypass_limit)
.find_or_create_by!(target_account: other_account)
rel.show_reblogs = reblogs unless reblogs.nil?
--- /dev/null
+# frozen_string_literal: true
+
+module FollowLimitable
+ extend ActiveSupport::Concern
+
+ included do
+ validates_with FollowLimitValidator, on: :create, unless: :bypass_follow_limit?
+ end
+
+ def bypass_follow_limit=(value)
+ @bypass_follow_limit = value
+ end
+
+ def bypass_follow_limit?
+ @bypass_follow_limit
+ end
+end
include Paginable
include RelationshipCacheable
include RateLimitable
+ include FollowLimitable
rate_limit by: :account, family: :follows
has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
- validates_with FollowLimitValidator, on: :create, if: :rate_limit?
scope :recent, -> { reorder(id: :desc) }
include Paginable
include RelationshipCacheable
include RateLimitable
+ include FollowLimitable
rate_limit by: :account, family: :follows
has_one :notification, as: :activity, dependent: :destroy
validates :account_id, uniqueness: { scope: :target_account_id }
- validates_with FollowLimitValidator, on: :create, if: :rate_limit?
def authorize!
account.follow!(target_account, reblogs: show_reblogs, notify: notify, uri: uri)
# @option [Boolean] :reblogs Whether or not to show reblogs, defaults to true
# @option [Boolean] :notify Whether to create notifications about new posts, defaults to false
# @option [Boolean] :bypass_locked
+ # @option [Boolean] :bypass_limit Allow following past the total follow number
# @option [Boolean] :with_rate_limit
def call(source_account, target_account, options = {})
@source_account = source_account
@target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
- @options = { bypass_locked: false, with_rate_limit: false }.merge(options)
+ @options = { bypass_locked: false, bypass_limit: false, with_rate_limit: false }.merge(options)
raise ActiveRecord::RecordNotFound if following_not_possible?
raise Mastodon::NotPermittedError if following_not_allowed?
end
def request_follow!
- follow_request = @source_account.request_follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit])
+ follow_request = @source_account.request_follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit], bypass_limit: @options[:bypass_limit])
if @target_account.local?
LocalNotificationWorker.perform_async(@target_account.id, follow_request.id, follow_request.class.name, :follow_request)
end
def direct_follow!
- follow = @source_account.follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit])
+ follow = @source_account.follow!(@target_account, reblogs: @options[:reblogs], notify: @options[:notify], rate_limit: @options[:with_rate_limit], bypass_limit: @options[:bypass_limit])
LocalNotificationWorker.perform_async(@target_account.id, follow.id, follow.class.name, :follow)
MergeWorker.perform_async(@target_account.id, @source_account.id)
source_account = Account.find(source_account_id)
target_account = Account.find(target_account_id)
- AuthorizeFollowService.new.call(source_account, target_account)
+ AuthorizeFollowService.new.call(source_account, target_account, bypass_limit: true)
rescue ActiveRecord::RecordNotFound
true
end
case relationship
when 'follow'
- FollowService.new.call(from_account, target_account, options)
+ begin
+ FollowService.new.call(from_account, target_account, options)
+ rescue ActiveRecord::RecordInvalid
+ raise if FollowLimitValidator.limit_for_account(from_account) < from_account.following_count
+ end
when 'unfollow'
UnfollowService.new.call(from_account, target_account)
when 'block'
# Schedule re-follow
begin
- FollowService.new.call(follower, target_account, reblogs: reblogs, notify: notify)
+ FollowService.new.call(follower, target_account, reblogs: reblogs, notify: notify, bypass_limit: true)
rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, HTTP::Error, OpenSSL::SSL::SSLError
next
end
reblogs = follow&.show_reblogs?
notify = follow&.notify?
- FollowService.new.call(follower_account, new_target_account, reblogs: reblogs, notify: notify, bypass_locked: bypass_locked)
+ FollowService.new.call(follower_account, new_target_account, reblogs: reblogs, notify: notify, bypass_locked: bypass_locked, bypass_limit: true)
UnfollowService.new.call(follower_account, old_target_account, skip_unmerge: true)
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
true
end
processed, = parallelize_with_progress(Account.local.without_suspended) do |account|
- FollowService.new.call(account, target_account)
+ FollowService.new.call(account, target_account, bypass_limit: true)
end
say("OK, followed target from #{processed} accounts", :green)
result = subject.perform(account.id)
expect(result).to be_nil
- expect(service).to have_received(:call).with(alice, account, reblogs: true, notify: false)
- expect(service).to have_received(:call).with(bob, account, reblogs: false, notify: false)
+ expect(service).to have_received(:call).with(alice, account, reblogs: true, notify: false, bypass_limit: true)
+ expect(service).to have_received(:call).with(bob, account, reblogs: false, notify: false, bypass_limit: true)
end
end
end