2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
class ReviewableFlaggedPost < Reviewable
|
2022-10-27 06:13:21 +08:00
|
|
|
scope :pending_and_default_visible, -> { pending.default_visible }
|
2019-01-04 01:03:01 +08:00
|
|
|
|
2019-08-01 23:23:23 +08:00
|
|
|
# Penalties are handled by the modal after the action is performed
|
|
|
|
def self.action_aliases
|
|
|
|
{
|
|
|
|
agree_and_keep_hidden: :agree_and_keep,
|
|
|
|
agree_and_silence: :agree_and_keep,
|
|
|
|
agree_and_suspend: :agree_and_keep,
|
2024-05-24 02:21:42 +08:00
|
|
|
agree_and_edit: :agree_and_keep,
|
2019-08-01 23:23:23 +08:00
|
|
|
disagree_and_restore: :disagree,
|
2023-03-02 23:40:53 +08:00
|
|
|
ignore_and_do_nothing: :ignore,
|
2019-08-01 23:23:23 +08:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
def self.counts_for(posts)
|
|
|
|
result = {}
|
|
|
|
|
2021-12-09 01:12:24 +08:00
|
|
|
counts = DB.query(<<~SQL, pending: statuses[:pending])
|
2019-01-04 01:03:01 +08:00
|
|
|
SELECT r.target_id AS post_id,
|
|
|
|
rs.reviewable_score_type,
|
|
|
|
count(*) as total
|
|
|
|
FROM reviewables AS r
|
|
|
|
INNER JOIN reviewable_scores AS rs ON rs.reviewable_id = r.id
|
|
|
|
WHERE r.type = 'ReviewableFlaggedPost'
|
|
|
|
AND r.status = :pending
|
|
|
|
GROUP BY r.target_id, rs.reviewable_score_type
|
|
|
|
SQL
|
|
|
|
|
|
|
|
counts.each do |c|
|
|
|
|
result[c.post_id] ||= {}
|
|
|
|
result[c.post_id][c.reviewable_score_type] = c.total
|
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def post
|
|
|
|
@post ||= (target || Post.with_deleted.find_by(id: target_id))
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_actions(actions, guardian, args)
|
|
|
|
return unless pending?
|
|
|
|
return if post.blank?
|
|
|
|
|
2023-08-25 10:53:56 +08:00
|
|
|
agree_bundle =
|
2019-01-04 01:03:01 +08:00
|
|
|
actions.add_bundle("#{id}-agree", icon: "thumbs-up", label: "reviewables.actions.agree.title")
|
|
|
|
|
2019-06-26 23:35:59 +08:00
|
|
|
if !post.user_deleted? && !post.hidden?
|
2023-08-25 10:53:56 +08:00
|
|
|
build_action(actions, :agree_and_hide, icon: "far-eye-slash", bundle: agree_bundle)
|
2019-06-26 23:35:59 +08:00
|
|
|
end
|
|
|
|
|
2019-08-01 23:23:23 +08:00
|
|
|
if post.hidden?
|
2023-08-25 10:53:56 +08:00
|
|
|
build_action(actions, :agree_and_keep_hidden, icon: "thumbs-up", bundle: agree_bundle)
|
2019-08-01 23:23:23 +08:00
|
|
|
else
|
2023-08-25 10:53:56 +08:00
|
|
|
build_action(actions, :agree_and_keep, icon: "thumbs-up", bundle: agree_bundle)
|
2024-05-24 02:21:42 +08:00
|
|
|
build_action(
|
|
|
|
actions,
|
|
|
|
:agree_and_edit,
|
2024-09-13 23:50:52 +08:00
|
|
|
icon: "pencil",
|
2024-05-24 02:21:42 +08:00
|
|
|
bundle: agree_bundle,
|
|
|
|
client_action: "edit",
|
|
|
|
)
|
2019-08-01 23:23:23 +08:00
|
|
|
end
|
|
|
|
|
2023-03-02 23:40:53 +08:00
|
|
|
if guardian.can_delete_post_or_topic?(post)
|
2024-09-13 23:50:52 +08:00
|
|
|
build_action(actions, :delete_and_agree, icon: "trash-can", bundle: agree_bundle)
|
2023-03-02 23:40:53 +08:00
|
|
|
|
|
|
|
if post.reply_count > 0
|
|
|
|
build_action(
|
|
|
|
actions,
|
|
|
|
:delete_and_agree_replies,
|
2024-09-13 23:50:52 +08:00
|
|
|
icon: "trash-can",
|
2023-08-25 10:53:56 +08:00
|
|
|
bundle: agree_bundle,
|
2023-03-02 23:40:53 +08:00
|
|
|
confirm: true,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-11-27 17:23:57 +08:00
|
|
|
if (potential_spam? || potentially_illegal?) && guardian.can_delete_user?(target_created_by)
|
|
|
|
delete_user_actions(actions, agree_bundle)
|
|
|
|
end
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
if guardian.can_suspend?(target_created_by)
|
|
|
|
build_action(
|
|
|
|
actions,
|
|
|
|
:agree_and_suspend,
|
|
|
|
icon: "ban",
|
2023-08-25 10:53:56 +08:00
|
|
|
bundle: agree_bundle,
|
2019-01-04 01:03:01 +08:00
|
|
|
client_action: "suspend",
|
|
|
|
)
|
|
|
|
build_action(
|
|
|
|
actions,
|
|
|
|
:agree_and_silence,
|
|
|
|
icon: "microphone-slash",
|
2023-08-25 10:53:56 +08:00
|
|
|
bundle: agree_bundle,
|
2019-01-04 01:03:01 +08:00
|
|
|
client_action: "silence",
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2023-08-25 10:53:56 +08:00
|
|
|
if post.user_deleted?
|
|
|
|
build_action(actions, :agree_and_restore, icon: "far-eye", bundle: agree_bundle)
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
if post.hidden?
|
|
|
|
build_action(actions, :disagree_and_restore, icon: "thumbs-down")
|
|
|
|
else
|
|
|
|
build_action(actions, :disagree, icon: "thumbs-down")
|
|
|
|
end
|
|
|
|
|
2024-11-26 14:18:32 +08:00
|
|
|
post_visible_or_system_user = !post.hidden? || guardian.user.is_system_user?
|
|
|
|
can_delete_post_or_topic = guardian.can_delete_post_or_topic?(post)
|
|
|
|
|
|
|
|
# We must return early in this case otherwise we can end up with a bundle
|
|
|
|
# with no associated actions, which is not valid on the client.
|
|
|
|
return if !can_delete_post_or_topic && !post_visible_or_system_user
|
|
|
|
|
2023-03-02 23:40:53 +08:00
|
|
|
ignore =
|
|
|
|
actions.add_bundle(
|
|
|
|
"#{id}-ignore",
|
|
|
|
icon: "thumbs-up",
|
|
|
|
label: "reviewables.actions.ignore.title",
|
|
|
|
)
|
2021-06-15 23:35:45 +08:00
|
|
|
|
2024-11-26 14:18:32 +08:00
|
|
|
if post_visible_or_system_user
|
2024-09-13 23:50:52 +08:00
|
|
|
build_action(actions, :ignore_and_do_nothing, icon: "up-right-from-square", bundle: ignore)
|
2023-03-02 23:40:53 +08:00
|
|
|
end
|
2024-11-26 14:18:32 +08:00
|
|
|
if can_delete_post_or_topic
|
2024-09-13 23:50:52 +08:00
|
|
|
build_action(actions, :delete_and_ignore, icon: "trash-can", bundle: ignore)
|
2019-04-05 03:51:36 +08:00
|
|
|
if post.reply_count > 0
|
|
|
|
build_action(
|
|
|
|
actions,
|
|
|
|
:delete_and_ignore_replies,
|
2024-09-13 23:50:52 +08:00
|
|
|
icon: "trash-can",
|
2019-04-05 03:51:36 +08:00
|
|
|
confirm: true,
|
2023-03-02 23:40:53 +08:00
|
|
|
bundle: ignore,
|
2019-04-05 03:51:36 +08:00
|
|
|
)
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_ignore(performed_by, args)
|
2023-03-02 23:40:53 +08:00
|
|
|
perform_ignore_and_do_nothing(performed_by, args)
|
|
|
|
end
|
|
|
|
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
def post_action_type_view
|
|
|
|
@post_action_type_view ||= PostActionTypeView.new
|
|
|
|
end
|
|
|
|
|
2023-03-02 23:40:53 +08:00
|
|
|
def perform_ignore_and_do_nothing(performed_by, args)
|
2019-01-04 01:03:01 +08:00
|
|
|
actions =
|
|
|
|
PostAction
|
|
|
|
.active
|
|
|
|
.where(post_id: target_id)
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
.where(post_action_type_id: post_action_type_view.notify_flag_type_ids)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
|
|
|
actions.each do |action|
|
|
|
|
action.deferred_at = Time.zone.now
|
|
|
|
action.deferred_by_id = performed_by.id
|
|
|
|
# so callback is called
|
|
|
|
action.save
|
2019-05-28 05:22:39 +08:00
|
|
|
unless args[:expired]
|
|
|
|
action.add_moderator_post_if_needed(performed_by, :ignored, args[:post_was_deleted])
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
if actions.first.present?
|
2020-03-25 05:57:44 +08:00
|
|
|
unassign_topic performed_by, post
|
2019-01-04 01:03:01 +08:00
|
|
|
DiscourseEvent.trigger(:flag_reviewed, post)
|
|
|
|
DiscourseEvent.trigger(:flag_deferred, actions.first)
|
|
|
|
end
|
|
|
|
|
|
|
|
create_result(:success, :ignored) do |result|
|
|
|
|
result.update_flag_stats = { status: :ignored, user_ids: actions.map(&:user_id) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_agree_and_keep(performed_by, args)
|
|
|
|
agree(performed_by, args)
|
|
|
|
end
|
|
|
|
|
2021-06-15 23:35:45 +08:00
|
|
|
def perform_delete_user(performed_by, args)
|
|
|
|
delete_options = delete_opts
|
|
|
|
|
|
|
|
UserDestroyer.new(performed_by).destroy(post.user, delete_options)
|
|
|
|
|
|
|
|
agree(performed_by, args)
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_delete_user_block(performed_by, args)
|
|
|
|
delete_options = delete_opts
|
|
|
|
|
|
|
|
delete_options.merge!(block_email: true, block_ip: true) if Rails.env.production?
|
|
|
|
|
|
|
|
UserDestroyer.new(performed_by).destroy(post.user, delete_options)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
|
|
|
agree(performed_by, args)
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_agree_and_hide(performed_by, args)
|
|
|
|
agree(performed_by, args) { |pa| post.hide!(pa.post_action_type_id) }
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_agree_and_restore(performed_by, args)
|
|
|
|
agree(performed_by, args) { PostDestroyer.new(performed_by, post).recover }
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_disagree(performed_by, args)
|
|
|
|
# -1 is the automatic system clear
|
|
|
|
action_type_ids =
|
|
|
|
if performed_by.id == Discourse::SYSTEM_USER_ID
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
post_action_type_view.auto_action_flag_types.values
|
2019-01-04 01:03:01 +08:00
|
|
|
else
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
post_action_type_view.notify_flag_type_ids
|
2019-01-04 01:03:01 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
actions =
|
|
|
|
PostAction.active.where(post_id: target_id).where(post_action_type_id: action_type_ids)
|
|
|
|
|
|
|
|
actions.each do |action|
|
|
|
|
action.disagreed_at = Time.zone.now
|
|
|
|
action.disagreed_by_id = performed_by.id
|
|
|
|
# so callback is called
|
|
|
|
action.save
|
|
|
|
action.add_moderator_post_if_needed(performed_by, :disagreed)
|
|
|
|
end
|
|
|
|
|
|
|
|
# reset all cached counters
|
|
|
|
cached = {}
|
|
|
|
action_type_ids.each do |atid|
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
column = "#{post_action_type_view.types[atid]}_count"
|
2019-01-04 01:03:01 +08:00
|
|
|
cached[column] = 0 if ActiveRecord::Base.connection.column_exists?(:posts, column)
|
|
|
|
end
|
|
|
|
|
|
|
|
Post.with_deleted.where(id: target_id).update_all(cached)
|
|
|
|
|
|
|
|
if actions.first.present?
|
2020-03-25 05:57:44 +08:00
|
|
|
unassign_topic performed_by, post
|
2019-01-04 01:03:01 +08:00
|
|
|
DiscourseEvent.trigger(:flag_reviewed, post)
|
|
|
|
DiscourseEvent.trigger(:flag_disagreed, actions.first)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Undo hide/silence if applicable
|
|
|
|
if post&.hidden?
|
2019-08-30 21:27:52 +08:00
|
|
|
notify_poster(performed_by)
|
2019-01-04 01:03:01 +08:00
|
|
|
post.unhide!
|
|
|
|
UserSilencer.unsilence(post.user) if UserSilencer.was_silenced_for?(post)
|
|
|
|
end
|
|
|
|
|
|
|
|
create_result(:success, :rejected) do |result|
|
|
|
|
result.update_flag_stats = { status: :disagreed, user_ids: actions.map(&:user_id) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_delete_and_ignore(performed_by, args)
|
2023-03-02 23:40:53 +08:00
|
|
|
result = perform_ignore_and_do_nothing(performed_by, args)
|
2019-08-30 21:27:52 +08:00
|
|
|
destroyer(performed_by, post).destroy
|
2019-01-04 01:03:01 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2019-04-05 03:51:36 +08:00
|
|
|
def perform_delete_and_ignore_replies(performed_by, args)
|
2023-03-02 23:40:53 +08:00
|
|
|
result = perform_ignore_and_do_nothing(performed_by, args)
|
2019-08-30 21:27:52 +08:00
|
|
|
PostDestroyer.delete_with_replies(performed_by, post, self)
|
2019-04-05 03:51:36 +08:00
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
def perform_delete_and_agree(performed_by, args)
|
|
|
|
result = agree(performed_by, args)
|
2019-08-30 21:27:52 +08:00
|
|
|
destroyer(performed_by, post).destroy
|
2019-01-04 01:03:01 +08:00
|
|
|
result
|
|
|
|
end
|
2019-04-05 03:51:36 +08:00
|
|
|
|
|
|
|
def perform_delete_and_agree_replies(performed_by, args)
|
|
|
|
result = agree(performed_by, args)
|
2020-01-07 00:37:54 +08:00
|
|
|
PostDestroyer.delete_with_replies(performed_by, post, self)
|
2019-04-05 03:51:36 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
protected
|
|
|
|
|
|
|
|
def agree(performed_by, args)
|
|
|
|
actions =
|
|
|
|
PostAction
|
|
|
|
.active
|
|
|
|
.where(post_id: target_id)
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
.where(post_action_type_id: post_action_type_view.notify_flag_types.values)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
|
|
|
trigger_spam = false
|
|
|
|
actions.each do |action|
|
2019-04-25 17:15:13 +08:00
|
|
|
ActiveRecord::Base.transaction do
|
|
|
|
action.agreed_at = Time.zone.now
|
|
|
|
action.agreed_by_id = performed_by.id
|
|
|
|
# so callback is called
|
|
|
|
action.save
|
|
|
|
DB.after_commit do
|
|
|
|
action.add_moderator_post_if_needed(performed_by, :agreed, args[:post_was_deleted])
|
FIX: serialize Flags instead of PostActionType (#28362)
### Why?
Before, all flags were static. Therefore, they were stored in class variables and serialized by SiteSerializer. Recently, we added an option for admins to add their own flags or disable existing flags. Therefore, the class variable had to be dropped because it was unsafe for a multisite environment. However, it started causing performance problems.
### Solution
When a new Flag system is used, instead of using PostActionType, we can serialize Flags and use fragment cache for performance reasons.
At the same time, we are still supporting deprecated `replace_flags` API call. When it is used, we fall back to the old solution and the admin cannot add custom flags. In a couple of months, we will be able to drop that API function and clean that code properly. However, because it may still be used, redis cache was introduced to improve performance.
To test backward compatibility you can add this code to any plugin
```ruby
replace_flags do |flag_settings|
flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
flag_settings.add(1001, :trolling, topic_type: true, notify_type: true, auto_action_type: true)
end
```
2024-08-14 10:13:46 +08:00
|
|
|
trigger_spam = true if action.post_action_type_id == post_action_type_view.types[:spam]
|
2019-04-25 17:15:13 +08:00
|
|
|
end
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
DiscourseEvent.trigger(:confirmed_spam_post, post) if trigger_spam
|
|
|
|
|
|
|
|
if actions.first.present?
|
2020-03-25 05:57:44 +08:00
|
|
|
unassign_topic performed_by, post
|
2019-01-04 01:03:01 +08:00
|
|
|
DiscourseEvent.trigger(:flag_reviewed, post)
|
|
|
|
DiscourseEvent.trigger(:flag_agreed, actions.first)
|
|
|
|
yield(actions.first) if block_given?
|
|
|
|
end
|
|
|
|
|
|
|
|
create_result(:success, :approved) do |result|
|
|
|
|
result.update_flag_stats = { status: :agreed, user_ids: actions.map(&:user_id) }
|
|
|
|
result.recalculate_score = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-18 18:28:59 +08:00
|
|
|
def build_action(
|
|
|
|
actions,
|
|
|
|
id,
|
|
|
|
icon:,
|
|
|
|
button_class: nil,
|
|
|
|
bundle: nil,
|
|
|
|
client_action: nil,
|
|
|
|
confirm: false
|
|
|
|
)
|
2019-01-04 01:03:01 +08:00
|
|
|
actions.add(id, bundle: bundle) do |action|
|
|
|
|
prefix = "reviewables.actions.#{id}"
|
|
|
|
action.icon = icon
|
2019-09-18 18:28:59 +08:00
|
|
|
action.button_class = button_class
|
2019-01-04 01:03:01 +08:00
|
|
|
action.label = "#{prefix}.title"
|
|
|
|
action.description = "#{prefix}.description"
|
|
|
|
action.client_action = client_action
|
|
|
|
action.confirm_message = "#{prefix}.confirm" if confirm
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-03-25 05:57:44 +08:00
|
|
|
def unassign_topic(performed_by, post)
|
|
|
|
topic = post.topic
|
|
|
|
return unless topic && performed_by && SiteSetting.reviewable_claiming != "disabled"
|
|
|
|
ReviewableClaimedTopic.where(topic_id: topic.id).delete_all
|
|
|
|
topic.reviewables.find_each { |reviewable| reviewable.log_history(:unclaimed, performed_by) }
|
|
|
|
|
|
|
|
user_ids = User.staff.pluck(:id)
|
|
|
|
|
2024-09-04 09:38:46 +08:00
|
|
|
if SiteSetting.enable_category_group_moderation? && topic.category
|
|
|
|
user_ids.concat(
|
|
|
|
GroupUser
|
|
|
|
.joins(
|
|
|
|
"INNER JOIN category_moderation_groups ON category_moderation_groups.group_id = group_users.group_id",
|
|
|
|
)
|
|
|
|
.where("category_moderation_groups.category_id": topic.category.id)
|
|
|
|
.distinct
|
|
|
|
.pluck(:user_id),
|
|
|
|
)
|
2020-03-25 05:57:44 +08:00
|
|
|
user_ids.uniq!
|
|
|
|
end
|
|
|
|
|
|
|
|
data = { topic_id: topic.id }
|
|
|
|
|
|
|
|
MessageBus.publish("/reviewable_claimed", data, user_ids: user_ids)
|
|
|
|
end
|
|
|
|
|
2019-08-30 21:27:52 +08:00
|
|
|
private
|
|
|
|
|
2021-06-15 23:35:45 +08:00
|
|
|
def delete_opts
|
|
|
|
{
|
|
|
|
delete_posts: true,
|
|
|
|
prepare_for_destroy: true,
|
|
|
|
block_urls: true,
|
|
|
|
delete_as_spammer: true,
|
|
|
|
context: "review",
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2019-08-30 21:27:52 +08:00
|
|
|
def destroyer(performed_by, post)
|
|
|
|
PostDestroyer.new(performed_by, post, reviewable: self)
|
|
|
|
end
|
|
|
|
|
|
|
|
def notify_poster(performed_by)
|
|
|
|
return unless performed_by.human? && performed_by.staff?
|
|
|
|
|
|
|
|
Jobs.enqueue(
|
|
|
|
:send_system_message,
|
|
|
|
user_id: post.user_id,
|
2022-02-08 04:18:17 +08:00
|
|
|
message_type: "flags_disagreed",
|
2019-08-30 21:27:52 +08:00
|
|
|
message_options: {
|
|
|
|
flagged_post_raw_content: post.raw,
|
|
|
|
url: post.url,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: reviewables
|
|
|
|
#
|
2019-05-03 06:34:12 +08:00
|
|
|
# id :bigint not null, primary key
|
2019-01-04 01:03:01 +08:00
|
|
|
# type :string not null
|
2021-12-09 01:12:24 +08:00
|
|
|
# status :integer default("pending"), not null
|
2019-01-04 01:03:01 +08:00
|
|
|
# created_by_id :integer not null
|
|
|
|
# reviewable_by_moderator :boolean default(FALSE), not null
|
|
|
|
# category_id :integer
|
|
|
|
# topic_id :integer
|
|
|
|
# score :float default(0.0), not null
|
|
|
|
# potential_spam :boolean default(FALSE), not null
|
|
|
|
# target_id :integer
|
|
|
|
# target_type :string
|
|
|
|
# target_created_by_id :integer
|
|
|
|
# payload :json
|
|
|
|
# version :integer default(0), not null
|
|
|
|
# latest_score :datetime
|
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
2021-07-06 06:14:15 +08:00
|
|
|
# force_review :boolean default(FALSE), not null
|
|
|
|
# reject_reason :text
|
2024-11-27 17:23:57 +08:00
|
|
|
# potentially_illegal :boolean default(FALSE)
|
2019-01-04 01:03:01 +08:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
2022-07-28 16:16:33 +08:00
|
|
|
# idx_reviewables_score_desc_created_at_desc (score,created_at)
|
2019-05-03 06:34:12 +08:00
|
|
|
# index_reviewables_on_reviewable_by_group_id (reviewable_by_group_id)
|
2019-04-12 21:55:27 +08:00
|
|
|
# index_reviewables_on_status_and_created_at (status,created_at)
|
|
|
|
# index_reviewables_on_status_and_score (status,score)
|
|
|
|
# index_reviewables_on_status_and_type (status,type)
|
2020-09-01 16:00:36 +08:00
|
|
|
# index_reviewables_on_target_id_where_post_type_eq_post (target_id) WHERE ((target_type)::text = 'Post'::text)
|
2019-04-12 21:55:27 +08:00
|
|
|
# index_reviewables_on_topic_id_and_status_and_created_by_id (topic_id,status,created_by_id)
|
|
|
|
# index_reviewables_on_type_and_target_id (type,target_id) UNIQUE
|
2019-01-04 01:03:01 +08:00
|
|
|
#
|