mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 19:37:55 +08:00
169 lines
5.6 KiB
Ruby
169 lines
5.6 KiB
Ruby
|
require_dependency 'rate_limiter'
|
||
|
require_dependency 'system_message'
|
||
|
|
||
|
class PostAction < ActiveRecord::Base
|
||
|
include RateLimiter::OnCreateRecord
|
||
|
|
||
|
attr_accessible :deleted_at, :post_action_type_id, :post_id, :user_id, :post, :user, :post_action_type, :message
|
||
|
|
||
|
belongs_to :post
|
||
|
belongs_to :user
|
||
|
belongs_to :post_action_type
|
||
|
|
||
|
rate_limit :post_action_rate_limiter
|
||
|
|
||
|
def self.update_flagged_posts_count
|
||
|
val = exec_sql('select count(*) from posts where deleted_at is null and id in (select post_id from post_actions where post_action_type_id in (?) and deleted_at is null)', PostActionType.FlagTypes).values[0][0].to_i
|
||
|
$redis.set('posts_flagged_count', val)
|
||
|
|
||
|
admins = User.exec_sql("select id from users where admin = 't'").map{|r| r["id"].to_i}
|
||
|
MessageBus.publish('/flagged_counts', {total: val}, {user_ids: admins})
|
||
|
end
|
||
|
|
||
|
def self.flagged_posts_count
|
||
|
$redis.get('posts_flagged_count').to_i
|
||
|
end
|
||
|
|
||
|
def self.counts_for(collection, user)
|
||
|
|
||
|
return {} if collection.blank?
|
||
|
|
||
|
collection_ids = collection.map {|p| p.id}
|
||
|
|
||
|
user_id = user.present? ? user.id : 0
|
||
|
|
||
|
result = PostAction.where(post_id: collection_ids, user_id: user_id, deleted_at: nil)
|
||
|
user_actions = {}
|
||
|
result.each do |r|
|
||
|
user_actions[r.post_id] ||= {}
|
||
|
user_actions[r.post_id][r.post_action_type_id] = r
|
||
|
end
|
||
|
|
||
|
user_actions
|
||
|
end
|
||
|
|
||
|
def self.clear_flags!(post, moderator_id)
|
||
|
|
||
|
# -1 is the automatic system cleary
|
||
|
actions = moderator_id == -1 ? PostActionType.AutoActionFlagTypes : PostActionType.FlagTypes
|
||
|
|
||
|
PostAction.exec_sql('update post_actions set deleted_at = ?, deleted_by = ?
|
||
|
where post_id = ? and deleted_at is null and post_action_type_id in (?)',
|
||
|
DateTime.now, moderator_id, post.id, actions
|
||
|
)
|
||
|
|
||
|
r = PostActionType.Types.invert
|
||
|
f = actions.map{|t| ["#{r[t]}_count", 0]}
|
||
|
|
||
|
Post.update_all(Hash[*f.flatten], id: post.id)
|
||
|
|
||
|
update_flagged_posts_count
|
||
|
end
|
||
|
|
||
|
def self.act(user, post, post_action_type_id, message = nil)
|
||
|
begin
|
||
|
create(post_id: post.id, user_id: user.id, post_action_type_id: post_action_type_id, message: message)
|
||
|
rescue ActiveRecord::RecordNotUnique
|
||
|
# can happen despite being .create
|
||
|
# since already bookmarked
|
||
|
true
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def self.remove_act(user, post, post_action_type_id)
|
||
|
if action = self.where(post_id: post.id, user_id: user.id, post_action_type_id: post_action_type_id, deleted_at: nil).first
|
||
|
|
||
|
transaction do
|
||
|
d = DateTime.now
|
||
|
count = PostAction.update_all({deleted_at: d},{id: action.id, deleted_at: nil})
|
||
|
|
||
|
if(count == 1)
|
||
|
action.deleted_at = DateTime.now
|
||
|
action.run_callbacks(:save)
|
||
|
action.run_callbacks(:destroy)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def is_bookmark?
|
||
|
post_action_type_id == PostActionType.Types[:bookmark]
|
||
|
end
|
||
|
|
||
|
def is_like?
|
||
|
post_action_type_id == PostActionType.Types[:like]
|
||
|
end
|
||
|
|
||
|
def is_flag?
|
||
|
PostActionType.FlagTypes.include?(post_action_type_id)
|
||
|
end
|
||
|
|
||
|
# A custom rate limiter for this model
|
||
|
def post_action_rate_limiter
|
||
|
return nil unless is_flag? or is_bookmark? or is_like?
|
||
|
|
||
|
return @rate_limiter if @rate_limiter.present?
|
||
|
|
||
|
%w(like flag bookmark).each do |type|
|
||
|
if send("is_#{type}?")
|
||
|
@rate_limiter = RateLimiter.new(user, "create_#{type}:#{Date.today.to_s}", SiteSetting.send("max_#{type}s_per_day"), 1.day.to_i)
|
||
|
return @rate_limiter
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after_save do
|
||
|
|
||
|
# Update denormalized counts
|
||
|
post_action_type = PostActionType.Types.invert[post_action_type_id]
|
||
|
column = "#{post_action_type.to_s}_count"
|
||
|
delta = deleted_at.nil? ? 1 : -1
|
||
|
|
||
|
# Voting also changes the sort_order
|
||
|
if post_action_type == :vote
|
||
|
Post.update_all ["vote_count = vote_count + :delta, sort_order = :max - (vote_count + :delta)", delta: delta, max: Topic::MAX_SORT_ORDER], ["id = ?", post_id]
|
||
|
else
|
||
|
Post.update_all ["#{column} = #{column} + ?", delta], ["id = ?", post_id]
|
||
|
end
|
||
|
|
||
|
exec_sql "UPDATE topics SET #{column} = #{column} + ? WHERE id = (select p.topic_id from posts p where p.id = ?)", delta, post_id
|
||
|
|
||
|
if PostActionType.FlagTypes.include?(post_action_type_id)
|
||
|
PostAction.update_flagged_posts_count
|
||
|
end
|
||
|
|
||
|
if SiteSetting.flags_required_to_hide_post > 0
|
||
|
# automatic hiding of posts
|
||
|
info = exec_sql("select case when deleted_at is null then 'new' else 'old' end, count(*) from post_actions
|
||
|
where post_id = ? and
|
||
|
post_action_type_id in (?)
|
||
|
group by case when deleted_at is null then 'new' else 'old' end
|
||
|
", self.post_id, PostActionType.AutoActionFlagTypes).values
|
||
|
|
||
|
old_flags = new_flags = 0
|
||
|
info.each do |r,v|
|
||
|
old_flags = v.to_i if r == 'old'
|
||
|
new_flags = v.to_i if r == 'new'
|
||
|
end
|
||
|
|
||
|
|
||
|
if new_flags >= SiteSetting.flags_required_to_hide_post
|
||
|
exec_sql("update posts set hidden = ?, hidden_reason_id = coalesce(hidden_reason_id, ?) where id = ?",
|
||
|
true, old_flags > 0 ? Post::HiddenReason::FLAG_THRESHOLD_REACHED_AGAIN : Post::HiddenReason::FLAG_THRESHOLD_REACHED, self.post_id)
|
||
|
|
||
|
exec_sql("update topics set visible = 'f'
|
||
|
where id = ? and not exists (select 1 from posts where hidden = 'f' and topic_id = ?)", self.post.topic_id, self.post.topic_id)
|
||
|
|
||
|
# inform user
|
||
|
if self.post.user
|
||
|
SystemMessage.create(self.post.user, :post_hidden,
|
||
|
url: self.post.url,
|
||
|
edit_delay: SiteSetting.cooldown_minutes_after_hiding_posts)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|