From 37e82ee66f014aaece2130f6d0ea9138a8500cb7 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 12 Feb 2026 11:25:29 +0100 Subject: [PATCH] Add `--suspended-only` option to `tootctl emoji purge` (#37828) --- lib/mastodon/cli/emoji.rb | 16 ++++++++++++++-- spec/lib/mastodon/cli/emoji_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/mastodon/cli/emoji.rb b/lib/mastodon/cli/emoji.rb index 206961f8548..a115750c539 100644 --- a/lib/mastodon/cli/emoji.rb +++ b/lib/mastodon/cli/emoji.rb @@ -109,15 +109,27 @@ module Mastodon::CLI end option :remote_only, type: :boolean + option :suspended_only, type: :boolean desc 'purge', 'Remove all custom emoji' long_desc <<-LONG_DESC Removes all custom emoji. With the --remote-only option, only remote emoji will be deleted. + + With the --suspended-only option, only emoji from suspended servers will be deleted. LONG_DESC def purge - scope = options[:remote_only] ? CustomEmoji.remote : CustomEmoji - scope.in_batches.destroy_all + if options[:suspended_only] + DomainBlock.where(severity: :suspend).find_each do |domain_block| + CustomEmoji.by_domain_and_subdomains(domain_block.domain).find_in_batches do |custom_emojis| + AttachmentBatch.new(CustomEmoji, custom_emojis).delete + end + end + else + scope = options[:remote_only] ? CustomEmoji.remote : CustomEmoji + scope.in_batches.destroy_all + end + say('OK', :green) end diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb index 4336db17d37..b21c533e97f 100644 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ b/spec/lib/mastodon/cli/emoji_spec.rb @@ -23,6 +23,35 @@ RSpec.describe Mastodon::CLI::Emoji do .to output_results('OK') end end + + context 'with --suspended-only and existing custom emoji on blocked servers' do + let(:blocked_domain) { 'evil.com' } + let(:blocked_subdomain) { 'subdomain.evil.org' } + let(:blocked_domain_without_emoji) { 'blocked.com' } + let(:silenced_domain) { 'silenced.com' } + + let(:options) { { suspended_only: true } } + + before do + Fabricate(:custom_emoji) + Fabricate(:custom_emoji, domain: blocked_domain) + Fabricate(:custom_emoji, domain: blocked_subdomain) + Fabricate(:custom_emoji, domain: silenced_domain) + + Fabricate(:domain_block, severity: :suspend, domain: blocked_domain) + Fabricate(:domain_block, severity: :suspend, domain: 'evil.org') + Fabricate(:domain_block, severity: :suspend, domain: blocked_domain_without_emoji) + Fabricate(:domain_block, severity: :silence, domain: silenced_domain) + end + + it 'reports a successful purge' do + expect { subject } + .to change { CustomEmoji.by_domain_and_subdomains(blocked_domain).count }.to(0) + .and change { CustomEmoji.by_domain_and_subdomains('evil.org').count }.to(0) + .and not_change { CustomEmoji.by_domain_and_subdomains(silenced_domain).count } + .and(not_change { CustomEmoji.local.count }) + end + end end describe '#import' do