FIX: more accurate and flexible random assign automation (#222)

- allows to define the number of days within which a user is considered recently assigned
- more correct by now using post custom fields
This commit is contained in:
Joffrey JAFFEUX 2021-10-19 17:31:17 +02:00 committed by GitHub
parent dc8f43fbb1
commit 7747bb81a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 16 deletions

View File

@ -86,7 +86,13 @@ en:
assignees_group: assignees_group:
label: Assignees Group label: Assignees Group
minimum_time_between_assignments: minimum_time_between_assignments:
label: Hours between assignments label: Mininmum hours between assignments
min_recently_assigned_days:
label: Min recently assigned days
description: Defaults to 14 days.
max_recently_assigned_days:
label: Max recently assigned days
description: First attempt to exclude users assigned in the last `n` days. If no user left, fallbacks to `min_recently_assigned_days`. Defaults to 180 days.
assigned_topic: assigned_topic:
label: Assigned Topic ID label: Assigned Topic ID
in_working_hours: in_working_hours:

View File

@ -1,6 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
class RandomAssignUtils class RandomAssignUtils
def self.recently_assigned_users_ids(topic_id, from)
posts = Post
.joins(:user)
.where(topic_id: topic_id, action_code: 'assigned')
.where('posts.created_at > ?', from)
.order(created_at: :desc)
usernames = Post.custom_fields_for_ids(posts, [:action_code_who]).map { |_, v| v['action_code_who'] }.uniq
User.where(username: usernames).limit(100).pluck(:id)
end
def self.user_tzinfo(user_id) def self.user_tzinfo(user_id)
timezone = UserOption.where(user_id: user_id).pluck(:timezone).first || "UTC" timezone = UserOption.where(user_id: user_id).pluck(:timezone).first || "UTC"

View File

@ -701,6 +701,8 @@ after_initialize do
field :assignees_group, component: :group field :assignees_group, component: :group
field :assigned_topic, component: :text field :assigned_topic, component: :text
field :minimum_time_between_assignments, component: :text field :minimum_time_between_assignments, component: :text
field :max_recently_assigned_days, component: :text
field :min_recently_assigned_days, component: :text
field :in_working_hours, component: :boolean field :in_working_hours, component: :boolean
version 1 version 1
@ -719,7 +721,7 @@ after_initialize do
next unless group_id = fields.dig('assignees_group', 'value') next unless group_id = fields.dig('assignees_group', 'value')
next unless group = Group.find_by(id: group_id) next unless group = Group.find_by(id: group_id)
min_hours = fields.dig('minimum_time_between_assignments', 'value') min_hours = fields.dig('minimum_time_between_assignments', 'value').presence
if min_hours && TopicCustomField if min_hours && TopicCustomField
.where(name: 'assigned_to_id', topic_id: topic_id) .where(name: 'assigned_to_id', topic_id: topic_id)
.where('created_at < ?', min_hours.to_i.hours.ago) .where('created_at < ?', min_hours.to_i.hours.ago)
@ -747,23 +749,14 @@ after_initialize do
next next
end end
last_assignees_ids = UserAction last_assignees_ids = RandomAssignUtils.recently_assigned_users_ids(
.joins(:user) topic_id,
.where(action_type: UserAction::ASSIGNED, target_topic_id: topic_id) (fields.dig('max_recently_assigned_days', 'value').presence || 180).to_i.days.ago
.where('user_actions.created_at > ?', 6.months.ago) )
.order(created_at: :desc)
.limit(group_users_ids.length)
.pluck('users.id')
.uniq
users_ids = group_users_ids - last_assignees_ids users_ids = group_users_ids - last_assignees_ids
if users_ids.blank? if users_ids.blank?
recently_assigned_users_ids = UserAction recently_assigned_users_ids = RandomAssignUtils.recently_assigned_users_ids(topic_id, (fields.dig('min_recently_assigned_days', 'value').presence || 14).to_i.days.ago)
.joins(:user)
.where(action_type: UserAction::ASSIGNED, target_topic_id: topic_id)
.where('user_actions.created_at < ?', 2.weeks.ago)
.pluck('users.id')
.uniq
users_ids = group_users_ids - recently_assigned_users_ids users_ids = group_users_ids - recently_assigned_users_ids
end end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'rails_helper'
require_relative '../support/assign_allowed_group'
require 'random_assign_utils'
describe RandomAssignUtils do
before do
SiteSetting.assign_enabled = true
end
let(:post) { Fabricate(:post) }
describe '.recently_assigned_users_ids' do
context 'no one has been assigned' do
it 'returns an empty array' do
assignees_ids = described_class.recently_assigned_users_ids(post.topic_id, 2.months.ago)
expect(assignees_ids).to eq([])
end
end
context 'users have been assigned' do
let(:admin) { Fabricate(:admin) }
let(:assign_allowed_group) { Group.find_by(name: 'staff') }
let(:user_1) { Fabricate(:user, groups: [assign_allowed_group]) }
let(:user_2) { Fabricate(:user, groups: [assign_allowed_group]) }
let(:user_3) { Fabricate(:user, groups: [assign_allowed_group]) }
it 'returns the recently assigned user ids' do
freeze_time 1.months.ago do
Assigner.new(post.topic, admin).assign(user_1)
Assigner.new(post.topic, admin).assign(user_2)
end
freeze_time 3.months.ago do
Assigner.new(post.topic, admin).assign(user_3)
end
assignees_ids = described_class.recently_assigned_users_ids(post.topic_id, 2.months.ago)
expect(assignees_ids).to contain_exactly(user_1.id, user_2.id)
end
end
end
end