discourse/spec/components/topic_creator_spec.rb
Martin Brennan e3b1f5721b
FIX: Enforce tag group count validation before sending to review queue (#12728)
There is a category setting that enforces 1 or more tags must be added to a topic from a specific tag group before creating it. This validation was not being run before the topic was being sent to a review queue for categories that have that setting enabled.

There was an existing validation in `TopicCreator` but it was not correct; it was only validating when the tags did _not_ exist and also only happened on `create`. I now run the validation in `TopicCreator.valid?`

I also improved the error message shown to the user when they have not added the tags required (showing the tag names from the tag group), and changed the composer tag selector to not show "optional" if there are N tags required from a certain group.
2021-04-19 09:43:50 +10:00

285 lines
11 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
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 '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 '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 'tags' do
fab!(:tag1) { Fabricate(:tag, name: "fun") }
fab!(:tag2) { Fabricate(:tag, name: "fun2") }
before do
SiteSetting.tagging_enabled = true
SiteSetting.min_trust_to_create_tag = 0
SiteSetting.min_trust_level_to_tag_topics = 0
end
context '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 '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 '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 "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 'required tag group' do
fab!(:tag_group) { Fabricate(:tag_group, tags: [tag1]) }
fab!(:category) { Fabricate(:category, name: "beta", required_tag_group: tag_group, min_tags_from_required_group: 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
end
context 'personal message' do
context '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 "enable_personal_messages setting should not be checked when sending private message to staff via flag" do
SiteSetting.enable_personal_messages = false
SiteSetting.min_trust_to_send_messages = TrustLevel[4]
expect(TopicCreator.create(user, Guardian.new(user), pm_valid_attrs.merge(subtype: TopicSubtype.notify_moderators))).to be_valid
end
end
context '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 "min_trust_to_send_messages setting should be checked when sending private message" do
SiteSetting.min_trust_to_send_messages = TrustLevel[4]
expect do
TopicCreator.create(user, Guardian.new(user), pm_valid_attrs)
end.to raise_error(ActiveRecord::Rollback)
end
end
context '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 '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
end
end