Skip to content

Commit c4c291f

Browse files
ClearlyClairehiyuki2578
authored andcommitted
Record account suspend/silence time and keep track of domain blocks (mastodon#10660)
* Record account suspend/silence time and keep track of domain blocks * Also unblock users who were suspended/silenced before dates were recorded * Add tests * Keep track of suspending date for users suspended through the CLI * Show accurate number of accounts that would be affected by unsuspending an instance * Change migration to set silenced_at and suspended_at * Revert "Also unblock users who were suspended/silenced before dates were recorded" This reverts commit a015c65. * Switch from using suspended and silenced to suspended_at and silenced_at * Add post-deployment migration script to remove `suspended` and `silenced` columns * Use Account#silence! and Account#suspend! instead of updating the underlying property * Add silenced_at and suspended_at migration to post-migration * Change account fabricator to translate suspended and silenced attributes * Minor fixes * Make unblocking domains always retroactive
1 parent aa53d23 commit c4c291f

30 files changed

Lines changed: 226 additions & 115 deletions

app/controllers/admin/domain_blocks_controller.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def show
4141

4242
def destroy
4343
authorize @domain_block, :destroy?
44-
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
44+
UnblockDomainService.new.call(@domain_block)
4545
log_action :destroy, @domain_block
4646
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg')
4747
end
@@ -53,11 +53,7 @@ def set_domain_block
5353
end
5454

5555
def resource_params
56-
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :retroactive)
57-
end
58-
59-
def retroactive_unblock?
60-
ActiveRecord::Type.lookup(:boolean).cast(resource_params[:retroactive])
56+
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)
6157
end
6258
end
6359
end

app/controllers/home_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def default_redirect_path
5858
if request.path.start_with?('/web')
5959
new_user_session_path
6060
elsif single_user_mode?
61-
short_account_path(Account.local.where(suspended: false).first)
61+
short_account_path(Account.local.without_suspended.first)
6262
else
6363
about_path
6464
end

app/models/account.rb

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
# header_updated_at :datetime
2929
# avatar_remote_url :string
3030
# subscription_expires_at :datetime
31-
# silenced :boolean default(FALSE), not null
32-
# suspended :boolean default(FALSE), not null
3331
# locked :boolean default(FALSE), not null
3432
# header_remote_url :string default(""), not null
3533
# last_webfingered_at :datetime
@@ -46,6 +44,8 @@
4644
# discoverable :boolean
4745
# also_known_as :string is an Array
4846
# cat :boolean default(FALSE), not null
47+
# silenced_at :datetime
48+
# suspended_at :datetime
4949
#
5050

5151
class Account < ApplicationRecord
@@ -83,10 +83,10 @@ class Account < ApplicationRecord
8383
scope :local, -> { where(domain: nil) }
8484
scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) }
8585
scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
86-
scope :silenced, -> { where(silenced: true) }
87-
scope :suspended, -> { where(suspended: true) }
88-
scope :without_suspended, -> { where(suspended: false) }
89-
scope :without_silenced, -> { where(silenced: false) }
86+
scope :silenced, -> { where.not(silenced_at: nil) }
87+
scope :suspended, -> { where.not(suspended_at: nil) }
88+
scope :without_suspended, -> { where(suspended_at: nil) }
89+
scope :without_silenced, -> { where(silenced_at: nil) }
9090
scope :recent, -> { reorder(id: :desc) }
9191
scope :bots, -> { where(actor_type: %w(Application Service)) }
9292
scope :alphabetic, -> { order(domain: :asc, username: :asc) }
@@ -166,25 +166,35 @@ def refresh!
166166
ResolveAccountService.new.call(acct)
167167
end
168168

169-
def silence!
170-
update!(silenced: true)
169+
def silenced?
170+
silenced_at.present?
171+
end
172+
173+
def silence!(date = nil)
174+
date ||= Time.now.utc
175+
update!(silenced_at: date)
171176
end
172177

173178
def unsilence!
174-
update!(silenced: false)
179+
update!(silenced_at: nil)
180+
end
181+
182+
def suspended?
183+
suspended_at.present?
175184
end
176185

177-
def suspend!
186+
def suspend!(date = nil)
187+
date ||= Time.now.utc
178188
transaction do
179189
user&.disable! if local?
180-
update!(suspended: true)
190+
update!(suspended_at: date)
181191
end
182192
end
183193

184194
def unsuspend!
185195
transaction do
186196
user&.enable! if local?
187-
update!(suspended: false)
197+
update!(suspended_at: nil)
188198
end
189199
end
190200

