Add a Routes module that gives models access to route helpers outside of views, and use it to replace various hardcoded routes.
144 lines
4.8 KiB
Ruby
144 lines
4.8 KiB
Ruby
class Comment < ApplicationRecord
|
|
validate :validate_creator_is_not_limited, :on => :create
|
|
validates_presence_of :body, :message => "has no content"
|
|
belongs_to :post
|
|
belongs_to :creator, class_name: "User"
|
|
belongs_to_updater
|
|
has_many :moderation_reports, as: :model
|
|
has_many :votes, :class_name => "CommentVote", :dependent => :destroy
|
|
|
|
before_create :autoreport_spam
|
|
after_create :update_last_commented_at_on_create
|
|
after_update(:if => ->(rec) {(!rec.is_deleted? || !rec.saved_change_to_is_deleted?) && CurrentUser.id != rec.creator_id}) do |rec|
|
|
ModAction.log("comment ##{rec.id} updated by #{CurrentUser.name}", :comment_update)
|
|
end
|
|
after_save :update_last_commented_at_on_destroy, :if => ->(rec) {rec.is_deleted? && rec.saved_change_to_is_deleted?}
|
|
after_save(:if => ->(rec) {rec.is_deleted? && rec.saved_change_to_is_deleted? && CurrentUser.id != rec.creator_id}) do |rec|
|
|
ModAction.log("comment ##{rec.id} deleted by #{CurrentUser.name}", :comment_delete)
|
|
end
|
|
|
|
deletable
|
|
mentionable(
|
|
:message_field => :body,
|
|
:title => ->(user_name) {"#{creator.name} mentioned you in a comment on post ##{post_id}"},
|
|
:body => ->(user_name) {"@#{creator.name} mentioned you in a \"comment\":#{Routes.post_path(post, anchor: "comment-#{id}")} on post ##{post_id}:\n\n[quote]\n#{DText.extract_mention(body, "@" + user_name)}\n[/quote]\n"}
|
|
)
|
|
|
|
module SearchMethods
|
|
def search(params)
|
|
q = search_attributes(params, :id, :created_at, :updated_at, :is_deleted, :is_sticky, :do_not_bump_post, :body, :score, :post, :creator, :updater)
|
|
q = q.text_attribute_matches(:body, params[:body_matches], index_column: :body_index)
|
|
|
|
case params[:order]
|
|
when "post_id", "post_id_desc"
|
|
q = q.order("comments.post_id DESC, comments.id DESC")
|
|
when "score", "score_desc"
|
|
q = q.order("comments.score DESC, comments.id DESC")
|
|
when "updated_at", "updated_at_desc"
|
|
q = q.order("comments.updated_at DESC")
|
|
else
|
|
q = q.apply_default_order(params)
|
|
end
|
|
|
|
q
|
|
end
|
|
end
|
|
|
|
module VoteMethods
|
|
def vote!(val, voter = CurrentUser.user)
|
|
numerical_score = (val == "up") ? 1 : -1
|
|
vote = votes.create!(user: voter, score: numerical_score)
|
|
|
|
if vote.is_positive?
|
|
update_column(:score, score + 1)
|
|
elsif vote.is_negative?
|
|
update_column(:score, score - 1)
|
|
end
|
|
|
|
return vote
|
|
end
|
|
|
|
def unvote!
|
|
vote = votes.where("user_id = ?", CurrentUser.user.id).first
|
|
|
|
if vote
|
|
if vote.is_positive?
|
|
update_column(:score, score - 1)
|
|
else
|
|
update_column(:score, score + 1)
|
|
end
|
|
|
|
vote.destroy
|
|
else
|
|
raise CommentVote::Error.new("You have not voted for this comment")
|
|
end
|
|
end
|
|
end
|
|
|
|
extend SearchMethods
|
|
include VoteMethods
|
|
|
|
def validate_creator_is_not_limited
|
|
if creator.is_comment_limited? && !do_not_bump_post?
|
|
errors.add(:base, "You can only post #{Danbooru.config.member_comment_limit} comments per hour")
|
|
end
|
|
end
|
|
|
|
def autoreport_spam
|
|
if SpamDetector.new(self).spam?
|
|
moderation_reports << ModerationReport.new(creator: User.system, reason: "Spam.")
|
|
end
|
|
end
|
|
|
|
def update_last_commented_at_on_create
|
|
Post.where(:id => post_id).update_all(:last_commented_at => created_at)
|
|
if Comment.where("post_id = ?", post_id).count <= Danbooru.config.comment_threshold && !do_not_bump_post?
|
|
Post.where(:id => post_id).update_all(:last_comment_bumped_at => created_at)
|
|
end
|
|
end
|
|
|
|
def update_last_commented_at_on_destroy
|
|
other_comments = Comment.where("post_id = ? and id <> ?", post_id, id).order("id DESC")
|
|
if other_comments.count == 0
|
|
Post.where(:id => post_id).update_all(:last_commented_at => nil)
|
|
else
|
|
Post.where(:id => post_id).update_all(:last_commented_at => other_comments.first.created_at)
|
|
end
|
|
|
|
other_comments = other_comments.where("do_not_bump_post = FALSE")
|
|
if other_comments.count == 0
|
|
Post.where(:id => post_id).update_all(:last_comment_bumped_at => nil)
|
|
else
|
|
Post.where(:id => post_id).update_all(:last_comment_bumped_at => other_comments.first.created_at)
|
|
end
|
|
end
|
|
|
|
def voted_by?(user)
|
|
return false if user.is_anonymous?
|
|
user.id.in?(votes.map(&:user_id))
|
|
end
|
|
|
|
def visibility(user)
|
|
return :invisible if is_deleted? && !user.is_moderator?
|
|
return :hidden if is_deleted? && user.is_moderator?
|
|
return :hidden if score < user.comment_threshold && !is_sticky?
|
|
return :visible
|
|
end
|
|
|
|
def self.hidden(user)
|
|
select { |comment| comment.visibility(user) == :hidden }
|
|
end
|
|
|
|
def self.unhidden(user)
|
|
select { |comment| comment.visibility(user) == :visible }
|
|
end
|
|
|
|
def quoted_response
|
|
DText.quote(body, creator.name)
|
|
end
|
|
|
|
def self.available_includes
|
|
[:post, :creator, :updater]
|
|
end
|
|
end
|