Add a polymorphic `subject` field that records the subject of the mod action. The subject is the post, user, comment, artist, etc the mod action is for. * The subject for the user ban and unban actions is the user, not the ban itself. * The subject for the user feedback update and deletion actions is the user, not the feedback itself. * The subject for the post undeletion action is the post, not the approval itself. * The subject for the move favorites action is the source post where the favorites were moved from, not the destination post where the favorites were moved to. * The subject for the post permanent delete action is nil, because the post itself is hard deleted. * When a post is permanently deleted, all mod actions related to the post are deleted as well.
95 lines
2.7 KiB
Ruby
95 lines
2.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class PostVote < ApplicationRecord
|
|
attr_accessor :updater
|
|
|
|
belongs_to :post
|
|
belongs_to :user
|
|
has_many :mod_actions, as: :subject, dependent: :destroy
|
|
|
|
validates :score, inclusion: { in: [1, -1], message: "must be 1 or -1" }
|
|
|
|
before_save { post.lock! }
|
|
before_save :update_score_on_delete, if: -> { !new_record? && is_deleted_changed?(from: false, to: true) }
|
|
before_save :update_score_on_undelete, if: -> { !new_record? && is_deleted_changed?(from: true, to: false) }
|
|
before_save :create_mod_action_on_delete_or_undelete
|
|
before_create :update_score_on_create
|
|
before_create :remove_conflicting_votes
|
|
|
|
scope :positive, -> { where("post_votes.score > 0") }
|
|
scope :negative, -> { where("post_votes.score < 0") }
|
|
scope :public_votes, -> { active.positive.where.not(user: User.has_private_favorites) }
|
|
|
|
deletable
|
|
|
|
def self.visible(user)
|
|
if user.is_admin?
|
|
all
|
|
elsif user.is_anonymous?
|
|
public_votes
|
|
else
|
|
active.where(user: user).or(public_votes)
|
|
end
|
|
end
|
|
|
|
def self.search(params, current_user)
|
|
q = search_attributes(params, [:id, :created_at, :updated_at, :score, :is_deleted, :user, :post], current_user: current_user)
|
|
|
|
q.apply_default_order(params)
|
|
end
|
|
|
|
def is_positive?
|
|
score > 0
|
|
end
|
|
|
|
def is_negative?
|
|
score < 0
|
|
end
|
|
|
|
def remove_conflicting_votes
|
|
PostVote.active.where.not(id: id).where(post: post, user: user).each do |vote|
|
|
vote.soft_delete!(updater: updater)
|
|
end
|
|
end
|
|
|
|
def validate_vote_is_unique
|
|
if !is_deleted? && PostVote.active.where.not(id: id).exists?(post: post, user: user)
|
|
errors.add(:user, "have already voted for this post")
|
|
end
|
|
end
|
|
|
|
def update_score_on_create
|
|
if is_positive?
|
|
Post.update_counters(post_id, { score: score, up_score: score })
|
|
else
|
|
Post.update_counters(post_id, { score: score, down_score: score })
|
|
end
|
|
end
|
|
|
|
def update_score_on_delete
|
|
if is_positive?
|
|
Post.update_counters(post_id, { score: -score, up_score: -score })
|
|
else
|
|
Post.update_counters(post_id, { score: -score, down_score: -score })
|
|
end
|
|
end
|
|
|
|
def update_score_on_undelete
|
|
update_score_on_create
|
|
end
|
|
|
|
def create_mod_action_on_delete_or_undelete
|
|
return if new_record? || updater.nil? || updater == user
|
|
|
|
if is_deleted_changed?(from: false, to: true)
|
|
ModAction.log("deleted post vote ##{id} on post ##{post_id}", :post_vote_delete, subject: self, user: updater)
|
|
elsif is_deleted_changed?(from: true, to: false)
|
|
ModAction.log("undeleted post vote ##{id} on post ##{post_id}", :post_vote_undelete, subject: self, user: updater)
|
|
end
|
|
end
|
|
|
|
def self.available_includes
|
|
[:user, :post]
|
|
end
|
|
end
|