160 lines
5.1 KiB
Ruby
160 lines
5.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class RandomAssignUtils
|
|
def self.raise_error(automation, message)
|
|
raise("[discourse-automation id=#{automation.id}] #{message}.")
|
|
end
|
|
|
|
def self.log_info(automation, message)
|
|
Rails.logger.info("[discourse-automation id=#{automation.id}] #{message}.")
|
|
end
|
|
|
|
def self.automation_script!(context, fields, automation)
|
|
raise_error(automation, "discourse-assign is not enabled") unless SiteSetting.assign_enabled?
|
|
|
|
unless topic_id = fields.dig("assigned_topic", "value")
|
|
raise_error(automation, "`assigned_topic` not provided")
|
|
end
|
|
|
|
unless topic = Topic.find_by(id: topic_id)
|
|
raise_error(automation, "Topic(#{topic_id}) not found")
|
|
end
|
|
|
|
min_hours = fields.dig("minimum_time_between_assignments", "value").presence
|
|
if min_hours &&
|
|
TopicCustomField
|
|
.where(name: "assigned_to_id", topic_id: topic_id)
|
|
.where("created_at < ?", min_hours.to_i.hours.ago)
|
|
.exists?
|
|
log_info(automation, "Topic(#{topic_id}) has already been assigned recently")
|
|
return
|
|
end
|
|
|
|
unless group_id = fields.dig("assignees_group", "value")
|
|
raise_error(automation, "`assignees_group` not provided")
|
|
end
|
|
|
|
unless group = Group.find_by(id: group_id)
|
|
raise_error(automation, "Group(#{group_id}) not found")
|
|
end
|
|
|
|
assignable_user_ids = User.assign_allowed.pluck(:id)
|
|
users_on_holiday =
|
|
Set.new(
|
|
User.where(
|
|
id: UserCustomField.where(name: "on_holiday", value: "t").select(:user_id),
|
|
).pluck(:id),
|
|
)
|
|
|
|
group_users = group.group_users.joins(:user)
|
|
if skip_new_users_for_days = fields.dig("skip_new_users_for_days", "value").presence
|
|
group_users = group_users.where("users.created_at < ?", skip_new_users_for_days.to_i.days.ago)
|
|
end
|
|
|
|
group_users_ids =
|
|
group_users
|
|
.pluck("users.id")
|
|
.filter { |user_id| assignable_user_ids.include?(user_id) }
|
|
.reject { |user_id| users_on_holiday.include?(user_id) }
|
|
|
|
if group_users_ids.empty?
|
|
RandomAssignUtils.no_one!(topic_id, group.name)
|
|
return
|
|
end
|
|
|
|
max_recently_assigned_days =
|
|
(fields.dig("max_recently_assigned_days", "value").presence || 180).to_i.days.ago
|
|
last_assignees_ids =
|
|
RandomAssignUtils.recently_assigned_users_ids(topic_id, max_recently_assigned_days)
|
|
users_ids = group_users_ids - last_assignees_ids
|
|
if users_ids.blank?
|
|
min_recently_assigned_days =
|
|
(fields.dig("min_recently_assigned_days", "value").presence || 14).to_i.days.ago
|
|
recently_assigned_users_ids =
|
|
RandomAssignUtils.recently_assigned_users_ids(topic_id, min_recently_assigned_days)
|
|
users_ids = group_users_ids - recently_assigned_users_ids
|
|
end
|
|
|
|
if users_ids.blank?
|
|
RandomAssignUtils.no_one!(topic_id, group.name)
|
|
return
|
|
end
|
|
|
|
if fields.dig("in_working_hours", "value")
|
|
assign_to_user_id =
|
|
users_ids.shuffle.find { |user_id| RandomAssignUtils.in_working_hours?(user_id) }
|
|
end
|
|
|
|
assign_to_user_id ||= users_ids.sample
|
|
if assign_to_user_id.blank?
|
|
RandomAssignUtils.no_one!(topic_id, group.name)
|
|
return
|
|
end
|
|
|
|
assign_to = User.find(assign_to_user_id)
|
|
result = nil
|
|
if raw = fields.dig("post_template", "value").presence
|
|
post =
|
|
PostCreator.new(
|
|
Discourse.system_user,
|
|
raw: raw,
|
|
skip_validations: true,
|
|
topic_id: topic.id,
|
|
).create!
|
|
|
|
result = Assigner.new(post, Discourse.system_user).assign(assign_to)
|
|
|
|
PostDestroyer.new(Discourse.system_user, post).destroy if !result[:success]
|
|
else
|
|
result = Assigner.new(topic, Discourse.system_user).assign(assign_to)
|
|
end
|
|
|
|
RandomAssignUtils.no_one!(topic_id, group.name) if !result[:success]
|
|
end
|
|
|
|
def self.recently_assigned_users_ids(topic_id, from)
|
|
posts =
|
|
Post
|
|
.joins(:user)
|
|
.where(topic_id: topic_id, action_code: %w[assigned reassigned assigned_to_post])
|
|
.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)
|
|
timezone = UserOption.where(user_id: user_id).pluck(:timezone).first || "UTC"
|
|
|
|
tzinfo = nil
|
|
begin
|
|
tzinfo = ActiveSupport::TimeZone.find_tzinfo(timezone)
|
|
rescue TZInfo::InvalidTimezoneIdentifier
|
|
Rails.logger.warn(
|
|
"#{User.find_by(id: user_id)&.username} has the timezone #{timezone} set, we do not know how to parse it in Rails (assuming UTC)",
|
|
)
|
|
timezone = "UTC"
|
|
tzinfo = ActiveSupport::TimeZone.find_tzinfo(timezone)
|
|
end
|
|
|
|
tzinfo
|
|
end
|
|
|
|
def self.no_one!(topic_id, group)
|
|
PostCreator.create!(
|
|
Discourse.system_user,
|
|
topic_id: topic_id,
|
|
raw: I18n.t("discourse_automation.scriptables.random_assign.no_one", group: group),
|
|
validate: false,
|
|
)
|
|
end
|
|
|
|
def self.in_working_hours?(user_id)
|
|
tzinfo = RandomAssignUtils.user_tzinfo(user_id)
|
|
tztime = tzinfo.now
|
|
|
|
!tztime.saturday? && !tztime.sunday? && tztime.hour > 7 && tztime.hour < 11
|
|
end
|
|
end
|