DEV: move post flags into database (#27125)

This is preparation for a feature that will allow admins to define their custom flags. Current behaviour should stay untouched.
This commit is contained in:
Krzysztof Kotlarek 2024-05-23 12:19:07 +10:00 committed by GitHub
parent 312a930ac8
commit cfbbfd177c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 380 additions and 104 deletions

View File

@ -14,7 +14,9 @@ export default Component.extend({
@discourseComputed("flag.name_key") @discourseComputed("flag.name_key")
customPlaceholder(nameKey) { customPlaceholder(nameKey) {
return I18n.t("flagging.custom_placeholder_" + nameKey); return I18n.t("flagging.custom_placeholder_" + nameKey, {
defaultValue: I18n.t("flagging.custom_placeholder_notify_moderators"),
});
}, },
@discourseComputed("flag.name", "flag.name_key", "username") @discourseComputed("flag.name", "flag.name_key", "username")
@ -22,7 +24,9 @@ export default Component.extend({
if (["notify_user", "notify_moderators"].includes(nameKey)) { if (["notify_user", "notify_moderators"].includes(nameKey)) {
return name.replace(/{{username}}|%{username}/, username); return name.replace(/{{username}}|%{username}/, username);
} else { } else {
return I18n.t("flagging.formatted_name." + nameKey); return I18n.t("flagging.formatted_name." + nameKey, {
defaultValue: name,
});
} }
}, },

View File

@ -254,7 +254,11 @@ export default function transformPost(
postId: post.id, postId: post.id,
action, action,
canUndo: a.can_undo, canUndo: a.can_undo,
description: I18n.t(`post.actions.by_you.${action}`), description: I18n.t(`post.actions.by_you.${action}`, {
defaultValue: I18n.t(`post.actions.by_you.custom`, {
custom: a.actionType.name,
}),
}),
}; };
}); });
} }

