FEATURE: Allow to reassign to same user

Currently, when only one user is available for the random auto-assign
and if that user was already assigned, then the assign will fail.

This patch addresses this issue by allowing to reassign a user who’s
already assigned. A new parameter (`allow_self_reassign`) has been added
to `Assigner#assign` with a default value of `false`.
This commit is contained in:
Loïc Guitaut 2023-11-23 18:14:10 +01:00 committed by Loïc Guitaut
parent eb073febb0
commit cac9a763dd
4 changed files with 76 additions and 27 deletions

View File

@ -195,7 +195,7 @@ class ::Assigner
topic.posts.where(post_number: 1).first topic.posts.where(post_number: 1).first
end end
def forbidden_reasons(assign_to:, type:, note:, status:) def forbidden_reasons(assign_to:, type:, note:, status:, allow_self_reassign:)
case case
when assign_to.is_a?(User) && !can_assignee_see_target?(assign_to) when assign_to.is_a?(User) && !can_assignee_see_target?(assign_to)
if topic.private_message? if topic.private_message?
@ -211,7 +211,7 @@ class ::Assigner
end end
when !can_be_assigned?(assign_to) when !can_be_assigned?(assign_to)
assign_to.is_a?(User) ? :forbidden_assign_to : :forbidden_group_assign_to assign_to.is_a?(User) ? :forbidden_assign_to : :forbidden_group_assign_to
when already_assigned?(assign_to, type, note, status) when !allow_self_reassign && already_assigned?(assign_to, type, note, status)
assign_to.is_a?(User) ? :already_assigned : :group_already_assigned assign_to.is_a?(User) ? :already_assigned : :group_already_assigned
when Assignment.where(topic: topic, active: true).count >= ASSIGNMENTS_PER_TOPIC_LIMIT && when Assignment.where(topic: topic, active: true).count >= ASSIGNMENTS_PER_TOPIC_LIMIT &&
!reassign? !reassign?
@ -252,7 +252,13 @@ class ::Assigner
{ success: true } { success: true }
end end
def assign(assign_to, note: nil, skip_small_action_post: false, status: nil) def assign(
assign_to,
note: nil,
skip_small_action_post: false,
status: nil,
allow_self_reassign: false
)
assigned_to_type = assign_to.is_a?(User) ? "User" : "Group" assigned_to_type = assign_to.is_a?(User) ? "User" : "Group"
if topic.private_message? && SiteSetting.invite_on_assign if topic.private_message? && SiteSetting.invite_on_assign
@ -260,7 +266,13 @@ class ::Assigner
end end
forbidden_reason = forbidden_reason =
forbidden_reasons(assign_to: assign_to, type: assigned_to_type, note: note, status: status) forbidden_reasons(
assign_to: assign_to,
type: assigned_to_type,
note: note,
status: status,
allow_self_reassign: allow_self_reassign,
)
return { success: false, reason: forbidden_reason } if forbidden_reason return { success: false, reason: forbidden_reason } if forbidden_reason
if no_assignee_change?(assign_to) && details_change?(note, status) if no_assignee_change?(assign_to) && details_change?(note, status)
@ -271,7 +283,8 @@ class ::Assigner
action_code[:user] = topic.assignment.present? ? "reassigned" : "assigned" action_code[:user] = topic.assignment.present? ? "reassigned" : "assigned"
action_code[:group] = topic.assignment.present? ? "reassigned_group" : "assigned_group" action_code[:group] = topic.assignment.present? ? "reassigned_group" : "assigned_group"
skip_small_action_post = skip_small_action_post || no_assignee_change?(assign_to) skip_small_action_post =
skip_small_action_post || (!allow_self_reassign && no_assignee_change?(assign_to))
if @target.assignment if @target.assignment
Jobs.enqueue( Jobs.enqueue(

View File

@ -87,7 +87,7 @@ class RandomAssignUtils
return create_post_template if post_template return create_post_template if post_template
Assigner Assigner
.new(topic, Discourse.system_user) .new(topic, Discourse.system_user)
.assign(assigned_user) .assign(assigned_user, allow_self_reassign: true)
.then do |result| .then do |result|
next if result[:success] next if result[:success]
no_one! no_one!
@ -104,7 +104,7 @@ class RandomAssignUtils
).create! ).create!
Assigner Assigner
.new(post, Discourse.system_user) .new(post, Discourse.system_user)
.assign(assigned_user) .assign(assigned_user, allow_self_reassign: true)
.then do |result| .then do |result|
next if result[:success] next if result[:success]
PostDestroyer.new(Discourse.system_user, post).destroy PostDestroyer.new(Discourse.system_user, post).destroy

View File

@ -264,33 +264,47 @@ RSpec.describe Assigner do
expect(second_assign[:success]).to eq(true) expect(second_assign[:success]).to eq(true)
end end
it "fails to assign when the assigned user and note is the same" do context "when 'allow_self_reassign' is false" do
assigner = described_class.new(topic, moderator_2) subject(:assign) do
assigner.assign(moderator, note: "note me down") assigner.assign(moderator, note: other_note, allow_self_reassign: self_reassign)
assign = assigner.assign(moderator, note: "note me down")
expect(assign[:success]).to eq(false)
expect(assign[:reason]).to eq(:already_assigned)
end end
it "fails to assign when the assigned user and note is the same" do let(:self_reassign) { false }
assigner = described_class.new(post, moderator_2) let(:assigner) { described_class.new(topic, moderator_2) }
assigner.assign(moderator, note: "note me down") let(:note) { "note me down" }
assign = assigner.assign(moderator, note: "note me down") before { assigner.assign(moderator, note: note) }
expect(assign[:success]).to eq(false) context "when the assigned user and the note is the same" do
expect(assign[:reason]).to eq(:already_assigned) let(:other_note) { note }
it "fails to assign" do
expect(assign).to match(success: false, reason: :already_assigned)
end
end end
it "allows assign when the assigned user is same but note is different" do context "when the assigned user is the same but the note is different" do
assigner = described_class.new(topic, moderator_2) let(:other_note) { "note me down again" }
assigner.assign(moderator, note: "note me down")
assign = assigner.assign(moderator, note: "note me down again") it "allows assignment" do
expect(assign).to match(success: true)
end
end
end
expect(assign[:success]).to eq(true) context "when 'allow_self_reassign' is true" do
subject(:assign) { assigner.assign(moderator, allow_self_reassign: self_reassign) }
let(:self_reassign) { true }
let(:assigner) { described_class.new(topic, moderator_2) }
context "when the assigned user is the same" do
before { assigner.assign(moderator) }
it "allows assignment" do
expect(assign).to match(success: true)
end
end
end end
it "fails to assign when the assigned user cannot view the pm" do it "fails to assign when the assigned user cannot view the pm" do

View File

@ -182,6 +182,28 @@ RSpec.describe RandomAssignUtils do
end end
end end
context "when in a group of one person" do
let(:fields) do
{
"assignees_group" => {
"value" => group_1.id,
},
"assigned_topic" => {
"value" => topic_1.id,
},
}
end
context "when user is already assigned" do
before { described_class.automation_script!(ctx, fields, automation) }
it "reassigns them" do
expect { auto_assign }.to change { topic_1.reload.assignment.id }
expect(topic_1.assignment.assigned_to).to eq(user_1)
end
end
end
context "when assignees_group is not provided" do context "when assignees_group is not provided" do
let(:fields) { { "assigned_topic" => { "value" => topic_1.id } } } let(:fields) { { "assigned_topic" => { "value" => topic_1.id } } }