226 lines
7.1 KiB
Ruby
226 lines
7.1 KiB
Ruby
# name: discourse-assign
|
|
# about: Assign users to topics
|
|
# version: 0.1
|
|
# authors: Sam Saffron
|
|
|
|
register_asset 'stylesheets/assigns.scss'
|
|
|
|
after_initialize do
|
|
|
|
module ::DiscourseAssign
|
|
class Engine < ::Rails::Engine
|
|
engine_name "discourse_assign"
|
|
isolate_namespace DiscourseAssign
|
|
end
|
|
end
|
|
|
|
class ::DiscourseAssign::AssignController < Admin::AdminController
|
|
before_filter :ensure_logged_in
|
|
|
|
def unassign
|
|
topic_id = params.require(:topic_id)
|
|
topic = Topic.find(topic_id.to_i)
|
|
if assigned_to_id = topic.custom_fields["assigned_to_id"]
|
|
topic.custom_fields["assigned_to_id"] = nil
|
|
topic.custom_fields["assigned_by_id"] = nil
|
|
topic.save!
|
|
|
|
post = topic.posts.where(post_number: 1).first
|
|
post.publish_change_to_clients!(:revised, { reload_topic: true })
|
|
|
|
assigned_user = User.find_by(id: assigned_to_id)
|
|
|
|
UserAction.where(
|
|
action_type: UserAction::ASSIGNED,
|
|
target_post_id: post.id
|
|
).destroy_all
|
|
|
|
# yank notification
|
|
Notification.where(
|
|
notification_type: Notification.types[:custom],
|
|
user_id: assigned_user.try(:id),
|
|
topic_id: topic.id,
|
|
post_number: 1
|
|
).where("data like '%discourse_assign.assign_notification%'")
|
|
.destroy_all
|
|
|
|
|
|
post_type = SiteSetting.assigns_public ? Post.types[:small_action] : Post.types[:whisper]
|
|
topic.add_moderator_post(current_user,
|
|
I18n.t('discourse_assign.unassigned'),
|
|
{ bump: false,
|
|
post_type: post_type,
|
|
action_code: "assigned"})
|
|
end
|
|
|
|
render json: success_json
|
|
end
|
|
|
|
def assign
|
|
topic_id = params.require(:topic_id)
|
|
username = params.require(:username)
|
|
|
|
topic = Topic.find(topic_id.to_i)
|
|
assign_to = User.find_by(username_lower: username.downcase)
|
|
|
|
raise Discourse::NotFound unless assign_to
|
|
|
|
#Scheduler::Defer.later "assign topic" do
|
|
|
|
topic.custom_fields["assigned_to_id"] = assign_to.id
|
|
topic.custom_fields["assigned_by_id"] = current_user.id
|
|
topic.save!
|
|
|
|
topic.posts.first.publish_change_to_clients!(:revised, { reload_topic: true })
|
|
|
|
|
|
UserAction.log_action!(action_type: UserAction::ASSIGNED,
|
|
user_id: assign_to.id,
|
|
acting_user_id: current_user.id,
|
|
target_post_id: topic.posts.find_by(post_number: 1).id,
|
|
target_topic_id: topic.id)
|
|
|
|
post_type = SiteSetting.assigns_public ? Post.types[:small_action] : Post.types[:whisper]
|
|
|
|
topic.add_moderator_post(current_user,
|
|
I18n.t('discourse_assign.assigned_to',
|
|
username: assign_to.username),
|
|
{ bump: false,
|
|
post_type: post_type,
|
|
action_code: "assigned"})
|
|
|
|
unless current_user.id == assign_to.id
|
|
|
|
Notification.create!(notification_type: Notification.types[:custom],
|
|
user_id: assign_to.id,
|
|
topic_id: topic.id,
|
|
post_number: 1,
|
|
data: {
|
|
message: 'discourse_assign.assign_notification',
|
|
display_username: current_user.username,
|
|
topic_title: topic.title
|
|
}.to_json
|
|
)
|
|
end
|
|
|
|
|
|
render json: success_json
|
|
end
|
|
|
|
class ::Topic
|
|
def assigned_to_user
|
|
@assigned_to_user ||
|
|
if user_id = custom_fields["assigned_to_id"]
|
|
@assigned_to_user = User.find_by(id: user_id)
|
|
end
|
|
end
|
|
|
|
def preload_assigned_to_user(assigned_to_user)
|
|
@assigned_to_user = assigned_to_user
|
|
end
|
|
end
|
|
|
|
TopicList.preloaded_custom_fields << "assigned_to_id"
|
|
|
|
TopicList.on_preload do |topics, topic_list|
|
|
is_staff = topic_list.current_user && topic_list.current_user.staff?
|
|
allowed_access = SiteSetting.assigns_public || is_staff
|
|
|
|
if allowed_access && topics.length > 0
|
|
users = User.where("id in (
|
|
SELECT value::int
|
|
FROM topic_custom_fields
|
|
WHERE name = 'assigned_to_id' AND topic_id IN (?)
|
|
)", topics.map(&:id))
|
|
.select(:id, :email, :username, :uploaded_avatar_id)
|
|
|
|
map = {}
|
|
users.each{|u| map[u.id] = u}
|
|
|
|
topics.each do |t|
|
|
if id = t.custom_fields['assigned_to_id']
|
|
t.preload_assigned_to_user(map[id.to_i])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
require_dependency 'topic_query'
|
|
TopicQuery.add_custom_filter(:assigned) do |results, topic_query|
|
|
if topic_query.guardian.is_staff? || SiteSetting.assigns_public
|
|
username = topic_query.options[:assigned]
|
|
user_id = User.where(username_lower: username.downcase).pluck(:id).first if username.present? && username != "*"
|
|
if user_id || username == "*"
|
|
|
|
if username == "*"
|
|
filter = "AND tc_assign.value IS NOT NULL"
|
|
else
|
|
filter = "AND tc_assign.value = '#{user_id.to_i.to_s}'"
|
|
end
|
|
|
|
results = results.joins("JOIN topic_custom_fields tc_assign ON
|
|
topics.id = tc_assign.topic_id AND
|
|
tc_assign.name = 'assigned_to_id'
|
|
#{filter}
|
|
")
|
|
end
|
|
end
|
|
|
|
results
|
|
end
|
|
|
|
require_dependency 'listable_topic_serializer'
|
|
class ::ListableTopicSerializer
|
|
has_one :assigned_to_user, serializer: BasicUserSerializer, embed: :objects
|
|
|
|
def include_assigned_to_user?
|
|
(SiteSetting.assigns_public || scope.is_staff?) && object.assigned_to_user
|
|
end
|
|
end
|
|
|
|
require_dependency 'topic_view_serializer'
|
|
class ::TopicViewSerializer
|
|
attributes :assigned_to_user
|
|
|
|
def assigned_to_user
|
|
if user = User.find_by(id: assigned_to_user_id)
|
|
|
|
assigned_at = TopicCustomField.where(
|
|
topic_id: object.topic.id,
|
|
name: "assigned_to_id"
|
|
).pluck(:created_at).first
|
|
|
|
{
|
|
username: user.username,
|
|
name: user.name,
|
|
avatar_template: user.avatar_template,
|
|
assigned_at: assigned_at
|
|
}
|
|
end
|
|
end
|
|
|
|
def include_assigned_to_user?
|
|
if SiteSetting.assigns_public || scope.is_staff?
|
|
assigned_to_user_id
|
|
end
|
|
end
|
|
|
|
def assigned_to_user_id
|
|
id = object.topic.custom_fields["assigned_to_id"]
|
|
# a bit messy but race conditions can give us an array here, avoid
|
|
id && id.to_i rescue nil
|
|
end
|
|
end
|
|
|
|
DiscourseAssign::Engine.routes.draw do
|
|
put "/assign" => "assign#assign"
|
|
put "/unassign" => "assign#unassign"
|
|
end
|
|
|
|
Discourse::Application.routes.append do
|
|
mount ::DiscourseAssign::Engine, at: "/assign"
|
|
end
|
|
|
|
end
|
|
end
|