discourse/spec/lib/topic_creator_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

661 lines
22 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
RSpec.describe TopicCreator do
fab!(:user) { Fabricate(:user, trust_level: TrustLevel[2]) }
fab!(:moderator)
fab!(:admin)
let(:valid_attrs) { Fabricate.attributes_for(:topic) }
let(:pm_valid_attrs) do
{
raw: "this is a new post",
title: "this is a new title",
archetype: Archetype.private_message,
target_usernames: moderator.username,
}
end
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
before { Group.refresh_automatic_groups! }
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
2015-01-10 00:34:37 +08:00
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
2015-01-10 00:34:37 +08:00
expect(TopicCreator.create(moderator, Guardian.new(moderator), valid_attrs)).to be_valid
end
it "supports custom_fields that has been registered to the DiscoursePluginRegistry" do
opts = valid_attrs.merge(custom_fields: { import_id: "bar" })
topic = TopicCreator.create(admin, Guardian.new(admin), opts)
expect(topic.custom_fields["import_id"]).to eq("bar")
end
context "with regular user" do
before { SiteSetting.create_topic_allowed_groups = Group::AUTO_GROUPS[:trust_level_0] }
it "should be possible for a regular user to create a topic" do
2015-01-10 00:34:37 +08:00
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
2015-01-10 00:34:37 +08:00
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"))
2015-01-10 00:34:37 +08:00
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))
2015-01-10 00:34:37 +08:00
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]) }
2018-03-29 02:40:26 +08:00
before do
SiteSetting.tagging_enabled = true
SiteSetting.create_tag_allowed_groups = Group::AUTO_GROUPS[:trust_level_0]
2018-03-29 02:40:26 +08:00
SiteSetting.min_trust_level_to_tag_topics = 0
end
context "with regular tags" do
2018-03-29 02:40:26 +08:00
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
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
context "when assigned via matched watched words" do
fab!(:word1) do
Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: tag1.name)
end
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
fab!(:word2) do
Fabricate(:watched_word, action: WatchedWord.actions[:tag], replacement: tag2.name)
end
fab!(:word3) do
Fabricate(
:watched_word,
action: WatchedWord.actions[:tag],
replacement: tag3.name,
case_sensitive: true,
)
end
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
it "adds watched words as tags" do
topic =
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
TopicCreator.create(
user,
Guardian.new(user),
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
valid_attrs.merge(
title: "This is a #{word1.word} title",
raw: "#{word2.word.upcase} is not the same as #{word3.word.upcase}",
),
)
FEATURE: Add support for case-sensitive Watched Words (#17445) * FEATURE: Add case-sensitivity flag to watched_words Currently, all watched words are matched case-insensitively. This flag allows a watched word to be flagged for case-sensitive matching. To allow allow for backwards compatibility the flag is set to false by default. * FEATURE: Support case-sensitive creation of Watched Words via API Extend admin creation and upload of Watched Words to support case sensitive flag. This lays the ground work for supporting case-insensitive matching of Watched Words. Support for an extra column has also been introduced for the Watched Words upload CSV file. The new column structure is as follows: word,replacement,case_sentive * FEATURE: Enable case-sensitive matching of Watched Words WordWatcher's word_matcher_regexp now returns a list of regular expressions instead of one case-insensitive regular expression. With the ability to flag a Watched Word as case-sensitive, an action can have words of both sensitivities.This makes the use of the global Regexp::IGNORECASE flag added to all words problematic. To get around platform limitations around the use of subexpression level switches/flags, a list of regular expressions is returned instead, one for each case sensitivity. Word matching has also been updated to use this list of regular expressions instead of one. * FEATURE: Use case-sensitive regular expressions for Watched Words Update Watched Words regular expressions matching and processing to handle the extra metadata which comes along with the introduction of case-sensitive Watched Words. This allows case-sensitive Watched Words to matched as such. * DEV: Simplify type casting of case-sensitive flag from uploads Use builtin semantics instead of a custom method for converting string case flags in uploaded Watched Words to boolean. * UX: Add case-sensitivity details to Admin Watched Words UI Update Watched Word form to include a toggle for case-sensitivity. This also adds support for, case-sensitive testing and matching of Watched Word in the admin UI. * DEV: Code improvements from review feedback - Extract watched word regex creation out to a utility function - Make JS array presence check more explicit and readable * DEV: Extract Watched Word regex creation to utility function Clean-up work from review feedback. Reduce code duplication. * DEV: Rename word_matcher_regexp to word_matcher_regexp_list Since a list is returned now instead of a single regular expression, change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate this change. * DEV: Incorporate WordWatcher updates from upstream Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches that aren't at the beginning of the line.
2022-08-02 16:06:03 +08:00
expect(topic).to be_valid
expect(topic.tags).to contain_exactly(tag1, tag2)
end
end
context "with staff-only tags" do
before { create_staff_only_tags(["alpha"]) }
2018-03-29 02:40:26 +08:00
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) }
2018-03-29 02:40:26 +08:00
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
2018-03-29 02:40:26 +08:00
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),
)
2018-03-29 02:40:26 +08:00
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),
)
2018-03-29 02:40:26 +08:00
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, refresh_auto_groups: true)
topic =
TopicCreator.create(
new_user,
Guardian.new(new_user),
valid_attrs.merge(category: category.id),
)
expect(topic).to be_valid
end
2018-03-29 02:40:26 +08:00
end
context "with required tag group" do
fab!(:tag_group) { Fabricate(:tag_group, tags: [tag1]) }
fab!(:category) do
Fabricate(
:category,
name: "beta",
category_required_tag_groups: [
CategoryRequiredTagGroup.new(tag_group: tag_group, min_count: 1),
],
)
end
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
2018-03-29 02:40:26 +08:00
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
Group.refresh_automatic_groups!
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 "create_topic_allowed_groups setting should not be checked when sending private message" do
SiteSetting.create_topic_allowed_groups = Group::AUTO_GROUPS[:trust_level_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
2018-08-27 12:50:56 +08:00
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.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
before { Group.refresh_automatic_groups! }
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
context "when invisible/unlisted" do
let(:unlisted_attrs) { valid_attrs.merge(visible: false) }
it "throws an exception for a non-staff user" do
expect do TopicCreator.create(user, Guardian.new(user), unlisted_attrs) end.to raise_error(
ActiveRecord::Rollback,
)
end
it "is invalid for a non-staff user" do
expect(TopicCreator.new(user, Guardian.new(user), unlisted_attrs).valid?).to eq(false)
end
it "creates unlisted topic for an admin" do
expect(TopicCreator.create(admin, Guardian.new(admin), unlisted_attrs)).to be_valid
end
it "is valid for an admin" do
expect(TopicCreator.new(admin, Guardian.new(admin), unlisted_attrs).valid?).to eq(true)
end
context "when embedded" do
let(:embedded_unlisted_attrs) do
unlisted_attrs.merge(embed_url: "http://eviltrout.com/stupid-url")
end
it "is valid for a non-staff user" do
expect(TopicCreator.new(user, Guardian.new(user), embedded_unlisted_attrs).valid?).to eq(
true,
)
end
end
end
end
end