discourse-assign/spec/lib/topic_assigner_spec.rb

348 lines
12 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe TopicAssigner do
before { SiteSetting.assign_enabled = true }
let(:assign_allowed_group) { Group.find_by(name: 'staff') }
let(:pm_post) { Fabricate(:private_message_post) }
let(:pm) { pm_post.topic }
def assert_publish_topic_state(topic, user)
message = MessageBus.track_publish("/private-messages/assigned") do
yield
end.first
expect(message.data[:topic_id]).to eq(topic.id)
expect(message.user_ids).to eq([user.id])
end
describe 'assigning and unassigning private message' do
it 'should publish the right message' do
user = pm.allowed_users.first
assign_allowed_group.add(user)
assigner = described_class.new(pm, user)
assert_publish_topic_state(pm, user) { assigner.assign(user) }
assert_publish_topic_state(pm, user) { assigner.unassign }
end
end
context "assigning and unassigning" do
let(:post) { Fabricate(:post) }
let(:topic) { post.topic }
let(:secure_category) { Fabricate(:private_category, group: Fabricate(:group)) }
let(:secure_topic) { Fabricate(:post).topic.tap { |t| t.update(category: secure_category) } }
let(:moderator) { Fabricate(:moderator, groups: [assign_allowed_group]) }
let(:moderator2) { Fabricate(:moderator, groups: [assign_allowed_group]) }
let(:assigner) { TopicAssigner.new(topic, moderator2) }
let(:assigner_self) { TopicAssigner.new(topic, moderator) }
it "can assign and unassign correctly" do
messages = MessageBus.track_publish("/notification-alert/#{moderator.id}") do
assigner.assign(moderator)
end
expect(messages.length).to eq(1)
expect(messages.first.data[:excerpt]).to eq("assigned you the topic '#{topic.title}'")
expect(TopicQuery.new(
moderator, assigned: moderator.username
).list_latest.topics).to eq([topic])
expect(TopicUser.find_by(user: moderator).notification_level)
.to eq(TopicUser.notification_levels[:watching])
assigner.unassign
expect(TopicQuery.new(
moderator, assigned: moderator.username
).list_latest.topics).to eq([])
expect(TopicUser.find_by(user: moderator).notification_level)
.to eq(TopicUser.notification_levels[:tracking])
end
it 'does not update notification level if already watching' do
TopicUser.change(moderator.id, topic.id,
notification_level: TopicUser.notification_levels[:watching]
)
expect do
assigner_self.assign(moderator)
end.to_not change { TopicUser.last.notifications_reason_id }
end
it 'does not update notification level if it is not set by the plugin' do
assigner.assign(moderator)
expect(TopicUser.find_by(user: moderator).notification_level)
.to eq(TopicUser.notification_levels[:watching])
TopicUser.change(moderator.id, topic.id,
notification_level: TopicUser.notification_levels[:muted]
)
assigner.unassign
expect(TopicUser.find_by(user: moderator, topic: topic).notification_level)
.to eq(TopicUser.notification_levels[:muted])
end
it "sends a high priority notification to the assignee" do
Notification.expects(:create!).with(
notification_type: Notification.types[:custom],
user_id: moderator.id,
topic_id: topic.id,
post_number: 1,
high_priority: true,
data: {
message: 'discourse_assign.assign_notification',
display_username: moderator2.username,
topic_title: topic.title
}.to_json
)
assigner.assign(moderator)
end
context "when assigns_by_staff_mention is set to true" do
let(:system_user) { Discourse.system_user }
let(:moderator) { Fabricate(:admin, username: "modi", groups: [assign_allowed_group]) }
let(:post) { Fabricate(:post, raw: "Hey you @system, stay unassigned", user: moderator) }
let(:topic) { post.topic }
before do
SiteSetting.assigns_by_staff_mention = true
SiteSetting.assign_other_regex = "\\byour (list|todo)\\b"
end
it "doesn't assign system user" do
TopicAssigner.auto_assign(post)
expect(topic.custom_fields["assigned_to_id"])
.to eq(nil)
end
it "assigns first mentioned staff user after system user" do
post.update(raw: "Don't assign @system. @modi, can you add this to your list?")
TopicAssigner.auto_assign(post)
expect(topic.custom_fields["assigned_to_id"].to_i)
.to eq(moderator.id)
end
end
it "doesn't assign the same user more than once" do
SiteSetting.assign_mailer = AssignMailer.levels[:always]
another_mod = Fabricate(:moderator, groups: [assign_allowed_group])
Email::Sender.any_instance.expects(:send).once
expect(assigned_to?(moderator)).to eq(true)
Email::Sender.any_instance.expects(:send).never
expect(assigned_to?(moderator)).to eq(false)
Email::Sender.any_instance.expects(:send).once
expect(assigned_to?(another_mod)).to eq(true)
end
def assigned_to?(asignee)
assigner.assign(asignee).fetch(:success)
end
it "doesn't assign if the user has too many assigned topics" do
SiteSetting.max_assigned_topics = 1
another_post = Fabricate.build(:post)
assigner.assign(moderator)
second_assign = TopicAssigner.new(another_post.topic, moderator2).assign(moderator)
expect(second_assign[:success]).to eq(false)
expect(second_assign[:reason]).to eq(:too_many_assigns)
end
it "doesn't enforce the limit when self-assigning" do
SiteSetting.max_assigned_topics = 1
another_post = Fabricate(:post)
assigner.assign(moderator)
second_assign = TopicAssigner.new(another_post.topic, moderator).assign(moderator)
expect(second_assign[:success]).to eq(true)
end
it "doesn't count self-assigns when enforcing the limit" do
SiteSetting.max_assigned_topics = 1
another_post = Fabricate(:post)
first_assign = assigner.assign(moderator)
# reached limit so stop
second_assign = TopicAssigner.new(Fabricate(:topic), moderator2).assign(moderator)
# self assign has a bypass
third_assign = TopicAssigner.new(another_post.topic, moderator).assign(moderator)
expect(first_assign[:success]).to eq(true)
expect(second_assign[:success]).to eq(false)
expect(third_assign[:success]).to eq(true)
end
fab!(:admin) { Fabricate(:admin) }
it 'fails to assign when the assigned user cannot view the pm' do
assign = TopicAssigner.new(pm, admin).assign(moderator)
expect(assign[:success]).to eq(false)
expect(assign[:reason]).to eq(:forbidden_assign_to)
end
it 'fails to assign when the assigned user cannot view the topic' do
assign = TopicAssigner.new(secure_topic, admin).assign(moderator)
expect(assign[:success]).to eq(false)
expect(assign[:reason]).to eq(:forbidden_assign_to)
end
it "assigns the PM to the moderator when it's included in the list of allowed users" do
pm.allowed_users << moderator
assign = TopicAssigner.new(pm, admin).assign(moderator)
expect(assign[:success]).to eq(true)
end
it "assigns the PM to the moderator when it's a member of an allowed group" do
pm.allowed_groups << assign_allowed_group
assign = TopicAssigner.new(pm, admin).assign(moderator)
expect(assign[:success]).to eq(true)
end
end
context "assign_self_regex" do
fab!(:me) { Fabricate(:admin) }
fab!(:op) { Fabricate(:post) }
fab!(:reply) { Fabricate(:post, topic: op.topic, user: me, raw: "Will fix. Added to my list ;)") }
before do
SiteSetting.assigns_by_staff_mention = true
SiteSetting.assign_self_regex = "\\bmy list\\b"
end
it "automatically assigns to myself" do
expect(TopicAssigner.auto_assign(reply)).to eq(success: true)
expect(op.topic.custom_fields).to eq("assigned_to_id" => me.id.to_s, "assigned_by_id" => me.id.to_s)
end
it "does not automatically assign to myself" do
admin = Fabricate(:admin)
raw = <<~MD
[quote]
Will fix. Added to my list ;)
[/quote]
`my list`
```text
my list
```
my list
Excellent :clap: Can't wait!
MD
another_reply = Fabricate(:post, topic: op.topic, user: admin, raw: raw)
expect(TopicAssigner.auto_assign(another_reply)).to eq(nil)
end
end
context "assign_other_regex" do
fab!(:me) { Fabricate(:admin) }
fab!(:other) { Fabricate(:admin) }
fab!(:op) { Fabricate(:post) }
fab!(:reply) { Fabricate(:post, topic: op.topic, user: me, raw: "can you add this to your list, @#{other.username}") }
before do
SiteSetting.assigns_by_staff_mention = true
SiteSetting.assign_other_regex = "\\byour (list|todo)\\b"
end
it "automatically assigns to other" do
expect(TopicAssigner.auto_assign(reply)).to eq(success: true)
expect(op.topic.custom_fields).to eq("assigned_to_id" => other.id.to_s, "assigned_by_id" => me.id.to_s)
end
end
context "unassign_on_close" do
let(:post) { Fabricate(:post) }
let(:topic) { post.topic }
let(:moderator) { Fabricate(:moderator, groups: [assign_allowed_group]) }
let(:assigner) { TopicAssigner.new(topic, moderator) }
before do
SiteSetting.unassign_on_close = true
assigner.assign(moderator)
end
it "unassigns on topic closed" do
topic.update_status("closed", true, moderator)
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank
end
it "unassigns on topic autoclosed" do
topic.update_status("autoclosed", true, moderator)
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank
end
it "does not unassign on topic open" do
topic.update_status("closed", false, moderator)
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([topic])
end
it "does not unassign on automatic topic open" do
topic.update_status("autoclosed", false, moderator)
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([topic])
end
end
context "assign_emailer" do
let(:post) { Fabricate(:post) }
let(:topic) { post.topic }
let(:moderator) { Fabricate(:moderator, groups: [assign_allowed_group]) }
let(:moderator2) { Fabricate(:moderator, groups: [assign_allowed_group]) }
it "send an email if set to 'always'" do
SiteSetting.assign_mailer = AssignMailer.levels[:always]
expect { TopicAssigner.new(topic, moderator).assign(moderator) }
.to change { ActionMailer::Base.deliveries.size }.by(1)
end
it "doesn't send an email if the assigner and assignee are not different" do
SiteSetting.assign_mailer = AssignMailer.levels[:different_users]
expect { TopicAssigner.new(topic, moderator).assign(moderator2) }
.to change { ActionMailer::Base.deliveries.size }.by(1)
end
it "doesn't send an email if the assigner and assignee are not different" do
SiteSetting.assign_mailer = AssignMailer.levels[:different_users]
expect { TopicAssigner.new(topic, moderator).assign(moderator) }
.to change { ActionMailer::Base.deliveries.size }.by(0)
end
it "doesn't send an email" do
SiteSetting.assign_mailer = AssignMailer.levels[:never]
expect { TopicAssigner.new(topic, moderator).assign(moderator2) }
.to change { ActionMailer::Base.deliveries.size }.by(0)
end
end
end