65
app/models/flag.rb Normal file
View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
class Flag < ActiveRecord::Base
MAX_SYSTEM_FLAG_ID = 1000
scope :enabled, -> { where(enabled: true) }
scope :system, -> { where("id < 1000") }
before_save :set_position
before_save :set_name_key
after_save :reset_flag_settings!
after_destroy :reset_flag_settings!
default_scope { order(:position) }
def used?
PostAction.exists?(post_action_type_id: self.id) ||
ReviewableScore.exists?(reviewable_score_type: self.id)
end
def self.reset_flag_settings!
# Flags are memoized for better performance. After the update, we need to reload them in all processes.
PostActionType.reload_types
DiscourseEvent.trigger(:reload_post_action_types)
end
def system?
self.id < MAX_SYSTEM_FLAG_ID
end
def applies_to?(type)
self.applies_to.include?(type)
end
private
def reset_flag_settings!
self.class.reset_flag_settings!
end
def set_position
self.position = Flag.maximum(:position).to_i + 1 if !self.position
end
def set_name_key
self.name_key = self.name.squeeze(" ").gsub(" ", "_").gsub(/[^\w]/, "").downcase
end
end
# == Schema Information
#
# Table name: flags
#
# id :bigint not null, primary key
# name :string
# name_key :string
# description :text
# notify_type :boolean default(FALSE), not null
# auto_action_type :boolean default(FALSE), not null
# custom_type :boolean default(FALSE), not null
# applies_to :string not null, is an Array
# position :integer not null
# enabled :boolean default(TRUE), not null
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -11,39 +11,47 @@ class PostActionType < ActiveRecord::Base
ApplicationSerializer.expire_cache_fragment!(/\Apost_action_flag_types_/) ApplicationSerializer.expire_cache_fragment!(/\Apost_action_flag_types_/)
end end
DiscourseEvent.on(:reload_post_action_types) { self.reload_types }
class << self class << self
attr_reader :flag_settings attr_reader :flag_settings
def replace_flag_settings(settings) def initialize_flag_settings
if settings @flag_settings = FlagSettings.new
@flag_settings = settings
else
initialize_flag_settings
end
@types = nil
end end
def ordered def replace_flag_settings(settings)
order("position asc") Discourse.deprecate("Flags should not be replaced. Insert custom flags as database records.")
@flag_settings = settings || FlagSettings.new
@all_flags = nil
end end
def types def types
unless @types return Enum.new(like: 2).merge!(flag_settings.flag_types) if overridden_by_plugin?
# NOTE: Previously bookmark was type 1 but that has been superseded Enum.new(like: 2).merge(flag_types)
# by the separate Bookmark model and functionality end
@types = Enum.new(like: 2)
@types.merge!(flag_settings.flag_types)
end
@types def reload_types
@all_flags = nil
@flag_settings = FlagSettings.new
ReviewableScore.reload_types
end
def overridden_by_plugin?
flag_settings.flag_types.present?
end
def all_flags
@all_flags ||= Flag.all
end end
def auto_action_flag_types def auto_action_flag_types
flag_settings.auto_action_types return flag_settings.auto_action_types if overridden_by_plugin?
flag_enum(all_flags.select(&:auto_action_type))
end end
def public_types def public_types
@public_types ||= types.except(*flag_types.keys << :notify_user) types.except(*flag_types.keys << :notify_user)
end end
def public_type_ids def public_type_ids
@ -51,11 +59,13 @@ class PostActionType < ActiveRecord::Base
end end
def flag_types_without_custom def flag_types_without_custom
flag_settings.without_custom_types return flag_settings.without_custom_types if overridden_by_plugin?
flag_enum(all_flags.reject(&:custom_type))
end end
def flag_types def flag_types
flag_settings.flag_types return flag_settings.flag_types if overridden_by_plugin?
flag_enum(all_flags)
end end
# flags resulting in mod notifications # flags resulting in mod notifications
@ -64,15 +74,25 @@ class PostActionType < ActiveRecord::Base
end end
def notify_flag_types def notify_flag_types
flag_settings.notify_types return flag_settings.notify_types if overridden_by_plugin?
flag_enum(all_flags.select(&:notify_type))
end end
def topic_flag_types def topic_flag_types
flag_settings.topic_flag_types if overridden_by_plugin?
flag_settings.topic_flag_types
else
flag_enum(all_flags.select { |flag| flag.applies_to?("Topic") })
end
end end
def custom_types def custom_types
flag_settings.custom_types return flag_settings.custom_types if overridden_by_plugin?
flag_enum(all_flags.select(&:custom_type))
end
def names
all_flags.pluck(:id, :name).to_h
end end
def is_flag?(sym) def is_flag?(sym)
@ -81,28 +101,8 @@ class PostActionType < ActiveRecord::Base
private private
def initialize_flag_settings def flag_enum(scope)
@flag_settings = FlagSettings.new Enum.new(scope.map { |flag| [flag.name_key.to_sym, flag.id] }.to_h)
@flag_settings.add(3, :off_topic, notify_type: true, auto_action_type: true)
@flag_settings.add(
4,
:inappropriate,
topic_type: true,
notify_type: true,
auto_action_type: true,
)
@flag_settings.add(8, :spam, topic_type: true, notify_type: true, auto_action_type: true)
@flag_settings.add(6, :notify_user, topic_type: false, notify_type: false, custom_type: true)
@flag_settings.add(
7,
:notify_moderators,
topic_type: true,
notify_type: true,
custom_type: true,
)
@flag_settings.add(10, :illegal, topic_type: true, notify_type: true, custom_type: true)
# When adding a new ID here, check that it doesn't clash with any added in
# `ReviewableScore.types`. You can thank me later.
end end
end end

View File

