discourse/app/models/post_action.rb
Sam 5280b3a01b more group progress, UI getting there, controller mostly done
changed it so notify moderators goes to the moderators group
allow admins to grant self moderation and revoke self moderation
2013-05-09 17:37:34 +10:00

221 lines
8 KiB
Ruby

require_dependency 'rate_limiter'
require_dependency 'system_message'
require_dependency 'trashable'
class PostAction < ActiveRecord::Base
class AlreadyActed < StandardError; end
include RateLimiter::OnCreateRecord
include Trashable
attr_accessible :post_action_type_id, :post_id, :user_id, :post, :user, :post_action_type, :message, :related_post_id
belongs_to :post
belongs_to :user
belongs_to :post_action_type
rate_limit :post_action_rate_limiter
validate :message_quality
def self.update_flagged_posts_count
posts_flagged_count = PostAction.joins(post: :topic)
.where('post_actions.post_action_type_id' => PostActionType.notify_flag_types.values,
'posts.deleted_at' => nil,
'topics.deleted_at' => nil)
.count('DISTINCT posts.id')
$redis.set('posts_flagged_count', posts_flagged_count)
user_ids = User.staff.select(:id).map {|u| u.id}
MessageBus.publish('/flagged_counts', { total: posts_flagged_count }, { user_ids: user_ids })
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)
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.count_per_day_for_type(sinceDaysAgo = 30, post_action_type)
unscoped.where(post_action_type_id: post_action_type).where('created_at > ?', sinceDaysAgo.days.ago).group('date(created_at)').order('date(created_at)').count
end
def self.clear_flags!(post, moderator_id, action_type_id = nil)
# -1 is the automatic system cleary
actions = if action_type_id
[action_type_id]
else
moderator_id == -1 ? PostActionType.auto_action_flag_types.values : PostActionType.flag_types.values
end
PostAction.update_all({ deleted_at: Time.zone.now, deleted_by: moderator_id }, { post_id: post.id, post_action_type_id: actions })
f = actions.map{|t| ["#{PostActionType.types[t]}_count", 0]}
Post.with_deleted.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
title, target_usernames, target_group_names, subtype, body = nil
if message
[:notify_moderators, :notify_user].each do |k|
if post_action_type_id == PostActionType.types[k]
if k == :notify_moderators
target_group_names = target_moderators
else
target_usernames = post.user.username
end
title = I18n.t("post_action_types.#{k}.email_title",
title: post.topic.title)
body = I18n.t("post_action_types.#{k}.email_body",
message: message,
link: "#{Discourse.base_url}#{post.url}")
subtype = k == :notify_moderators ? TopicSubtype.notify_moderators : TopicSubtype.notify_user
end
end
end
related_post_id = nil
if target_usernames.present? || target_group_names.present?
related_post_id = PostCreator.new(user,
target_usernames: target_usernames,
target_group_names: target_group_names,
archetype: Archetype.private_message,
subtype: subtype,
title: title,
raw: body
).create.id
end
create( post_id: post.id,
user_id: user.id,
post_action_type_id: post_action_type_id,
message: message,
related_post_id: related_post_id )
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 = where(post_id: post.id, user_id: user.id, post_action_type_id: post_action_type_id).first
action.trash!
action.run_callbacks(:save)
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.flag_types.values.include?(post_action_type_id)
end
def is_private_message?
post_action_type_id == PostActionType.types[:notify_user] ||
post_action_type_id == PostActionType.types[:notify_moderators]
end
# A custom rate limiter for this model
def post_action_rate_limiter
return unless is_flag? || is_bookmark? || 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
def message_quality
return if message.blank?
sentinel = TextSentinel.title_sentinel(message)
errors.add(:message, I18n.t(:is_invalid)) unless sentinel.valid?
end
before_create do
post_action_type_ids = is_flag? ? PostActionType.flag_types.values : post_action_type_id
raise AlreadyActed if PostAction.where(user_id: user_id,
post_id: post_id,
post_action_type_id: post_action_type_ids,
deleted_at: nil)
.exists?
end
after_save do
# Update denormalized counts
post_action_type = PostActionType.types[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
Topic.update_all ["#{column} = #{column} + ?", delta], id: post.topic_id
if PostActionType.notify_flag_types.values.include?(post_action_type_id)
PostAction.update_flagged_posts_count
end
if PostActionType.auto_action_flag_types.include?(post_action_type) && SiteSetting.flags_required_to_hide_post > 0
# automatic hiding of posts
flag_counts = exec_sql("SELECT SUM(CASE WHEN deleted_at IS NULL THEN 1 ELSE 0 END) AS new_flags,
SUM(CASE WHEN deleted_at IS NOT NULL THEN 1 ELSE 0 END) AS old_flags
FROM post_actions
WHERE post_id = ? AND post_action_type_id IN (?)", post.id, PostActionType.auto_action_flag_types.values).first
old_flags, new_flags = flag_counts['old_flags'].to_i, flag_counts['new_flags'].to_i
if new_flags >= SiteSetting.flags_required_to_hide_post
reason = old_flags > 0 ? Post.hidden_reasons[:flag_threshold_reached_again] : Post.hidden_reasons[:flag_threshold_reached]
Post.update_all(["hidden = true, hidden_reason_id = COALESCE(hidden_reason_id, ?)", reason], id: post_id)
Topic.update_all({ visible: false },
["id = :topic_id AND NOT EXISTS(SELECT 1 FROM POSTS WHERE topic_id = :topic_id AND NOT hidden)", topic_id: post.topic_id])
# inform user
if post.user
SystemMessage.create(post.user, :post_hidden,
url: post.url,
edit_delay: SiteSetting.cooldown_minutes_after_hiding_posts)
end
end
end
end
protected
def self.target_moderators
Group[:moderators].name
end
end