diff --git a/app/models/tag_alias.rb b/app/models/tag_alias.rb index 9f01f5dcf..3a2a728e4 100644 --- a/app/models/tag_alias.rb +++ b/app/models/tag_alias.rb @@ -1,17 +1,8 @@ -class TagAlias < ApplicationRecord - attr_accessor :skip_secondary_validations - +class TagAlias < TagRelationship before_save :ensure_tags_exist after_save :clear_all_cache after_destroy :clear_all_cache after_save :create_mod_action - before_validation :initialize_creator, :on => :create - before_validation :normalize_names - validates_format_of :status, :with => /\A(active|deleted|pending|processing|queued|error: .*)\Z/ - validates_presence_of :creator_id, :antecedent_name, :consequent_name - validates :creator, presence: { message: "must exist" }, if: lambda { creator_id.present? } - validates :approver, presence: { message: "must exist" }, if: lambda { approver_id.present? } - validates :forum_topic, presence: { message: "must exist" }, if: lambda { forum_topic_id.present? } validates_uniqueness_of :antecedent_name validate :absence_of_transitive_relation validate :antecedent_and_consequent_are_different @@ -24,40 +15,6 @@ class TagAlias < ApplicationRecord attr_accessible :antecedent_name, :consequent_name, :forum_topic_id, :skip_secondary_validations attr_accessible :status, :approver_id, :as => [:admin] - module SearchMethods - def name_matches(name) - where("(antecedent_name like ? escape E'\\\\' or consequent_name like ? escape E'\\\\')", name.mb_chars.downcase.to_escaped_for_sql_like, name.downcase.to_escaped_for_sql_like) - end - - def active - where("status IN (?)", ["active", "processing"]) - end - - def search(params) - q = where("true") - return q if params.blank? - - if params[:name_matches].present? - q = q.name_matches(params[:name_matches]) - end - - if params[:antecedent_name].present? - q = q.where("antecedent_name = ?", params[:antecedent_name]) - end - - if params[:id].present? - q = q.where("id in (?)", params[:id].split(",").map(&:to_i)) - end - - case params[:order] - when "created_at" - q = q.order("created_at desc") - end - - q - end - end - module CacheMethods extend ActiveSupport::Concern @@ -124,7 +81,6 @@ class TagAlias < ApplicationRecord end end - extend SearchMethods include CacheMethods include ApprovalMethods include ForumMethods @@ -172,32 +128,6 @@ class TagAlias < ApplicationRecord end end - def is_pending? - status == "pending" - end - - def is_active? - status == "active" - end - - def normalize_names - self.antecedent_name = antecedent_name.mb_chars.downcase.tr(" ", "_") - self.consequent_name = consequent_name.downcase.tr(" ", "_") - end - - def initialize_creator - self.creator_id ||= CurrentUser.user.id - self.creator_ip_addr ||= CurrentUser.ip_addr - end - - def antecedent_tag - Tag.find_or_create_by_name(antecedent_name) - end - - def consequent_tag - Tag.find_or_create_by_name(consequent_name) - end - def absence_of_transitive_relation # We don't want a -> b && b -> c chains if the b -> c alias was created first. # If the a -> b alias was created first, the new one will be allowed and the old one will be moved automatically instead. @@ -310,17 +240,6 @@ class TagAlias < ApplicationRecord end end - def deletable_by?(user) - return true if user.is_admin? - return true if is_pending? && user.is_builder? - return true if is_pending? && user.id == creator_id - return false - end - - def editable_by?(user) - deletable_by?(user) - end - def reject! update({ :status => "deleted" }, :as => CurrentUser.role) clear_all_cache diff --git a/app/models/tag_implication.rb b/app/models/tag_implication.rb index 2e886b132..00e997dac 100644 --- a/app/models/tag_implication.rb +++ b/app/models/tag_implication.rb @@ -1,21 +1,8 @@ -class TagImplication < ApplicationRecord - attr_accessor :skip_secondary_validations - +class TagImplication < TagRelationship before_save :update_descendant_names after_save :update_descendant_names_for_parents after_destroy :update_descendant_names_for_parents after_save :create_mod_action - belongs_to :creator, :class_name => "User" - belongs_to :approver, :class_name => "User" - belongs_to :forum_topic - belongs_to :forum_post - before_validation :initialize_creator, :on => :create - before_validation :normalize_names - validates_format_of :status, :with => /\A(active|deleted|pending|processing|queued|error: .*)\Z/ - validates_presence_of :creator_id, :antecedent_name, :consequent_name - validates :creator, presence: { message: "must exist" }, if: lambda { creator_id.present? } - validates :approver, presence: { message: "must exist" }, if: lambda { approver_id.present? } - validates :forum_topic, presence: { message: "must exist" }, if: lambda { forum_topic_id.present? } validates_uniqueness_of :antecedent_name, :scope => :consequent_name validate :absence_of_circular_relation validate :absence_of_transitive_relation @@ -23,8 +10,6 @@ class TagImplication < ApplicationRecord validate :consequent_is_not_aliased validate :antecedent_and_consequent_are_different validate :wiki_pages_present, :on => :create - attr_accessible :antecedent_name, :consequent_name, :forum_topic_id, :skip_secondary_validations - attr_accessible :status, :approver_id, :as => [:admin] module DescendantMethods extend ActiveSupport::Concern @@ -91,44 +76,6 @@ class TagImplication < ApplicationRecord end end - module SearchMethods - def name_matches(name) - where("(antecedent_name like ? escape E'\\\\' or consequent_name like ? escape E'\\\\')", name.downcase.to_escaped_for_sql_like, name.downcase.to_escaped_for_sql_like) - end - - def active - where(status: %w[active processing queued]) - end - - def search(params) - q = where("true") - return q if params.blank? - - if params[:id].present? - q = q.where("id in (?)", params[:id].split(",").map(&:to_i)) - end - - if params[:name_matches].present? - q = q.name_matches(params[:name_matches]) - end - - if params[:antecedent_name].present? - q = q.where("antecedent_name = ?", params[:antecedent_name]) - end - - if params[:consequent_name].present? - q = q.where("consequent_name = ?", params[:consequent_name]) - end - - case params[:order] - when "created_at" - q = q.order("created_at desc") - end - - q - end - end - module ValidationMethods def absence_of_circular_relation # We don't want a -> b && b -> a chains @@ -285,50 +232,12 @@ class TagImplication < ApplicationRecord include DescendantMethods include ParentMethods - extend SearchMethods include ValidationMethods include ApprovalMethods - def initialize_creator - self.creator_id = CurrentUser.user.id - self.creator_ip_addr = CurrentUser.ip_addr - end - - def normalize_names - self.antecedent_name = antecedent_name.downcase.tr(" ", "_") - self.consequent_name = consequent_name.downcase.tr(" ", "_") - end - - def is_pending? - status == "pending" - end - - def is_active? - status == "active" - end - - def antecedent_tag - Tag.find_or_create_by_name(antecedent_name) - end - - def consequent_tag - Tag.find_or_create_by_name(consequent_name) - end - def reload(options = {}) super clear_parents_cache clear_descendants_cache end - - def deletable_by?(user) - return true if user.is_admin? - return true if is_pending? && user.is_builder? - return true if is_pending? && user.id == creator_id - return false - end - - def editable_by?(user) - deletable_by?(user) - end end diff --git a/app/models/tag_relationship.rb b/app/models/tag_relationship.rb new file mode 100644 index 000000000..c581c75a3 --- /dev/null +++ b/app/models/tag_relationship.rb @@ -0,0 +1,91 @@ +class TagRelationship < ApplicationRecord + self.abstract_class = true + + attr_accessor :skip_secondary_validations + attr_accessible :antecedent_name, :consequent_name, :forum_topic_id, :skip_secondary_validations + attr_accessible :status, :approver_id, :as => [:admin] + + belongs_to :creator, :class_name => "User" + belongs_to :approver, :class_name => "User" + belongs_to :forum_post + belongs_to :forum_topic + has_one :antecedent_tag, :class_name => "Tag", :foreign_key => "name", :primary_key => "antecedent_name" + has_one :consequent_tag, :class_name => "Tag", :foreign_key => "name", :primary_key => "consequent_name" + + before_validation :initialize_creator, :on => :create + before_validation :normalize_names + validates_format_of :status, :with => /\A(active|deleted|pending|processing|queued|error: .*)\Z/ + validates_presence_of :creator_id, :antecedent_name, :consequent_name + validates :creator, presence: { message: "must exist" }, if: lambda { creator_id.present? } + validates :approver, presence: { message: "must exist" }, if: lambda { approver_id.present? } + validates :forum_topic, presence: { message: "must exist" }, if: lambda { forum_topic_id.present? } + + def initialize_creator + self.creator_id = CurrentUser.user.id + self.creator_ip_addr = CurrentUser.ip_addr + end + + def normalize_names + self.antecedent_name = antecedent_name.mb_chars.downcase.tr(" ", "_") + self.consequent_name = consequent_name.mb_chars.downcase.tr(" ", "_") + end + + def is_pending? + status == "pending" + end + + def is_active? + status == "active" + end + + def deletable_by?(user) + return true if user.is_admin? + return true if is_pending? && user.is_builder? + return true if is_pending? && user.id == creator_id + return false + end + + def editable_by?(user) + deletable_by?(user) + end + + module SearchMethods + def name_matches(name) + where("(antecedent_name like ? escape E'\\\\' or consequent_name like ? escape E'\\\\')", name.mb_chars.downcase.to_escaped_for_sql_like, name.mb_chars.downcase.to_escaped_for_sql_like) + end + + def active + where(status: %w[active processing queued]) + end + + def search(params) + q = where("true") + return q if params.blank? + + if params[:id].present? + q = q.where("id in (?)", params[:id].split(",").map(&:to_i)) + end + + if params[:name_matches].present? + q = q.name_matches(params[:name_matches]) + end + + if params[:antecedent_name].present? + q = q.where("antecedent_name = ?", params[:antecedent_name]) + end + + if params[:consequent_name].present? + q = q.where("consequent_name = ?", params[:consequent_name]) + end + + case params[:order] + when "created_at" + q = q.order("created_at desc") + end + + q + end + end + + extend SearchMethods +end