@ -14,25 +14,25 @@ class PostActionTypeSerializer < ApplicationSerializer
end end
def name def name
i18n("title") i18n("title", default: object.class.names[object.id])
end end
def description def description
i18n("description", tos_url: tos_url, base_path: Discourse.base_path) i18n("description", vars: { tos_url:, base_path: Discourse.base_path })
end end
def short_description def short_description
i18n("short_description", tos_url: tos_url, base_path: Discourse.base_path) i18n("short_description", vars: { tos_url: tos_url, base_path: Discourse.base_path })
end end
def name_key def name_key
PostActionType.types[object.id] PostActionType.types[object.id].to_s
end end
protected protected
def i18n(field, vars = nil) def i18n(field, default: nil, vars: nil)
key = "post_action_types.#{name_key}.#{field}" key = "post_action_types.#{name_key}.#{field}"
vars ? I18n.t(key, vars) : I18n.t(key) vars ? I18n.t(key, vars, default: default) : I18n.t(key, default: default)
end end
end end

View File

@ -9,8 +9,9 @@ class ReviewableScoreTypeSerializer < ApplicationSerializer
# Allow us to share post action type translations for backwards compatibility # Allow us to share post action type translations for backwards compatibility
def title def title
I18n.t("post_action_types.#{ReviewableScore.types[id]}.title", default: nil) || I18n.t("post_action_types.#{type}.title", default: nil) ||
I18n.t("reviewable_score_types.#{ReviewableScore.types[id]}.title") I18n.t("reviewable_score_types.#{type}.title", default: nil) ||
PostActionType.flag_settings.names[id]
end end
def reviewable_priority def reviewable_priority

View File

@ -350,13 +350,6 @@ class SiteSerializer < ApplicationSerializer
private private
def ordered_flags(flags) def ordered_flags(flags)
notify_moderators_type = PostActionType.flag_types[:notify_moderators] flags.map { |id| PostActionType.new(id: id) }
types = flags
if notify_moderators_flag = types.index(notify_moderators_type)
types.insert(types.length, types.delete_at(notify_moderators_flag))
end
types.map { |id| PostActionType.new(id: id) }
end end
end end

View File

@ -3,8 +3,8 @@
class TopicFlagTypeSerializer < PostActionTypeSerializer class TopicFlagTypeSerializer < PostActionTypeSerializer
protected protected
def i18n(field, vars = nil) def i18n(field, default: nil, vars: nil)
key = "topic_flag_types.#{name_key}.#{field}" key = "topic_flag_types.#{name_key}.#{field}"
vars ? I18n.t(key, vars) : I18n.t(key) vars ? I18n.t(key, vars, default: default) : I18n.t(key, default: default)
end end
end end

View File

@ -3771,6 +3771,7 @@ en:
illegal: "You flagged this as illegal" illegal: "You flagged this as illegal"
notify_moderators: "You flagged this for moderation" notify_moderators: "You flagged this for moderation"
notify_user: "You sent a message to this user" notify_user: "You sent a message to this user"
custom: "You flagged this topic as %{custom}"
delete: delete:
confirm: confirm:

56
db/fixtures/003_flags.rb Normal file
View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
Flag.seed do |s|
s.id = 3
s.name = "off_topic"
s.position = 2
s.notify_type = true
s.auto_action_type = true
s.custom_type = false
s.applies_to = %w[Post Chat::Message]
end
Flag.seed do |s|
s.id = 4
s.name = "inappropriate"
s.position = 3
s.notify_type = true
s.auto_action_type = true
s.custom_type = false
s.applies_to = %w[Post Topic Chat::Message]
end
Flag.seed do |s|
s.id = 8
s.name = "spam"
s.position = 4
s.notify_type = true
s.auto_action_type = true
s.custom_type = false
s.applies_to = %w[Post Topic Chat::Message]
end
Flag.seed do |s|
s.id = 6
s.name = "notify_user"
s.position = 0
s.notify_type = false
s.auto_action_type = false
s.custom_type = true
s.applies_to = %w[Post Chat::Message]
end
Flag.seed do |s|
s.id = 7
s.name = "notify_moderators"
s.position = 1
s.notify_type = true
s.auto_action_type = false
s.custom_type = true
s.applies_to = %w[Post Topic Chat::Message]
end
Flag.seed do |s|
s.id = 10
s.name = "illegal"
s.position = 5
s.notify_type = true
s.auto_action_type = false
s.custom_type = true
s.applies_to = %w[Post Topic Chat::Message]
end

