Add tag alias undo support

This commit is contained in:
Kira 2019-10-03 02:15:27 -07:00
parent 28346368dc
commit fa4a51d81b
7 changed files with 192 additions and 24 deletions

View File

@ -0,0 +1,8 @@
class TagAliasJob < ApplicationJob
queue_as :tags
def perform(*args)
ta = TagAlias.find(args[0])
ta.process_undo!(update_topic: args[1])
end
end

View File

@ -1,9 +0,0 @@
class TagAliasUpdatePostsJob < ApplicationJob
queue_as :tags
def perform(*args)
ta = TagAlias.find(args[0])
ta.update_posts
end
end

View File

@ -1,4 +1,6 @@
class TagAlias < TagRelationship
has_many :tag_rel_undos, as: :tag_rel
after_save :create_mod_action
validates :antecedent_name, uniqueness: true
validate :absence_of_transitive_relation
@ -9,9 +11,16 @@ class TagAlias < TagRelationship
def approve!(update_topic: true, approver: CurrentUser.user)
CurrentUser.scoped(approver) do
update(status: "queued", approver_id: approver.id)
create_undo_information
TagAliasJob.perform_later(id, update_topic)
end
end
def undo!(approver: CurrentUser.user)
CurrentUser.scoped(approver) do
TagAliaseUndoJob.perform_later(id, true)
end
end
end
module ForumMethods
@ -54,7 +63,7 @@ class TagAlias < TagRelationship
TagAlias.to_aliased_with_originals(names).values
end
def self.to_aliased_query(query)
def self.to_aliased_query(query, overrides: nil)
# Remove tag types (newline syntax)
query.gsub!(/(^| )(-)?(#{TagCategory.mapping.keys.sort_by { |x| -x.size }.join("|")}):([\S])/i, '\1\2\4')
# Remove tag types (comma syntax)
@ -66,11 +75,85 @@ class TagAlias < TagRelationship
[negated ? x[1..-1] : x, negated]
end
aliased = to_aliased_with_originals(tags.map { |t| t[0] })
aliased.merge!(overrides) if overrides
tags.map { |t| "#{t[1] ? '-' : ''}#{aliased[t[0]]}" }.join(" ")
end
lines.uniq.join("\n")
end
def process_undo!(update_topic: true)
unless valid?
raise errors.full_messages.join("; ")
end
CurrentUser.scoped(approver) do
update(status: "pending")
update_posts_locked_tags_undo
update_blacklists_undo
update_posts_undo
forum_updater.update(retirement_message, "UNDONE") if update_topic
rename_wiki_and_artist_undo
end
tag_rel_undos.update_all(applied: true)
end
def update_posts_locked_tags_undo
Post.without_timeout do
Post.where_ilike(:locked_tags, "*#{consequent_name}*").find_each(batch_size: 50) do |post|
fixed_tags = TagAlias.to_aliased_query(post.locked_tags, overrides: {consequent_name => antecedent_name})
CurrentUser.scoped(creator, creator_ip_addr) do
post.update_column(:locked_tags, fixed_tags)
end
end
end
end
def update_blacklists_undo
User.without_timeout do
User.where_ilike(:blacklisted_tags, "*#{consequent_name}*").find_each(batch_size: 50) do |user|
fixed_blacklist = TagAlias.to_aliased_query(user.blacklisted_tags, overrides: {consequent_name => antecedent_name})
user.update_column(:blacklisted_tags, fixed_blacklist)
end
end
end
def update_posts_undo
Post.without_timeout do
tag_rel_undos.where(applied: false).each do |tu|
Post.where(id: tu.undo_data).find_each do |post|
post.do_not_version_changes = true
post.tag_string_diff = "-#{consequent_name} #{antecedent_name}"
post.save
end
end
# TODO: Race condition with indexing jobs here.
antecedent_tag.fix_post_count if antecedent_tag
consequent_tag.fix_post_count if consequent_tag
end
end
def rename_wiki_and_artist_undo
consequent_wiki = WikiPage.titled(consequent_name).first
if consequent_wiki.present?
if WikiPage.titled(antecedent_name).blank?
CurrentUser.scoped(creator, creator_ip_addr) do
consequent_wiki.update(title: antecedent_name, skip_secondary_validations: true)
end
else
forum_updater.update(conflict_message)
end
end
if consequent_tag.category == Tag.categories.artist
if consequent_tag.artist.present? && antecedent_tag.artist.blank?
CurrentUser.scoped(creator, creator_ip_addr) do
consequent_tag.artist.update!(name: antecedent_name)
end
end
end
end
def process!(update_topic: true)
unless valid?
raise errors.full_messages.join("; ")
@ -82,14 +165,13 @@ class TagAlias < TagRelationship
CurrentUser.scoped(approver) do
update(status: "processing")
move_aliases_and_implications
move_saved_searches
ensure_category_consistency
update_posts_locked_tags
update_blacklists
update_posts
forum_updater.update(approval_message(approver), "APPROVED") if update_topic
rename_wiki_and_artist
update(status: "active", post_count: consequent_tag.post_count)
update(status: 'active', post_count: consequent_tag.post_count)
end
rescue Exception => e
Rails.logger.error("[TA] #{e.message}\n#{e.backtrace}")
@ -116,17 +198,6 @@ class TagAlias < TagRelationship
end
end
def move_saved_searches
escaped = Regexp.escape(antecedent_name)
if SavedSearch.enabled?
SavedSearch.where("query like ?", "%#{antecedent_name}%").find_each do |ss|
ss.query = ss.query.sub(/(?:^| )#{escaped}(?:$| )/, " #{consequent_name} ").strip.gsub(/ /, " ")
ss.save
end
end
end
def move_aliases_and_implications
aliases = TagAlias.where(["consequent_name = ?", antecedent_name])
aliases.each do |ta|
@ -182,6 +253,18 @@ class TagAlias < TagRelationship
end
end
def create_undo_information
post_ids = []
Post.transaction do
Post.without_timeout do
Post.sql_raw_tag_match(antecedent_name).find_each do |post|
post_ids << post.id
end
tag_rel_undos.create!(undo_data: post_ids)
end
end
end
def update_posts
Post.without_timeout do
Post.sql_raw_tag_match(antecedent_name).find_each do |post|

View File

@ -1,6 +1,8 @@
class TagImplication < TagRelationship
extend Memoist
has_many :tag_rel_undos, as: :tag_rel
array_attribute :descendant_names
before_save :update_descendant_names
@ -150,6 +152,19 @@ class TagImplication < TagRelationship
end
end
def create_undo_information
Post.without_timeout do
Post.sql_raw_tag_match(antecedent_name).find_in_batches do |posts|
post_info = Hash.new
posts.each do |p|
post_info[p.id] = p.tag_string
end
tag_rel_undos.create!(undo_data: post_info)
end
end
end
def update_posts
Post.without_timeout do
Post.sql_raw_tag_match(antecedent_name).find_each do |post|
@ -165,6 +180,7 @@ class TagImplication < TagRelationship
def approve!(approver: CurrentUser.user, update_topic: true)
update(status: "queued", approver_id: approver.id)
create_undo_information
TagImplicationJob.perform_later(id, update_topic)
end

View File

@ -0,0 +1,3 @@
class TagRelUndo < ApplicationRecord
belongs_to :tag_rel, polymorphic: true
end

View File

@ -0,0 +1,10 @@
class CreateTagRelationshipUndos < ActiveRecord::Migration[6.0]
def change
create_table :tag_rel_undos do |t|
t.references :tag_rel, polymorphic: true
t.json :undo_data
t.boolean :applied, default: false
t.timestamps
end
end
end

View File

@ -2185,6 +2185,40 @@ CREATE SEQUENCE public.tag_implications_id_seq
ALTER SEQUENCE public.tag_implications_id_seq OWNED BY public.tag_implications.id;
--
-- Name: tag_rel_undos; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.tag_rel_undos (
id bigint NOT NULL,
tag_rel_type character varying,
tag_rel_id bigint,
undo_data json,
applied boolean DEFAULT false,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: tag_rel_undos_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.tag_rel_undos_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: tag_rel_undos_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.tag_rel_undos_id_seq OWNED BY public.tag_rel_undos.id;
--
-- Name: tag_subscriptions; Type: TABLE; Schema: public; Owner: -
--
@ -3162,6 +3196,13 @@ ALTER TABLE ONLY public.tag_aliases ALTER COLUMN id SET DEFAULT nextval('public.
ALTER TABLE ONLY public.tag_implications ALTER COLUMN id SET DEFAULT nextval('public.tag_implications_id_seq'::regclass);
--
-- Name: tag_rel_undos id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.tag_rel_undos ALTER COLUMN id SET DEFAULT nextval('public.tag_rel_undos_id_seq'::regclass);
--
-- Name: tag_subscriptions id; Type: DEFAULT; Schema: public; Owner: -
--
@ -3708,6 +3749,14 @@ ALTER TABLE ONLY public.tag_implications
ADD CONSTRAINT tag_implications_pkey PRIMARY KEY (id);
--
-- Name: tag_rel_undos tag_rel_undos_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.tag_rel_undos
ADD CONSTRAINT tag_rel_undos_pkey PRIMARY KEY (id);
--
-- Name: tag_subscriptions tag_subscriptions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -4744,6 +4793,13 @@ CREATE INDEX index_tag_implications_on_consequent_name ON public.tag_implication
CREATE INDEX index_tag_implications_on_forum_post_id ON public.tag_implications USING btree (forum_post_id);
--
-- Name: index_tag_rel_undos_on_tag_rel_type_and_tag_rel_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_tag_rel_undos_on_tag_rel_type_and_tag_rel_id ON public.tag_rel_undos USING btree (tag_rel_type, tag_rel_id);
--
-- Name: index_tag_subscriptions_on_creator_id; Type: INDEX; Schema: public; Owner: -
--
@ -5268,6 +5324,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190905111159'),
('20190916204908'),
('20190919213915'),
('20190924233432');
('20190924233432'),
('20191003070653');