From 92ec805278cda94e2c10626f0a5b908ae60b6eb9 Mon Sep 17 00:00:00 2001 From: Pablo Monfort Date: Tue, 21 Jul 2026 10:22:53 -0300 Subject: [PATCH] AO3-7156 Add scheduled task to delete unused admin post tags. --- app/models/admin_post_tag.rb | 6 ++++ config/resque_schedule.yml | 7 +++++ factories/admin_post_tags.rb | 8 ++++++ lib/tasks/tag_tasks.rake | 2 +- spec/models/admin_post_tag_spec.rb | 44 ++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 factories/admin_post_tags.rb create mode 100644 spec/models/admin_post_tag_spec.rb diff --git a/app/models/admin_post_tag.rb b/app/models/admin_post_tag.rb index 47d98d14308..cc72f167195 100644 --- a/app/models/admin_post_tag.rb +++ b/app/models/admin_post_tag.rb @@ -1,4 +1,7 @@ class AdminPostTag < ApplicationRecord + include AsyncWithResque + @queue = :utilities + belongs_to :language has_many :admin_post_taggings has_many :admin_posts, through: :admin_post_taggings @@ -18,4 +21,7 @@ def self.fetch(name, language_id) tag.valid? ? tag : nil end + def self.delete_unused + left_outer_joins(:admin_post_taggings).where(admin_post_taggings: { id: nil }).delete_all + end end diff --git a/config/resque_schedule.yml b/config/resque_schedule.yml index 988be768cfb..f22b285f949 100644 --- a/config/resque_schedule.yml +++ b/config/resque_schedule.yml @@ -114,6 +114,13 @@ cleanup_work_original_creators: Remove original_creators for works orphaned/moved more than ORIGINAL_CREATOR_TTL_HOURS hours ago. +delete_unused_admin_post_tags: + cron: "0 0 * * 0" + class: "AdminPostTag" + queue: utilities + args: delete_unused + description: "Delete admin post tags not used on any admin post." + disable_admin_post_comments: every: 1d class: "AdminPost" diff --git a/factories/admin_post_tags.rb b/factories/admin_post_tags.rb new file mode 100644 index 00000000000..c1e693c6f9b --- /dev/null +++ b/factories/admin_post_tags.rb @@ -0,0 +1,8 @@ +require "faker" + +FactoryBot.define do + factory :admin_post_tag do + name { Faker::Lorem.unique.word } + language { Language.default } + end +end diff --git a/lib/tasks/tag_tasks.rake b/lib/tasks/tag_tasks.rake index 1af40a87eaa..09a64ba098e 100644 --- a/lib/tasks/tag_tasks.rake +++ b/lib/tasks/tag_tasks.rake @@ -86,7 +86,7 @@ namespace :Tag do desc "Delete unused admin post tags" task(delete_unused_admin_post_tags: :environment) do - AdminPostTag.joins("LEFT JOIN `admin_post_taggings` ON admin_post_taggings.admin_post_tag_id = admin_post_tags.id").where("admin_post_taggings.id IS NULL").destroy_all + AdminPostTag.delete_unused end desc "Clean up orphaned taggings" diff --git a/spec/models/admin_post_tag_spec.rb b/spec/models/admin_post_tag_spec.rb new file mode 100644 index 00000000000..f31e27e779c --- /dev/null +++ b/spec/models/admin_post_tag_spec.rb @@ -0,0 +1,44 @@ +require "spec_helper" + +describe AdminPostTag do + describe ".delete_unused" do + let!(:admin_post) { create(:admin_post) } + let!(:tag) { create(:admin_post_tag) } + + context "when a tag is used on an admin post" do + before do + admin_post.admin_post_taggings.create!(admin_post_tag: tag) + end + + it "does not delete the tag" do + expect { AdminPostTag.delete_unused } + .not_to change { AdminPostTag.count } + end + end + + context "when a tag is not used on any admin post" do + it "deletes the tag" do + expect { AdminPostTag.delete_unused } + .to change { AdminPostTag.count } + .by(-1) + expect(AdminPostTag.find_by(name: tag.name)).to be_nil + end + end + + context "when both used and unused tags exist" do + let!(:unused_tag) { create(:admin_post_tag) } + + before do + admin_post.admin_post_taggings.create!(admin_post_tag: tag) + end + + it "only deletes the unused tag" do + expect { AdminPostTag.delete_unused } + .to change { AdminPostTag.count } + .by(-1) + expect(AdminPostTag.find_by(name: tag.name)).to be_present + expect(AdminPostTag.find_by(name: unused_tag.name)).to be_nil + end + end + end +end