View File

@ -18,7 +18,7 @@ class AddFlagStatsToUser < ActiveRecord::Migration[5.2]
SUM(CASE WHEN pa.deferred_at IS NOT NULL THEN 1 ELSE 0 END) as flags_ignored SUM(CASE WHEN pa.deferred_at IS NOT NULL THEN 1 ELSE 0 END) as flags_ignored
FROM post_actions AS pa FROM post_actions AS pa
INNER JOIN users AS u ON u.id = pa.user_id INNER JOIN users AS u ON u.id = pa.user_id
WHERE pa.post_action_type_id IN (#{PostActionType.notify_flag_types.values.join(", ")}) WHERE pa.post_action_type_id IN (3, 4, 8, 7, 10)
AND pa.user_id > 0 AND pa.user_id > 0
GROUP BY u.id GROUP BY u.id
) AS x ) AS x

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class CreateFlags < ActiveRecord::Migration[7.0]
def change
create_table :flags do |t|
t.string :name, unique: true
t.string :name_key, unique: true
t.text :description
t.boolean :notify_type, default: false, null: false
t.boolean :auto_action_type, default: false, null: false
t.boolean :custom_type, default: false, null: false
t.string :applies_to, array: true, null: false
t.integer :position, null: false
t.boolean :enabled, default: true, null: false
t.timestamps
end
# IDs below 1000 are reserved for system flags
DB.exec("SELECT setval('flags_id_seq', #{Flag::MAX_SYSTEM_FLAG_ID + 1}, FALSE);")
end
end

View File

@ -7,6 +7,7 @@ class FlagSettings
:topic_flag_types, :topic_flag_types,
:auto_action_types, :auto_action_types,
:custom_types, :custom_types,
:names,
) )
def initialize def initialize
@ -16,18 +17,28 @@ class FlagSettings
@auto_action_types = Enum.new @auto_action_types = Enum.new
@custom_types = Enum.new @custom_types = Enum.new
@without_custom_types = Enum.new @without_custom_types = Enum.new
@names = Enum.new
end end
def add(id, name, topic_type: nil, notify_type: nil, auto_action_type: nil, custom_type: nil) def add(
@all_flag_types[name] = id id,
@topic_flag_types[name] = id if !!topic_type name_key,
@notify_types[name] = id if !!notify_type topic_type: nil,
@auto_action_types[name] = id if !!auto_action_type notify_type: nil,
auto_action_type: nil,
custom_type: nil,
name: nil
)
@all_flag_types[name_key] = id
@topic_flag_types[name_key] = id if !!topic_type
@notify_types[name_key] = id if !!notify_type
@auto_action_types[name_key] = id if !!auto_action_type
@names[id] = name if name
if !!custom_type if !!custom_type
@custom_types[name] = id @custom_types[name_key] = id
else else
@without_custom_types[name] = id @without_custom_types[name_key] = id
end end
end end

View File

@ -4,6 +4,7 @@ require "guardian/bookmark_guardian"
require "guardian/category_guardian" require "guardian/category_guardian"
require "guardian/ensure_magic" require "guardian/ensure_magic"
require "guardian/group_guardian" require "guardian/group_guardian"
require "guardian/flag_guardian"
require "guardian/post_guardian" require "guardian/post_guardian"
require "guardian/post_revision_guardian" require "guardian/post_revision_guardian"
require "guardian/sidebar_guardian" require "guardian/sidebar_guardian"
@ -16,6 +17,7 @@ class Guardian
include BookmarkGuardian include BookmarkGuardian
include CategoryGuardian include CategoryGuardian
include EnsureMagic include EnsureMagic
include FlagGuardian
include GroupGuardian include GroupGuardian
include PostGuardian include PostGuardian
include PostRevisionGuardian include PostRevisionGuardian

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
module FlagGuardian
def can_edit_flag?(flag)
@user.admin? && !flag.system? && !flag.used?
end
end

