discourse/spec/lib/topic_creator_spec.rb
Martin Brennan e62e93f83a
FEATURE: Introduce personal_message_enabled_groups setting (#18042)
This will replace `enable_personal_messages` and
`min_trust_to_send_messages`, this commit introduces
the setting `personal_message_enabled_groups`
and uses it in all places that `enable_personal_messages`
and `min_trust_to_send_messages` currently apply.

A migration is included to set `personal_message_enabled_groups`
based on the following rules:

* If `enable_personal_messages` was false, then set
  `personal_message_enabled_groups` to `3`, which is
  the staff auto group
* If `min_trust_to_send_messages` is not default (1)
  and the above condition is false, then set the
  `personal_message_enabled_groups` setting to
  the appropriate auto group based on the trust level
* Otherwise just set `personal_message_enabled_groups` to
  11 which is the TL1 auto group

After follow-up PRs to plugins using these old settings, we will be
able to drop the old settings from core, in the meantime I've added
 DEPRECATED notices to their descriptions and added them
to the deprecated site settings list.

This commit also introduces a `_map` shortcut method definition
for all `group_list` site settings, e.g. `SiteSetting.personal_message_enabled_groups`
also has `SiteSetting.personal_message_enabled_groups_map` available,
which automatically splits the setting by `|` and converts it into
an array of integers.
2022-09-26 13:58:40 +10:00

519 lines
20 KiB
Ruby

# frozen_string_literal: true
RSpec.describe TopicCreator do
fab!(:user) { Fabricate(:user, trust_level: TrustLevel[2]) }
fab!(:moderator) { Fabricate(:moderator) }
fab!(:admin) { Fabricate(:admin) }
let(:valid_attrs) { Fabricate.attributes_for(:topic) }
let(:pm_valid_attrs) { { raw: 'this is a new post', title: 'this is a new title', archetype: Archetype.private_message, target_usernames: moderator.username } }
let(:pm_to_email_valid_attrs) do
{
raw: 'this is a new email',
title: 'this is a new subject',
archetype: Archetype.private_message,
target_emails: 'moderator@example.com'
}
end
describe '#create' do
context 'with topic success cases' do
before do
TopicCreator.any_instance.expects(:save_topic).returns(true)
TopicCreator.any_instance.expects(:watch_topic).returns(true)
SiteSetting.allow_duplicate_topic_titles = true
end
it "should be possible for an admin to create a topic" do
expect(TopicCreator.create(admin, Guardian.new(admin), valid_attrs)).to be_valid
end
it "should be possible for a moderator to create a topic" do
expect(TopicCreator.create(moderator, Guardian.new(moderator), valid_attrs)).to be_valid
end
it "supports both meta_data and custom_fields" do
opts = valid_attrs.merge(
meta_data: { import_topic_id: "foo" },
custom_fields: { import_id: "bar" }
)
topic = TopicCreator.create(admin, Guardian.new(admin), opts)
expect(topic.custom_fields["import_topic_id"]).to eq("foo")
expect(topic.custom_fields["import_id"]).to eq("bar")
end
context 'with regular user' do
before { SiteSetting.min_trust_to_create_topic = TrustLevel[0] }
it "should be possible for a regular user to create a topic" do
expect(TopicCreator.create(user, Guardian.new(user), valid_attrs)).to be_valid
end
it "should be possible for a regular user to create a topic with blank auto_close_time" do
expect(TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(auto_close_time: ''))).to be_valid
end
it "ignores auto_close_time without raising an error" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(auto_close_time: '24'))
expect(topic).to be_valid
expect(topic.public_topic_timer).to eq(nil)
end
it "can create a topic in a category" do
category = Fabricate(:category, name: "Neil's Blog")
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(category: category.id))
expect(topic).to be_valid
expect(topic.category).to eq(category)
end
it "ignores participant_count without raising an error" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(participant_count: 3))
expect(topic.participant_count).to eq(1)
end
it "accepts participant_count in import mode" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(import_mode: true, participant_count: 3))
expect(topic.participant_count).to eq(3)
end
end
end
context 'with tags' do
fab!(:tag1) { Fabricate(:tag, name: "fun") }
fab!(:tag2) { Fabricate(:tag, name: "fun2") }
fab!(:tag3) { Fabricate(:tag, name: "fun3") }
fab!(:tag4) { Fabricate(:tag, name: "fun4") }
fab!(:tag5) { Fabricate(:tag, name: "fun5") }
fab!(:tag_group1) { Fabricate(:tag_group, tags: [tag1]) }
fab!(:tag_group2) { Fabricate(:tag_group, tags: [tag2]) }
before do
SiteSetting.tagging_enabled = true
SiteSetting.min_trust_to_create_tag = 0
SiteSetting.min_trust_level_to_tag_topics = 0
end
context 'with regular tags' do
it "user can add tags to topic" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(tags: [tag1.name]))
expect(topic).to be_valid
expect(topic.tags.length).to eq(1)
end
end
context 'when assigned via matched watched words' do
fab!(:word1) { Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: tag1.name) }
fab!(:word2) { Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: tag2.name) }
fab!(:word3) { Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: tag3.name, case_sensitive: true) }
it 'adds watched words as tags' do
topic = TopicCreator.create(
user,
Guardian.new(user),
valid_attrs.merge(
title: "This is a #{word1.word} title",
raw: "#{word2.word.upcase} is not the same as #{word3.word.upcase}")
)
expect(topic).to be_valid
expect(topic.tags).to contain_exactly(tag1, tag2)
end
end
context 'with staff-only tags' do
before do
create_staff_only_tags(['alpha'])
end
it "regular users can't add staff-only tags" do
expect do
TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(tags: ['alpha']))
end.to raise_error(ActiveRecord::Rollback)
end
it 'staff can add staff-only tags' do
topic = TopicCreator.create(admin, Guardian.new(admin), valid_attrs.merge(tags: ['alpha']))
expect(topic).to be_valid
expect(topic.tags.length).to eq(1)
end
end
context 'when minimum_required_tags is present' do
fab!(:category) { Fabricate(:category, name: "beta", minimum_required_tags: 2) }
it "fails for regular user if minimum_required_tags is not satisfied" do
expect(
TopicCreator.new(user, Guardian.new(user), valid_attrs.merge(category: category.id)).valid?
).to be_falsy
end
it "lets admin create a topic regardless of minimum_required_tags" do
topic = TopicCreator.create(admin, Guardian.new(admin), valid_attrs.merge(tags: [tag1.name], category: category.id))
expect(topic).to be_valid
expect(topic.tags.length).to eq(1)
end
it "works for regular user if minimum_required_tags is satisfied" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(tags: [tag1.name, tag2.name], category: category.id))
expect(topic).to be_valid
expect(topic.tags.length).to eq(2)
end
it "minimum_required_tags is satisfying for new tags if user can create" do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(tags: ["new tag", "another tag"], category: category.id))
expect(topic).to be_valid
expect(topic.tags.length).to eq(2)
end
it "lets new user create a topic if they don't have sufficient trust level to tag topics" do
SiteSetting.min_trust_level_to_tag_topics = 1
new_user = Fabricate(:newuser)
topic = TopicCreator.create(new_user, Guardian.new(new_user), valid_attrs.merge(category: category.id))
expect(topic).to be_valid
end
end
context 'with required tag group' do
fab!(:tag_group) { Fabricate(:tag_group, tags: [tag1]) }
fab!(:category) { Fabricate(:category, name: "beta", category_required_tag_groups: [CategoryRequiredTagGroup.new(tag_group: tag_group, min_count: 1)]) }
it "when no tags are not present" do
expect(
TopicCreator.new(user, Guardian.new(user), valid_attrs.merge(category: category.id)).valid?
).to be_falsy
end
it "when tags are not part of the tag group" do
expect(
TopicCreator.new(user, Guardian.new(user), valid_attrs.merge(category: category.id, tags: ['nope'])).valid?
).to be_falsy
end
it "when requirement is met" do
expect(
TopicCreator.new(user, Guardian.new(user), valid_attrs.merge(category: category.id, tags: [tag1.name, tag2.name])).valid?
).to be_truthy
end
it "lets staff ignore the restriction" do
expect(
TopicCreator.new(user, Guardian.new(admin), valid_attrs.merge(category: category.id)).valid?
).to be_truthy
end
end
context "when category has restricted tags or tag groups" do
fab!(:category) { Fabricate(:category, tags: [tag3], tag_groups: [tag_group1]) }
it "allows topics without any tags" do
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic without tags",
raw: "hello this is a test topic without tags",
category: category.id,
)
expect(tc.valid?).to eq(true)
expect(tc.errors).to be_empty
topic = tc.create
expect(topic.tags).to be_empty
end
it "allows topics if they use tags only from the tags set that the category restricts" do
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag3.name]
)
expect(tc.valid?).to eq(true)
expect(tc.errors).to be_empty
topic = tc.create
expect(topic.tags).to contain_exactly(tag1, tag3)
end
it "allows topics to use tags that are restricted in multiple categories" do
category2 = Fabricate(:category, tags: [tag5], tag_groups: [tag_group1])
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category2.id,
tags: [tag1.name, tag5.name]
)
expect(tc.valid?).to eq(true)
expect(tc.errors).to be_empty
topic = tc.create
expect(topic.tags).to contain_exactly(tag1, tag5)
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags 1",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag3.name]
)
expect(tc.valid?).to eq(true)
expect(tc.errors).to be_empty
topic = tc.create
expect(topic.tags).to contain_exactly(tag1, tag3)
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags 2",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag5.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.restricted_tags_cannot_be_used_in_category",
count: 1,
tags: tag5.name,
category: category.name
)
)
end
it "rejects topics if they use a tag outside the set of tags that the category restricts" do
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag2.name, tag1.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.category_does_not_allow_tags",
count: 1,
tags: tag2.name,
category: category.name
)
)
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag2.name, tag5.name, tag3.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.category_does_not_allow_tags",
count: 2,
tags: [tag2, tag5].map(&:name).sort.join(", "),
category: category.name
)
)
end
it "rejects topics in other categories if a restricted tag of a category are used" do
category2 = Fabricate(:category)
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category2.id,
tags: [tag1.name, tag2.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.restricted_tags_cannot_be_used_in_category",
count: 1,
tags: tag1.name,
category: category2.name
)
)
end
context "when allowing other tags" do
before { category.update!(allow_global_tags: true) }
it "allows topics to use tags that aren't restricted by any category" do
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag2.name, tag3.name, tag5.name]
)
expect(tc.valid?).to eq(true)
expect(tc.errors).to be_empty
topic = tc.create
expect(topic.tags).to contain_exactly(tag1, tag2, tag3, tag5)
end
it "rejects topics if they use restricted tags of another category" do
Fabricate(:category, tags: [tag5], tag_groups: [tag_group2])
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag5.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.restricted_tags_cannot_be_used_in_category",
count: 1,
tags: tag5.name,
category: category.name
)
)
tc = TopicCreator.new(
user,
Guardian.new(user),
title: "hello this is a test topic with tags",
raw: "hello this is a test topic with tags",
category: category.id,
tags: [tag1.name, tag2.name, tag5.name]
)
expect(tc.valid?).to eq(false)
expect(tc.errors.full_messages).to contain_exactly(
I18n.t(
"tags.forbidden.restricted_tags_cannot_be_used_in_category",
count: 2,
tags: [tag2, tag5].map(&:name).sort.join(", "),
category: category.name
)
)
end
end
end
end
context 'with personal message' do
context 'with success cases' do
before do
TopicCreator.any_instance.expects(:save_topic).returns(true)
TopicCreator.any_instance.expects(:watch_topic).returns(true)
SiteSetting.allow_duplicate_topic_titles = true
SiteSetting.enable_staged_users = true
end
it "should be possible for a regular user to send private message" do
expect(TopicCreator.create(user, Guardian.new(user), pm_valid_attrs)).to be_valid
end
it "min_trust_to_create_topic setting should not be checked when sending private message" do
SiteSetting.min_trust_to_create_topic = TrustLevel[4]
expect(TopicCreator.create(user, Guardian.new(user), pm_valid_attrs)).to be_valid
end
it "personal_message_enabled_groups setting should not be checked when sending private messages to staff via flag" do
SiteSetting.personal_message_enabled_groups = Group::AUTO_GROUPS[:staff]
expect(TopicCreator.create(user, Guardian.new(user), pm_valid_attrs.merge(subtype: TopicSubtype.notify_moderators))).to be_valid
end
end
context 'with failure cases' do
it "should be rollback the changes when email is invalid" do
SiteSetting.manual_polling_enabled = true
SiteSetting.reply_by_email_address = "sam+%{reply_key}@sam.com"
SiteSetting.reply_by_email_enabled = true
SiteSetting.min_trust_to_send_email_messages = TrustLevel[1]
attrs = pm_to_email_valid_attrs.dup
attrs[:target_emails] = "t" * 256
expect do
TopicCreator.create(user, Guardian.new(user), attrs)
end.to raise_error(ActiveRecord::Rollback)
end
it "personal_message_enabled_groups setting should be checked when sending private message" do
SiteSetting.enable_personal_messages = false
SiteSetting.personal_message_enabled_groups = Group::AUTO_GROUPS[:trust_level_4]
expect do
TopicCreator.create(user, Guardian.new(user), pm_valid_attrs)
end.to raise_error(ActiveRecord::Rollback)
end
end
context 'with to emails' do
it 'works for staff' do
SiteSetting.min_trust_to_send_email_messages = 'staff'
expect(TopicCreator.create(admin, Guardian.new(admin), pm_to_email_valid_attrs)).to be_valid
end
it 'work for trusted users' do
SiteSetting.min_trust_to_send_email_messages = 3
user.update!(trust_level: 3)
expect(TopicCreator.create(user, Guardian.new(user), pm_to_email_valid_attrs)).to be_valid
end
it 'does not work for non-staff' do
SiteSetting.min_trust_to_send_email_messages = 'staff'
expect { TopicCreator.create(user, Guardian.new(user), pm_to_email_valid_attrs) }.to raise_error(ActiveRecord::Rollback)
end
it 'does not work for untrusted users' do
SiteSetting.min_trust_to_send_email_messages = 3
user.update!(trust_level: 2)
expect { TopicCreator.create(user, Guardian.new(user), pm_to_email_valid_attrs) }.to raise_error(ActiveRecord::Rollback)
end
end
end
context 'when setting timestamps' do
it 'supports Time instances' do
freeze_time
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(
created_at: 1.week.ago,
pinned_at: 3.days.ago
))
expect(topic.created_at).to eq_time(1.week.ago)
expect(topic.pinned_at).to eq_time(3.days.ago)
end
it 'supports strings' do
freeze_time
time1 = Time.zone.parse('2019-09-02')
time2 = Time.zone.parse('2020-03-10 15:17')
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(
created_at: '2019-09-02',
pinned_at: '2020-03-10 15:17'
))
expect(topic.created_at).to eq_time(time1)
expect(topic.pinned_at).to eq_time(time2)
end
end
context 'with external_id' do
it 'adds external_id' do
topic = TopicCreator.create(user, Guardian.new(user), valid_attrs.merge(
external_id: 'external_id'
))
expect(topic.external_id).to eq('external_id')
end
end
end
end