0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-11 02:59:07 +08:00
discourse/plugins/discourse-assign/app/models/assignment.rb
Mark VanLandingham 2aaa6a5ca3
FEATURE: Add category-level assignment permissions (#40412)
Previously, assignment permissions only came from the global
`assign_allowed_on_groups` site setting.

This change lets categories grant assignment permission to additional
groups, keeping assignment controls and assignee suggestions scoped to
the relevant category.
2026-06-08 09:59:40 -05:00

161 lines
4.4 KiB
Ruby
Vendored

# frozen_string_literal: true
require_relative "../../lib/discourse_assign/assignment_permissions"
class Assignment < ActiveRecord::Base
VALID_TYPES = %w[topic post].freeze
belongs_to :topic
belongs_to :assigned_to, polymorphic: true
belongs_to :assigned_by_user, class_name: "User"
belongs_to :target, polymorphic: true
scope :joins_with_topics,
-> do
joins(
"INNER JOIN topics ON topics.id = assignments.target_id AND assignments.target_type = 'Topic' AND topics.deleted_at IS NULL",
)
end
scope :active_for_group, ->(group) { active.where(assigned_to: group) }
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
before_validation :default_status
validate :validate_status, if: -> { SiteSetting.enable_assign_status }
class << self
def valid_type?(type)
VALID_TYPES.include?(type.downcase)
end
def statuses
SiteSetting.assign_statuses.split("|")
end
def default_status
Assignment.statuses.first
end
def status_enabled?
SiteSetting.enable_assign_status
end
def deactivate!(topic:)
active.where(topic: topic).find_each(&:deactivate!)
end
def reactivate!(topic:)
inactive.where(topic: topic).find_each(&:reactivate!)
end
end
def assigned_to_user?
assigned_to.is_a?(User)
end
def assigned_to_group?
assigned_to.is_a?(Group)
end
def assigned_users
Array.wrap(assigned_to.try(:users) || assigned_to)
end
def post
return target.posts.find_by(post_number: 1) if target.is_a?(Topic)
target
end
def create_missing_notifications!
assigned_users.each do |user|
next if user.notifications.for_assignment(self).exists?
DiscourseAssign::CreateNotification.call(
assignment: self,
user: user,
mark_as_read: assigned_by_user == user,
)
end
end
def reactivate!
return unless target
update!(active: true)
Jobs.enqueue(:assign_notification, assignment_id: id)
publish_topic_assignment
end
def deactivate!
update!(active: false)
Jobs.enqueue(
:unassign_notification,
topic_id: topic_id,
assigned_to_id: assigned_to_id,
assigned_to_type: assigned_to_type,
assignment_id: id,
)
end
def publish_topic_assignment
return if !assigned_to
allowed_user_ids =
DiscourseAssign::AssignmentPermissions.allowed_user_ids_for_target(target || topic)
return if allowed_user_ids.blank?
serializer_class = assigned_to_user? ? BasicUserSerializer : BasicGroupSerializer
MessageBus.publish(
"/staff/topic-assignment",
{
type: "assigned",
topic_id: topic_id,
post_id: target.is_a?(Post) && target.id,
post_number: target.is_a?(Post) && target.post_number,
assigned_type: assigned_to_type,
assigned_to: serializer_class.new(assigned_to, scope: Guardian.new, root: false).as_json,
assignment_note: note,
assignment_status: status,
},
user_ids: allowed_user_ids,
)
end
private
def default_status
self.status ||= Assignment.default_status if SiteSetting.enable_assign_status
end
def validate_status
if SiteSetting.enable_assign_status && !Assignment.statuses.include?(self.status)
errors.add(:status, :invalid)
end
end
end
# == Schema Information
#
# Table name: assignments
#
# id :bigint not null, primary key
# active :boolean default(TRUE)
# assigned_to_type :string not null
# note :string
# status :text
# target_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# assigned_by_user_id :integer not null
# assigned_to_id :integer not null
# target_id :integer not null
# topic_id :integer not null
#
# Indexes
#
# index_assignments_on_active (active)
# index_assignments_on_assigned_to_id_and_assigned_to_type (assigned_to_id,assigned_to_type)
# index_assignments_on_target_id_and_target_type (target_id,target_type) UNIQUE
# index_assignments_on_topic_id (topic_id)
# unique_target_and_assigned (assigned_to_id,assigned_to_type,target_id,target_type) UNIQUE
#