aliases: refactor tag moving code.

* Factor out the code for moving tags from tag aliases to a separate
  TagMover class.

* When aliasing two tags that have conflicting wikis, merge the old wiki
  into the new one instead of failing with an error. Merge the other names
  fields, replace the old wiki body with a message linking to the new
  wiki, and mark the old wiki as deleted.

* When aliasing two tags that have conflicting artist entries, merge the
  old artist into the new one instead of silently ignore the conflict.
  Merge the group name, other names, and urls fields, and mark the old
  artist as deleted.

* When two tags have conflicting wikis or artist entries, but the old
  wiki or artist entry is deleted, then just ignore the old wiki or
  artist and don't try to merge it.

* Fix it so that when saved searches are rewritten, we rewrite negated
  searches too.
This commit is contained in:
evazion
2020-08-26 13:54:27 -05:00
parent 44402299ec
commit f0299a8945
5 changed files with 244 additions and 84 deletions

View File

@@ -57,12 +57,12 @@ module Searchable
# https://www.postgresql.org/docs/current/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP
# "(?e)" means force use of ERE syntax; see sections 9.7.3.1 and 9.7.3.4.
def where_regex(attr, value)
where("#{qualified_column_for(attr)} ~ ?", "(?e)" + value)
def where_regex(attr, value, flags: "e")
where("#{qualified_column_for(attr)} ~ ?", "(?#{flags})" + value)
end
def where_not_regex(attr, value)
where.not("#{qualified_column_for(attr)} ~ ?", "(?e)" + value)
def where_not_regex(attr, value, flags: "e")
where.not("#{qualified_column_for(attr)} ~ ?", "(?#{flags})" + value)
end
def where_inet_matches(attr, value)

108
app/logical/tag_mover.rb Normal file
View File

@@ -0,0 +1,108 @@
class TagMover
attr_reader :old_tag, :new_tag, :user
def initialize(old_name, new_name, user: User.system)
@old_tag = Tag.find_or_create_by_name(old_name)
@new_tag = Tag.find_or_create_by_name(new_name)
@user = user
end
def move!
CurrentUser.scoped(user) do
move_tag_category!
move_artist!
move_wiki!
move_saved_searches!
move_posts!
end
end
def move_tag_category!
if old_tag.general? && !new_tag.general?
old_tag.update!(category: new_tag.category)
elsif new_tag.general? && !old_tag.general?
new_tag.update!(category: old_tag.category)
end
end
def move_artist!
return unless old_tag.artist? && old_artist.present? && !old_artist.is_deleted?
if new_artist.nil?
old_artist.update!(name: new_tag.name)
else
merge_artists!
end
end
def move_wiki!
return unless old_wiki.present? && !old_wiki.is_deleted?
if new_wiki.nil?
old_wiki.update!(title: new_tag.name)
else
merge_wikis!
end
end
def move_posts!
Post.raw_tag_match(old_tag.name).find_each do |post|
post.lock!
post.remove_tag(old_tag.name)
post.add_tag(new_tag.name)
post.save!
end
end
def move_saved_searches!
SavedSearch.rewrite_queries!(old_tag.name, new_tag.name)
end
def merge_artists!
old_artist.lock!
new_artist.lock!
new_artist.other_names += old_artist.other_names
new_artist.other_names += [old_artist.name]
new_artist.group_name = old_artist.group_name unless new_artist.group_name.present?
new_artist.url_string += "\n" + old_artist.url_string
new_artist.is_deleted = false
new_artist.save!
old_artist.other_names = [new_artist.name]
old_artist.group_name = ""
old_artist.url_string = ""
old_artist.is_deleted = true
old_artist.save!
end
def merge_wikis!
old_wiki.lock!
new_wiki.lock!
new_wiki.other_names += old_wiki.other_names
new_wiki.is_deleted = false
new_wiki.save!
old_wiki.body = "This tag has been moved to [[#{new_wiki.title}]]."
old_wiki.other_names = []
old_wiki.is_deleted = true
old_wiki.save!
end
def old_wiki
old_tag.wiki_page
end
def new_wiki
new_tag.wiki_page
end
def old_artist
old_tag.artist
end
def new_artist
new_tag.artist
end
end