View File

@ -197,6 +197,9 @@ class Plugin::Instance
# Applies to all sites in a multisite environment. Ignores plugin.enabled? # Applies to all sites in a multisite environment. Ignores plugin.enabled?
def replace_flags(settings: ::FlagSettings.new, score_type_names: []) def replace_flags(settings: ::FlagSettings.new, score_type_names: [])
Discourse.deprecate(
"replace flags should not be used as flags were moved to the database. Instead, a flag record should be added to the database. Alternatively, soon, the admin will be able to do this in the admin panel.",
)
next_flag_id = ReviewableScore.types.values.max + 1 next_flag_id = ReviewableScore.types.values.max + 1
yield(settings, next_flag_id) if block_given? yield(settings, next_flag_id) if block_given?

View File

@ -35,7 +35,10 @@ export default class ChatMessageFlag {
return flags.map((flag) => { return flags.map((flag) => {
flag.set( flag.set(
"description", "description",
I18n.t(`chat.flags.${flag.name_key}`, { basePath: getURL("") }) I18n.t(`chat.flags.${flag.name_key}`, {
basePath: getURL(""),
defaultValue: "",
})
); );
return flag; return flag;
}); });

View File

@ -22,7 +22,7 @@ RSpec.describe Chat::FlagMessage do
let(:guardian) { Guardian.new(current_user) } let(:guardian) { Guardian.new(current_user) }
let(:channel_id) { channel_1.id } let(:channel_id) { channel_1.id }
let(:message_id) { message_1.id } let(:message_id) { message_1.id }
let(:flag_type_id) { ReviewableScore.types.values.first } let(:flag_type_id) { ReviewableScore.types[:off_topic] }
let(:message) { nil } let(:message) { nil }
let(:is_warning) { nil } let(:is_warning) { nil }
let(:take_action) { nil } let(:take_action) { nil }

View File

@ -1032,7 +1032,7 @@ RSpec.describe DiscourseNarrativeBot::NewUserNarrative do
let(:another_post) { Fabricate(:post, user: discobot_user, topic: topic) } let(:another_post) { Fabricate(:post, user: discobot_user, topic: topic) }
let(:flag) do let(:flag) do
Fabricate( Fabricate(
:flag, :flag_post_action,
post: post, post: post,
user: user, user: user,
post_action_type_id: PostActionType.types[:inappropriate], post_action_type_id: PostActionType.types[:inappropriate],
@ -1040,7 +1040,7 @@ RSpec.describe DiscourseNarrativeBot::NewUserNarrative do
end end
let(:other_flag) do let(:other_flag) do
Fabricate( Fabricate(
:flag, :flag_post_action,
post: another_post, post: another_post,
user: user, user: user,
post_action_type_id: PostActionType.types[:spam], post_action_type_id: PostActionType.types[:spam],
@ -1166,7 +1166,7 @@ RSpec.describe DiscourseNarrativeBot::NewUserNarrative do
describe "when post contain the right answer" do describe "when post contain the right answer" do
let(:post) { Fabricate(:post, user: discobot_user, topic: topic) } let(:post) { Fabricate(:post, user: discobot_user, topic: topic) }
let(:flag) { Fabricate(:flag, post: post, user: user) } let(:flag) { Fabricate(:flag_post_action, post: post, user: user) }
before do before do
narrative.set_data(user, state: :tutorial_flag, topic_id: topic.id) narrative.set_data(user, state: :tutorial_flag, topic_id: topic.id)

View File

@ -1,7 +1,3 @@
# frozen_string_literal: true # frozen_string_literal: true
Fabricator(:flag, from: :post_action) do Fabricator(:flag) { name "offtopic", applies_to { %w[Post Chat::Message] } }
user
post
post_action_type_id PostActionType.types[:spam]
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
Fabricator(:flag_post_action, from: :post_action) do
user
post
post_action_type_id PostActionType.types[:spam]
end

View File

@ -360,7 +360,7 @@ RSpec.describe ComposerMessagesFinder do
end end
it "shows a message when the replier has already flagged the post" do it "shows a message when the replier has already flagged the post" do
Fabricate(:flag, post: self_flagged_post, user: user) Fabricate(:flag_post_action, post: self_flagged_post, user: user)
finder = finder =
ComposerMessagesFinder.new( ComposerMessagesFinder.new(
user, user,
@ -372,13 +372,13 @@ RSpec.describe ComposerMessagesFinder do
end end
it "shows a message when replying to flagged topic (first post)" do it "shows a message when replying to flagged topic (first post)" do
Fabricate(:flag, post: original_post, user: user) Fabricate(:flag_post_action, post: original_post, user: user)
finder = ComposerMessagesFinder.new(user, composer_action: "reply", topic_id: topic.id) finder = ComposerMessagesFinder.new(user, composer_action: "reply", topic_id: topic.id)
expect(finder.check_dont_feed_the_trolls).to be_present expect(finder.check_dont_feed_the_trolls).to be_present
end end
it "does not show a message when not enough others have flagged the post" do it "does not show a message when not enough others have flagged the post" do
Fabricate(:flag, post: under_flagged_post, user: other_user) Fabricate(:flag_post_action, post: under_flagged_post, user: other_user)
finder = finder =
ComposerMessagesFinder.new( ComposerMessagesFinder.new(
user, user,
@ -392,7 +392,12 @@ RSpec.describe ComposerMessagesFinder do
it "does not show a message when the flag has already been resolved" do it "does not show a message when the flag has already been resolved" do
SiteSetting.dont_feed_the_trolls_threshold = 1 SiteSetting.dont_feed_the_trolls_threshold = 1
Fabricate(:flag, post: resolved_flag_post, user: other_user, disagreed_at: 1.hour.ago) Fabricate(
:flag_post_action,
post: resolved_flag_post,
user: other_user,
disagreed_at: 1.hour.ago,
)
finder = finder =
ComposerMessagesFinder.new( ComposerMessagesFinder.new(
user, user,
@ -404,8 +409,8 @@ RSpec.describe ComposerMessagesFinder do
end end
it "shows a message when enough others have already flagged the post" do it "shows a message when enough others have already flagged the post" do
Fabricate(:flag, post: over_flagged_post, user: other_user) Fabricate(:flag_post_action, post: over_flagged_post, user: other_user)
Fabricate(:flag, post: over_flagged_post, user: third_user) Fabricate(:flag_post_action, post: over_flagged_post, user: third_user)
finder = finder =
ComposerMessagesFinder.new( ComposerMessagesFinder.new(
user, user,

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
RSpec.describe FlagGuardian do
fab!(:user)
fab!(:admin)
fab!(:flag)
describe "#can_edit_flag?" do
it "returns true for admin and false for regular user" do
expect(Guardian.new(admin).can_edit_flag?(flag)).to eq(true)
expect(Guardian.new(user).can_edit_flag?(flag)).to eq(false)
end
it "returns false when flag is system" do
expect(Guardian.new(admin).can_edit_flag?(Flag.system.first)).to eq(false)
end
it "returns false when flag was already used with post action" do
Fabricate(:post_action, post_action_type_id: flag.id)
expect(Guardian.new(admin).can_edit_flag?(flag)).to eq(false)
end
it "returns false when flag was already used with reviewable" do
Fabricate(:reviewable_score, reviewable_score_type: flag.id)
expect(Guardian.new(admin).can_edit_flag?(flag)).to eq(false)
end
end
end

View File

@ -673,10 +673,7 @@ TEXT
end end
describe "#replace_flags" do describe "#replace_flags" do
after do after { PostActionType.replace_flag_settings(nil) }
PostActionType.replace_flag_settings(nil)
ReviewableScore.reload_types
end
let(:original_flags) { PostActionType.flag_settings } let(:original_flags) { PostActionType.flag_settings }

View File

@ -484,7 +484,7 @@ RSpec.describe PostRevisor do
post = Fabricate(:post, raw: "hello world") post = Fabricate(:post, raw: "hello world")
Fabricate(:flag, post: post, user: user) Fabricate(:flag_post_action, post: post, user: user)
revisor = PostRevisor.new(post) revisor = PostRevisor.new(post)
revisor.revise!( revisor.revise!(

69
spec/models/flag_spec.rb Normal file
View File

@ -0,0 +1,69 @@
# frozen_string_literal: true
RSpec.describe Flag, type: :model do
before { Flag.reset_flag_settings! }
it "has id lower than 1000 for system flags" do
flag = Fabricate(:flag, id: 1)
expect(flag.system?).to be true
end
it "has id greater than 1000 for non-system flags" do
flag = Fabricate(:flag)
expect(flag.system?).to be false
expect(flag.id).to be > 1000
end
it "has correct name key" do
flag = Fabricate(:flag, name: "CuStOm Flag!!!")
expect(flag.name_key).to eq("custom_flag")
flag.update!(name: "It's Illegal")
expect(flag.name_key).to eq("its_illegal")
flag.update!(name: "THIS IS SPaM!+)(*&^%$#@@@!)")
expect(flag.name_key).to eq("this_is_spam")
end
it "updates post action types when created, modified or destroyed" do
expect(PostActionType.flag_types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal],
)
expect(ReviewableScore.types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal needs_approval],
)
flag = Fabricate(:flag, name: "custom")
expect(PostActionType.flag_types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal custom],
)
expect(ReviewableScore.types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal custom needs_approval],
)
flag.update!(name: "edited_custom")
expect(PostActionType.flag_types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal edited_custom],
)
expect(ReviewableScore.types.keys).to eq(
%i[
notify_user
notify_moderators
off_topic
inappropriate
spam
illegal
edited_custom
needs_approval
],
)
flag.destroy!
expect(PostActionType.flag_types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal],
)
expect(ReviewableScore.types.keys).to eq(
%i[notify_user notify_moderators off_topic inappropriate spam illegal needs_approval],
)
end
end

View File

@ -359,7 +359,7 @@ RSpec.describe TrustLevel3Requirements do
flags = flags =
%i[off_topic inappropriate notify_user notify_moderators spam].map do |t| %i[off_topic inappropriate notify_user notify_moderators spam].map do |t|
Fabricate( Fabricate(
:flag, :flag_post_action,
post: Fabricate(:post, user: user), post: Fabricate(:post, user: user),
post_action_type_id: PostActionType.types[t], post_action_type_id: PostActionType.types[t],
agreed_at: 1.minute.ago, agreed_at: 1.minute.ago,
@ -369,7 +369,7 @@ RSpec.describe TrustLevel3Requirements do
_deferred_flags = _deferred_flags =
%i[off_topic inappropriate notify_user notify_moderators spam].map do |t| %i[off_topic inappropriate notify_user notify_moderators spam].map do |t|
Fabricate( Fabricate(
:flag, :flag_post_action,
post: Fabricate(:post, user: user), post: Fabricate(:post, user: user),
post_action_type_id: PostActionType.types[t], post_action_type_id: PostActionType.types[t],
deferred_at: 1.minute.ago, deferred_at: 1.minute.ago,
@ -379,7 +379,7 @@ RSpec.describe TrustLevel3Requirements do
_deleted_flags = _deleted_flags =
%i[off_topic inappropriate notify_user notify_moderators spam].map do |t| %i[off_topic inappropriate notify_user notify_moderators spam].map do |t|
Fabricate( Fabricate(
:flag, :flag_post_action,
post: Fabricate(:post, user: user), post: Fabricate(:post, user: user),
post_action_type_id: PostActionType.types[t], post_action_type_id: PostActionType.types[t],
deleted_at: 1.minute.ago, deleted_at: 1.minute.ago,
@ -388,7 +388,7 @@ RSpec.describe TrustLevel3Requirements do
# Same post, different user: # Same post, different user:
Fabricate( Fabricate(
:flag, :flag_post_action,
post: flags[1].post, post: flags[1].post,
post_action_type_id: PostActionType.types[:spam], post_action_type_id: PostActionType.types[:spam],
agreed_at: 1.minute.ago, agreed_at: 1.minute.ago,
@ -396,7 +396,7 @@ RSpec.describe TrustLevel3Requirements do
# Flagged their own post: # Flagged their own post:
Fabricate( Fabricate(
:flag, :flag_post_action,
user: user, user: user,
post: Fabricate(:post, user: user), post: Fabricate(:post, user: user),
post_action_type_id: PostActionType.types[:spam], post_action_type_id: PostActionType.types[:spam],
@ -405,7 +405,7 @@ RSpec.describe TrustLevel3Requirements do
# More than 100 days ago: # More than 100 days ago:
Fabricate( Fabricate(
:flag, :flag_post_action,
post: Fabricate(:post, user: user, created_at: 101.days.ago), post: Fabricate(:post, user: user, created_at: 101.days.ago),
post_action_type_id: PostActionType.types[:spam], post_action_type_id: PostActionType.types[:spam],
created_at: 101.days.ago, created_at: 101.days.ago,

View File

@ -72,7 +72,11 @@ RSpec.describe SpamRule::AutoSilence do
end end
it "returns 0 when there is one flag that has a reason other than spam" do it "returns 0 when there is one flag that has a reason other than spam" do
Fabricate(:flag, post: post, post_action_type_id: PostActionType.types[:off_topic]) Fabricate(
:flag_post_action,
post: post,
post_action_type_id: PostActionType.types[:off_topic],
)
expect(count).to eq(0) expect(count).to eq(0)
end end

View File

@ -6,7 +6,7 @@ describe "Composer don't feed the trolls popup", type: :system do
fab!(:topic) { Fabricate(:topic, user: user) } fab!(:topic) { Fabricate(:topic, user: user) }
fab!(:post) { Fabricate(:post, user: user, topic: topic) } fab!(:post) { Fabricate(:post, user: user, topic: topic) }
fab!(:reply) { Fabricate(:post, user: troll, topic: topic) } fab!(:reply) { Fabricate(:post, user: troll, topic: topic) }
fab!(:flag) { Fabricate(:flag, post: reply, user: user) } fab!(:flag) { Fabricate(:flag_post_action, post: reply, user: user) }
let(:topic_page) { PageObjects::Pages::Topic.new } let(:topic_page) { PageObjects::Pages::Topic.new }
before { sign_in user } before { sign_in user }

View File

@ -12,7 +12,7 @@ describe "Flagging post", type: :system do
describe "Using Take Action" do describe "Using Take Action" do
it "can select the default action to hide the post, agree with other flags, and reach the flag threshold" do it "can select the default action to hide the post, agree with other flags, and reach the flag threshold" do
other_flag = Fabricate(:flag, post: post_to_flag, user: Fabricate(:moderator)) other_flag = Fabricate(:flag_post_action, post: post_to_flag, user: Fabricate(:moderator))
other_flag_reviewable = other_flag_reviewable =
Fabricate(:reviewable_flagged_post, target: post_to_flag, created_by: other_flag.user) Fabricate(:reviewable_flagged_post, target: post_to_flag, created_by: other_flag.user)
expect(other_flag.reload.agreed_at).to be_nil expect(other_flag.reload.agreed_at).to be_nil