Merge pull request #5099 from nonamethanks/deprecated-tags
Add ability to mark tags as deprecated
This commit is contained in:
@@ -50,6 +50,10 @@ class BulkUpdateRequestProcessor
|
||||
[:change_category, Tag.normalize_name($1), $2.downcase]
|
||||
when /\Anuke (\S+)\z/i
|
||||
[:nuke, $1]
|
||||
when /\Adeprecate (\S+)\z/i
|
||||
[:deprecate, $1]
|
||||
when /\Aundeprecate (\S+)\z/i
|
||||
[:undeprecate, $1]
|
||||
else
|
||||
[:invalid_line, line]
|
||||
end
|
||||
@@ -125,6 +129,18 @@ class BulkUpdateRequestProcessor
|
||||
when :nuke
|
||||
# okay
|
||||
|
||||
when :deprecate
|
||||
tag = Tag.find_by_name(args[0])
|
||||
if tag.is_deprecated?
|
||||
errors.add(:base, "Can't deprecate #{args[0]} (tag is already deprecated)")
|
||||
end
|
||||
|
||||
when :undeprecate
|
||||
tag = Tag.find_by_name(args[0])
|
||||
if !tag.is_deprecated?
|
||||
errors.add(:base, "Can't undeprecate #{args[0]} (tag is not deprecated)")
|
||||
end
|
||||
|
||||
when :invalid_line
|
||||
errors.add(:base, "Invalid line: #{args[0]}")
|
||||
|
||||
@@ -182,6 +198,16 @@ class BulkUpdateRequestProcessor
|
||||
tag = Tag.find_or_create_by_name(args[0])
|
||||
tag.update!(category: Tag.categories.value_for(args[1]))
|
||||
|
||||
when :deprecate
|
||||
tag = Tag.find_or_create_by_name(args[0])
|
||||
tag.update!(is_deprecated: true)
|
||||
TagImplication.active.where(consequent_name: tag.name).each { |ti| ti.reject!(User.system) }
|
||||
TagImplication.active.where(antecedent_name: tag.name).each { |ti| ti.reject!(User.system) }
|
||||
|
||||
when :undeprecate
|
||||
tag = Tag.find_or_create_by_name(args[0])
|
||||
tag.update!(is_deprecated: false)
|
||||
|
||||
else
|
||||
# should never happen
|
||||
raise Error, "Unknown command: #{command}"
|
||||
@@ -204,7 +230,7 @@ class BulkUpdateRequestProcessor
|
||||
[args[0], args[1]]
|
||||
when :mass_update
|
||||
PostQuery.new(args[0]).tag_names + PostQuery.new(args[1]).tag_names
|
||||
when :nuke
|
||||
when :nuke, :deprecate, :undeprecate
|
||||
PostQuery.new(args[0]).tag_names
|
||||
when :change_category
|
||||
args[0]
|
||||
@@ -240,6 +266,8 @@ class BulkUpdateRequestProcessor
|
||||
else
|
||||
"nuke {{#{args[0]}}}"
|
||||
end
|
||||
when :deprecate, :undeprecate
|
||||
"#{command.to_s} [[#{args[0]}]]"
|
||||
when :change_category
|
||||
"category [[#{args[0]}]] -> #{args[1]}"
|
||||
else
|
||||
|
||||
@@ -60,6 +60,8 @@ class ModAction < ApplicationRecord
|
||||
tag_implication_create: 140,
|
||||
tag_implication_update: 141, # XXX unused
|
||||
tag_implication_delete: 142,
|
||||
tag_deprecate: 240,
|
||||
tag_undeprecate: 242,
|
||||
ip_ban_create: 160,
|
||||
ip_ban_delete: 162,
|
||||
ip_ban_undelete: 163,
|
||||
|
||||
@@ -411,6 +411,7 @@ class Post < ApplicationRecord
|
||||
normalized_tags = Tag.convert_cosplay_tags(normalized_tags)
|
||||
normalized_tags += Tag.create_for_list(Tag.automatic_tags_for(normalized_tags))
|
||||
normalized_tags += TagImplication.tags_implied_by(normalized_tags).map(&:name)
|
||||
normalized_tags -= added_deprecated_tags
|
||||
normalized_tags = normalized_tags.compact.uniq.sort
|
||||
normalized_tags = Tag.create_for_list(normalized_tags)
|
||||
self.tag_string = normalized_tags.join(" ")
|
||||
@@ -428,6 +429,16 @@ class Post < ApplicationRecord
|
||||
tag_names - invalid_tags.map(&:name)
|
||||
end
|
||||
|
||||
def added_deprecated_tags
|
||||
added_deprecated_tags = added_tags.select(&:is_deprecated)
|
||||
if added_deprecated_tags.present?
|
||||
added_deprecated_tags_list = added_deprecated_tags.map { |t| "[[#{t.name}]]" }.to_sentence
|
||||
warnings.add(:base, "The following tags are deprecated and could not be added: #{added_deprecated_tags_list}")
|
||||
end
|
||||
|
||||
added_deprecated_tags.pluck(:name)
|
||||
end
|
||||
|
||||
def remove_negated_tags(tags)
|
||||
@negated_tags, tags = tags.partition {|x| x =~ /\A-/i}
|
||||
@negated_tags = @negated_tags.map {|x| x[1..-1]}
|
||||
|
||||
@@ -16,6 +16,7 @@ class Tag < ApplicationRecord
|
||||
validates :category, inclusion: { in: TagCategory.category_ids }
|
||||
|
||||
before_create :create_character_tag_for_cosplay_tag, if: :is_cosplay_tag?
|
||||
before_save :create_mod_action
|
||||
after_save :update_category_cache, if: :saved_change_to_category?
|
||||
after_save :update_category_post_counts, if: :saved_change_to_category?
|
||||
|
||||
@@ -217,6 +218,17 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
concerning :DeprecationMethods do
|
||||
def create_mod_action
|
||||
return if CurrentUser.user == User.system
|
||||
if is_deprecated_was == true and is_deprecated == false
|
||||
ModAction.log("marked the tag [[#{name}]] as not deprecated", :tag_undeprecate)
|
||||
elsif is_deprecated_was == false and is_deprecated == true
|
||||
ModAction.log("marked the tag [[#{name}]] as deprecated", :tag_deprecate)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module SearchMethods
|
||||
def autocorrect_matches(name)
|
||||
fuzzy_name_matches(name).order_similarity(name)
|
||||
@@ -265,7 +277,7 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
|
||||
def search(params)
|
||||
q = search_attributes(params, :id, :created_at, :updated_at, :category, :post_count, :name, :wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications, :dtext_links)
|
||||
q = search_attributes(params, :id, :created_at, :updated_at, :is_deprecated, :category, :post_count, :name, :wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications, :dtext_links)
|
||||
|
||||
if params[:fuzzy_name_matches].present?
|
||||
q = q.fuzzy_name_matches(params[:fuzzy_name_matches])
|
||||
|
||||
@@ -7,7 +7,14 @@ class TagPolicy < ApplicationPolicy
|
||||
(user.is_member? && record.post_count < 50)
|
||||
end
|
||||
|
||||
def can_change_deprecated_status?
|
||||
user.is_admin? || (record.post_count == 0 && !record.is_deprecated?)
|
||||
end
|
||||
|
||||
def permitted_attributes
|
||||
[(:category if can_change_category?)].compact
|
||||
[
|
||||
(:category if can_change_category?),
|
||||
(:is_deprecated if can_change_deprecated_status?),
|
||||
].compact
|
||||
end
|
||||
end
|
||||
|
||||
@@ -121,6 +121,10 @@
|
||||
<%= format_text(wiki_page.body) %>
|
||||
<%= render "tag_relationships/alias_and_implication_list", tag: wiki_page.tag %>
|
||||
|
||||
<% if wiki_page.tag&.is_deprecated? %>
|
||||
<p class="fineprint">This tag is <%= link_to "deprecated", wiki_page_path("help:deprecation_notice") %> and can't be added to new posts.</p>
|
||||
<% end %>
|
||||
|
||||
<p class="mt-4">
|
||||
<%= link_to_wiki "View wiki", wiki_page.title, id: "view-wiki-link" %>
|
||||
</p>
|
||||
@@ -154,6 +158,10 @@
|
||||
<p>There is no wiki page yet for the tag <%= link_to_wiki @post_set.tag.pretty_name %>. <%= link_to "Create new wiki page", new_wiki_page_path(wiki_page: { title: @post_set.tag.name }), rel: "nofollow" %>.</p>
|
||||
|
||||
<%= render "tag_relationships/alias_and_implication_list", tag: @post_set.tag %>
|
||||
|
||||
<% if @post_set.tag&.is_deprecated? %>
|
||||
<p class="fineprint">This tag is <%= link_to "deprecated", wiki_page_path("help:deprecation_notice") %> and can't be added to new posts.</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<%= f.input :name_or_alias_matches, label: "Name", input_html: { value: params[:search][:name_or_alias_matches], data: { autocomplete: "tag" } } %>
|
||||
<%= f.input :category, label: "Category", collection: TagCategory.canonical_mapping.to_a, include_blank: true,selected: params[:search][:category] %>
|
||||
<%= f.input :order, collection: [%w[Newest date], %w[Count count], %w[Name name]], include_blank: false, selected: params[:search][:order] %>
|
||||
<%= f.input :is_deprecated, label: "Is deprecated?", collection: %w[yes no], include_blank: true, selected: params[:search][:is_deprecated] %>
|
||||
<%= f.input :hide_empty, label: "Hide empty?", collection: %w[yes no], selected: params[:search][:hide_empty] %>
|
||||
<%= f.input :has_wiki_page, label: "Has wiki?", collection: %w[yes no], include_blank: true, selected: params[:search][:has_wiki_page] %>
|
||||
<%= f.input :has_artist, label: "Has artist?", collection: %w[yes no], include_blank: true, selected: params[:search][:has_artist] %>
|
||||
|
||||
@@ -5,10 +5,20 @@
|
||||
<%= edit_form_for(@tag) do |f| %>
|
||||
<% if policy(@tag).can_change_category? %>
|
||||
<%= f.input :category, collection: TagCategory.canonical_mapping.to_a, include_blank: false %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% else %>
|
||||
<p>Create a <%= link_to "bulk update request", new_bulk_update_request_path(bulk_update_request: { script: "category #{@tag.name} -> general" }) %> to change this tag's category.</p>
|
||||
<% end %>
|
||||
|
||||
<% if policy(@tag).can_change_deprecated_status? %>
|
||||
<%= f.input :is_deprecated, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %>
|
||||
<% else %>
|
||||
<% if @tag.is_deprecated? %>
|
||||
<p>Create a <%= link_to "bulk update request", new_bulk_update_request_path(bulk_update_request: { script: "deprecate #{@tag.name}" }) %> to mark this tag as not deprecated.</p>
|
||||
<% else %>
|
||||
<p>Create a <%= link_to "bulk update request", new_bulk_update_request_path(bulk_update_request: { script: "undeprecate #{@tag.name}" }) %> to mark this tag as deprecated.</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
<ul>
|
||||
<li>Count: <%= @tag.post_count %></li>
|
||||
<li>Category: <%= @tag.category_name %></li>
|
||||
<% if @tag.is_deprecated? %>
|
||||
<li> This tag is <%= link_to "deprecated", wiki_page_path("help:deprecation_notice") %> and can't be added to new posts.</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
<% end %>
|
||||
|
||||
<%= render "tag_relationships/alias_and_implication_list", tag: @wiki_page.tag %>
|
||||
|
||||
<% if @wiki_page.tag&.is_deprecated? %>
|
||||
<p class="fineprint">This tag is <%= link_to "deprecated", wiki_page_path("help:deprecation_notice") %> and can't be added to new posts.</p>
|
||||
<% end %>
|
||||
|
||||
<%= render "wiki_pages/posts", wiki_page: @wiki_page %>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
<% end %>
|
||||
|
||||
<%= render "tag_relationships/alias_and_implication_list", tag: @wiki_page.tag %>
|
||||
|
||||
<% if @wiki_page.tag&.is_deprecated? %>
|
||||
<p class="fineprint">This tag is <%= link_to "deprecated", wiki_page_path("help:deprecation_notice") %> and can't be added to new posts.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= render "wiki_pages/posts", wiki_page: @wiki_page %>
|
||||
|
||||
7
db/migrate/20220407203236_add_is_deprecated_to_tags.rb
Normal file
7
db/migrate/20220407203236_add_is_deprecated_to_tags.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class AddIsDeprecatedToTags < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
ApplicationRecord.without_timeout do
|
||||
add_column :tags, :is_deprecated, :boolean, null: false, default: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5796,6 +5796,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20220211075129'),
|
||||
('20220318082614'),
|
||||
('20220403042706'),
|
||||
('20220403220558');
|
||||
('20220403220558'),
|
||||
('20220407203236');
|
||||
|
||||
|
||||
|
||||
@@ -119,6 +119,51 @@ class TagsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
context "for deprecation" do
|
||||
setup do
|
||||
@deprecated_tag = create(:tag, name: "bad_tag", category: Tag.categories.general, post_count: 0, is_deprecated: true)
|
||||
@nondeprecated_tag = create(:tag, name: "log", category: Tag.categories.general, post_count: 0)
|
||||
@normal_tag = create(:tag, name: "random", category: Tag.categories.general, post_count: 1000)
|
||||
@normal_user = create(:user)
|
||||
@admin = create(:admin_user)
|
||||
end
|
||||
|
||||
should "not remove deprecated status if the user is not an admin" do
|
||||
put_auth tag_path(@deprecated_tag), @normal_user, params: {tag: { is_deprecated: false }}
|
||||
|
||||
assert_response 403
|
||||
assert(true, @deprecated_tag.reload.is_deprecated?)
|
||||
end
|
||||
|
||||
should "remove the deprecated status if the user is admin" do
|
||||
put_auth tag_path(@deprecated_tag), @admin, params: {tag: { is_deprecated: false }}
|
||||
|
||||
assert_redirected_to @deprecated_tag
|
||||
assert(false, @deprecated_tag.reload.is_deprecated?)
|
||||
end
|
||||
|
||||
should "allow marking a tag as deprecated if it's empty" do
|
||||
put_auth tag_path(@nondeprecated_tag), @normal_user, params: {tag: { is_deprecated: true }}
|
||||
|
||||
assert_redirected_to @nondeprecated_tag
|
||||
assert(true, @nondeprecated_tag.reload.is_deprecated?)
|
||||
end
|
||||
|
||||
should "not allow marking a tag as deprecated if it's not empty" do
|
||||
put_auth tag_path(@normal_tag), @normal_user, params: {tag: { is_deprecated: true }}
|
||||
|
||||
assert_response 403
|
||||
assert(false, @normal_tag.reload.is_deprecated?)
|
||||
end
|
||||
|
||||
should "allow admins to mark tags as deprecated" do
|
||||
put_auth tag_path(@normal_tag), @admin, params: {tag: { is_deprecated: true }}
|
||||
|
||||
assert_redirected_to @normal_tag
|
||||
assert(true, @normal_tag.reload.is_deprecated?)
|
||||
end
|
||||
end
|
||||
|
||||
should "not change category when the tag is too large to be changed by a builder" do
|
||||
@tag.update(category: Tag.categories.general, post_count: 1001)
|
||||
put_auth tag_path(@tag), @user, params: {:tag => {:category => Tag.categories.artist}}
|
||||
|
||||
@@ -446,6 +446,34 @@ class BulkUpdateRequestTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
context "the deprecate command" do
|
||||
should "deprecate the tag" do
|
||||
@tag = create(:tag, name: "silver_hair")
|
||||
@bur = create_bur!("deprecate silver_hair", @admin)
|
||||
|
||||
assert_equal(true, @tag.reload.is_deprecated?)
|
||||
end
|
||||
|
||||
should "remove implications" do
|
||||
@ti1 = create(:tag_implication, antecedent_name: "silver_hair", consequent_name: "old_woman")
|
||||
@ti2 = create(:tag_implication, antecedent_name: "my_literal_dog", consequent_name: "silver_hair")
|
||||
@bur = create_bur!("deprecate silver_hair", @admin)
|
||||
|
||||
assert_equal("deleted", @ti1.reload.status)
|
||||
assert_equal("deleted", @ti2.reload.status)
|
||||
assert_equal("approved", @bur.reload.status)
|
||||
end
|
||||
end
|
||||
|
||||
context "the undeprecate command" do
|
||||
should "undeprecate the tag" do
|
||||
@tag = create(:tag, name: "silver_hair", is_deprecated: true)
|
||||
@bur = create_bur!("undeprecate silver_hair", @admin)
|
||||
|
||||
assert_equal(false, @tag.reload.is_deprecated?)
|
||||
end
|
||||
end
|
||||
|
||||
context "that contains a mass update followed by an alias" do
|
||||
should "make the alias take effect after the mass update" do
|
||||
@p1 = create(:post, tag_string: "maid_dress")
|
||||
|
||||
@@ -479,6 +479,23 @@ class PostTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
context "tagged with a deprecated tag" do
|
||||
should "not remove the tag if the tag was already in the post" do
|
||||
bad_tag = create(:tag, name: "bad_tag")
|
||||
old_post = FactoryBot.create(:post, tag_string: "bad_tag")
|
||||
bad_tag.update!(is_deprecated: true)
|
||||
old_post.update!(tag_string: "asd bad_tag")
|
||||
assert_equal("asd bad_tag", old_post.reload.tag_string)
|
||||
|
||||
end
|
||||
|
||||
should "not add the tag if it is being added" do
|
||||
create(:tag, name: "a_bad_tag", is_deprecated: true)
|
||||
@post.update!(tag_string: "asd a_bad_tag")
|
||||
assert_equal("asd", @post.reload.tag_string)
|
||||
end
|
||||
end
|
||||
|
||||
context "tagged with a metatag" do
|
||||
context "for typing a tag" do
|
||||
setup do
|
||||
|
||||
Reference in New Issue
Block a user