mirror of
https://github.com/discourse/discourse.git
synced 2024-12-24 06:23:45 +08:00
55a8184231
Add flag reason filter and improve handling of deleted content in review queue This commit enhances the review queue with several key improvements: 1. Adds a new "Reason" filter to allow filtering flags by their score type 2. Improves UI for deleted content by: - Adding visual indication for deleted posts (red background) - Properly handling deleted content visibility for staff (category mods can not see deleted content) 3. Refactors reviewable score type handling for better code organization 4. Adds tests for trashed topics/posts visibility This change will help moderators more efficiently manage the review queue by being able to focus on specific types of flags and better identify deleted content.
125 lines
3.7 KiB
Ruby
125 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ReviewableScore < ActiveRecord::Base
|
|
belongs_to :reviewable
|
|
belongs_to :user
|
|
belongs_to :reviewed_by, class_name: "User"
|
|
belongs_to :meta_topic, class_name: "Topic"
|
|
|
|
enum :status, { pending: 0, agreed: 1, disagreed: 2, ignored: 3 }
|
|
|
|
# To keep things simple the types correspond to `PostActionType` for backwards
|
|
# compatibility, but we can add extra reasons for scores.
|
|
def self.types
|
|
@types ||= PostActionType.flag_types.merge(PostActionType.score_types)
|
|
end
|
|
|
|
def self.type_title(type)
|
|
I18n.t("post_action_types.#{type}.title", default: nil) ||
|
|
I18n.t("reviewable_score_types.#{type}.title", default: nil) ||
|
|
PostActionType.names[types[type]]
|
|
end
|
|
|
|
# When extending post action flags, we need to call this method in order to
|
|
# get the latests flags.
|
|
def self.reload_types
|
|
@types = nil
|
|
types
|
|
end
|
|
|
|
def self.add_new_types(type_names)
|
|
next_id = types.values.max + 1
|
|
|
|
type_names.each_with_index { |name, idx| @types[name] = next_id + idx }
|
|
end
|
|
|
|
def self.score_transitions
|
|
{ approved: statuses[:agreed], rejected: statuses[:disagreed], ignored: statuses[:ignored] }
|
|
end
|
|
|
|
def score_type
|
|
Reviewable::Collection::Item.new(reviewable_score_type)
|
|
end
|
|
|
|
def took_action?
|
|
take_action_bonus > 0
|
|
end
|
|
|
|
def self.calculate_score(user, type_bonus, take_action_bonus)
|
|
score = user_flag_score(user) + type_bonus + take_action_bonus
|
|
score > 0 ? score : 0
|
|
end
|
|
|
|
# A user's flag score is:
|
|
# 1.0 + trust_level + user_accuracy_bonus
|
|
# (trust_level is 5 for staff)
|
|
def self.user_flag_score(user)
|
|
1.0 + (user.staff? ? 5.0 : user.trust_level.to_f) + user_accuracy_bonus(user)
|
|
end
|
|
|
|
# A user's accuracy bonus is:
|
|
# if 5 or less flags => 0.0
|
|
# if > 5 flags => (agreed flags / total flags) * 5.0
|
|
def self.user_accuracy_bonus(user)
|
|
user_stat = user&.user_stat
|
|
return 0.0 if user_stat.blank? || user.bot?
|
|
|
|
calc_user_accuracy_bonus(user_stat.flags_agreed, user_stat.flags_disagreed)
|
|
end
|
|
|
|
def self.calc_user_accuracy_bonus(agreed, disagreed)
|
|
agreed ||= 0
|
|
disagreed ||= 0
|
|
|
|
total = (agreed + disagreed).to_f
|
|
return 0.0 if total <= 5
|
|
accuracy_axis = 0.7
|
|
|
|
percent_correct = agreed / total
|
|
positive_accuracy = percent_correct >= accuracy_axis
|
|
|
|
bottom = positive_accuracy ? accuracy_axis : 0.0
|
|
top = positive_accuracy ? 1.0 : accuracy_axis
|
|
|
|
absolute_distance = positive_accuracy ? percent_correct - bottom : top - percent_correct
|
|
|
|
axis_distance_multiplier = 1.0 / (top - bottom)
|
|
positivity_multiplier = positive_accuracy ? 1.0 : -1.0
|
|
|
|
(
|
|
absolute_distance * axis_distance_multiplier * positivity_multiplier *
|
|
(Math.log(total, 4) * 5.0)
|
|
).round(2)
|
|
end
|
|
|
|
def reviewable_conversation
|
|
return if meta_topic.blank?
|
|
Reviewable::Conversation.new(meta_topic)
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: reviewable_scores
|
|
#
|
|
# id :bigint not null, primary key
|
|
# reviewable_id :integer not null
|
|
# user_id :integer not null
|
|
# reviewable_score_type :integer not null
|
|
# status :integer not null
|
|
# score :float default(0.0), not null
|
|
# take_action_bonus :float default(0.0), not null
|
|
# reviewed_by_id :integer
|
|
# reviewed_at :datetime
|
|
# meta_topic_id :integer
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# reason :string
|
|
# user_accuracy_bonus :float default(0.0), not null
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_reviewable_scores_on_reviewable_id (reviewable_id)
|
|
# index_reviewable_scores_on_user_id (user_id)
|
|
#
|