@@ -400,7 +410,7 @@ def search_for(terms, limit = 10, offset = 0)
400410
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
401411
FROM accounts
402412
WHERE #{query} @@ #{textsearch}
403-
AND accounts.suspended = false
413+
AND accounts.suspended_at IS NULL
404414
AND accounts.moved_to_account_id IS NULL
405415
ORDER BY rank DESC
406416
LIMIT ? OFFSET ?
@@ -428,7 +438,7 @@ def advanced_search_for(terms, account, limit = 10, following = false, offset =
428438
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
429439
WHERE accounts.id IN (SELECT * FROM first_degree)
430440
AND #{query} @@ #{textsearch}
431-
AND accounts.suspended = false
441+
AND accounts.suspended_at IS NULL
432442
AND accounts.moved_to_account_id IS NULL
433443
GROUP BY accounts.id
434444
ORDER BY rank DESC
@@ -444,7 +454,7 @@ def advanced_search_for(terms, account, limit = 10, following = false, offset =
444454
FROM accounts
445455
LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
446456
WHERE #{query} @@ #{textsearch}
447-
AND accounts.suspended = false
457+
AND accounts.suspended_at IS NULL
448458
AND accounts.moved_to_account_id IS NULL
449459
GROUP BY accounts.id
450460
ORDER BY rank DESC

app/models/concerns/account_finder_concern.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def find_remote!(username, domain)
1313
end
1414

1515
def representative
16-
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.find_by(suspended: false)
16+
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first
1717
end
1818

1919
def find_local(username)

app/models/domain_block.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ class DomainBlock < ApplicationRecord
1717

1818
enum severity: [:silence, :suspend, :noop]
1919

20-
attr_accessor :retroactive
21-
2220
validates :domain, presence: true, uniqueness: true
2321

2422
has_many :accounts, foreign_key: :domain, primary_key: :domain
@@ -36,4 +34,9 @@ def stricter_than?(other_block)
3634
return false if other_block.silence? && noop?
3735
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
3836
end
37+
38+
def affected_accounts_count
39+
scope = suspend? ? accounts.where(suspended_at: created_at) : accounts.where(silenced_at: created_at)
40+
scope.count
41+
end
3942
end

app/models/status.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ class Status < ApplicationRecord
8484
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
8585
scope :with_public_visibility, -> { where(visibility: :public) }
8686
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
87-
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: false }) }
88-
scope :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) }
87+
scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) }
88+
scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) }
8989
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
9090
scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
9191
scope :tagged_with_all, ->(tags) {

app/models/user.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class User < ApplicationRecord
8888
scope :confirmed, -> { where.not(confirmed_at: nil) }
8989
scope :enabled, -> { where(disabled: false) }
9090
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
91-
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) }
91+
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where.not(accounts: { suspended_at: nil }) }
9292
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
9393
scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
9494

app/services/activitypub/process_account_service.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ def call(username, domain, json, options = {})
5050

5151
def create_account
5252
@account = Account.new
53-
@account.protocol = :activitypub
54-
@account.username = @username
55-
@account.domain = @domain
56-
@account.suspended = true if auto_suspend?
57-
@account.silenced = true if auto_silence?
58-
@account.private_key = nil
53+
@account.protocol = :activitypub
54+
@account.username = @username
55+
@account.domain = @domain
56+
@account.private_key = nil
57+
@account.suspended_at = domain_block.created_at if auto_suspend?
58+
@account.silenced_at = domain_block.created_at if auto_silence?
5959
end
6060

6161
def update_account

app/services/block_domain_service.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def invalidate_association_caches!
2929
end
3030

3131
def silence_accounts!
32-
blocked_domain_accounts.in_batches.update_all(silenced: true)
32+
blocked_domain_accounts.without_silenced.in_batches.update_all(silenced_at: @domain_block.created_at)
3333
end
3434

3535
def clear_media!
@@ -43,9 +43,9 @@ def clear_media!
4343
end
4444

4545
def suspend_accounts!
46-
blocked_domain_accounts.where(suspended: false).reorder(nil).find_each do |account|
46+
blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
4747
UnsubscribeService.new.call(account) if account.subscribed?
48-
SuspendAccountService.new.call(account)
48+
SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
4949
end
5050
end
5151

app/services/post_status_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def call(account, options = {})
4949
def preprocess_attributes!
5050
@text = @options.delete(:spoiler_text) if @text.blank? && @options[:spoiler_text].present?
5151
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
52-
@visibility = :unlisted if @visibility == :public && @account.silenced
52+
@visibility = :unlisted if @visibility == :public && @account.silenced?
5353
@scheduled_at = @options[:scheduled_at]&.to_datetime
5454
@scheduled_at = nil if scheduled_in_the_past?
5555
rescue ArgumentError

0 commit comments

Comments
 (0)