diff --git a/app/jobs/scheduled/clean_up_tags.rb b/app/jobs/scheduled/clean_up_tags.rb new file mode 100644 index 00000000000..835ae8d689b --- /dev/null +++ b/app/jobs/scheduled/clean_up_tags.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jobs + class CleanUpTags < ::Jobs::Scheduled + every 1.day + + GRACE_PERIOD_MINUTES = 5 + + def execute(args) + return unless SiteSetting.automatically_clean_unused_tags + Tag.unused.where("tags.created_at < ?", GRACE_PERIOD_MINUTES.minutes.ago).destroy_all + end + end +end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index c086da55627..b718aa1ce87 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2401,6 +2401,7 @@ en: remove_muted_tags_from_latest: "Don't show topics tagged only with muted tags in the latest topic list." force_lowercase_tags: "Force all new tags to be entirely lowercase." create_post_for_category_and_tag_changes: "Create a small action post when a topic's category or tags change" + automatically_clean_unused_tags: "Automatically delete tags that are not being used on any topics or private messages on a daily basis." watched_precedence_over_muted: "Notify me about topics in categories or tags I’m watching that also belong to one I have muted" company_name: "Name of your company or organization. If left blank, no boilerplate Terms of Service or Privacy Notice will be provided." diff --git a/config/site_settings.yml b/config/site_settings.yml index bcec4218bf0..82e276775df 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2886,6 +2886,8 @@ tags: client: true create_post_for_category_and_tag_changes: default: false + automatically_clean_unused_tags: + default: false dashboard: dashboard_hidden_reports: diff --git a/spec/jobs/clean_up_tags_spec.rb b/spec/jobs/clean_up_tags_spec.rb new file mode 100644 index 00000000000..34f48ef29b3 --- /dev/null +++ b/spec/jobs/clean_up_tags_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe Jobs::CleanUpTags do + subject(:job) { described_class.new } + + let!(:tags) do + [ + Fabricate( + :tag, + name: "used_publically", + staff_topic_count: 2, + public_topic_count: 2, + pm_topic_count: 0, + created_at: 10.minutes.ago, + ), + Fabricate( + :tag, + name: "used_privately", + staff_topic_count: 0, + public_topic_count: 0, + pm_topic_count: 3, + created_at: 10.minutes.ago, + ), + Fabricate( + :tag, + name: "used_by_staff", + staff_topic_count: 3, + public_topic_count: 0, + pm_topic_count: 0, + created_at: 10.minutes.ago, + ), + ] + end + fab!(:unused_tag) do + Fabricate( + :tag, + name: "unused1", + staff_topic_count: 0, + public_topic_count: 0, + pm_topic_count: 0, + created_at: 10.minutes.ago, + ) + end + + fab!(:tag_in_group) do + Fabricate( + :tag, + name: "unused_in_group", + public_topic_count: 0, + staff_topic_count: 0, + pm_topic_count: 0, + ) + end + fab!(:tag_group) { Fabricate(:tag_group, tag_names: [tag_in_group.name]) } + + it "deletes unused tags" do + SiteSetting.automatically_clean_unused_tags = true + expect { job.execute({}) }.to change { Tag.count }.by(-1) + expect { unused_tag.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "does nothing when site setting is disabled by default" do + expect { job.execute({}) }.not_to change { Tag.count } + end +end