FEATURE: assign to post (#224)

FEATURE: assign to post (#224)

Ability to assign an individual post to a user or group

diff --git a/app/controllers/discourse_assign/assign_controller.rb b/app/controllers/discourse_assign/assign_controller.rb
index c41cf55..8dbcd7c 100644
--- a/app/controllers/discourse_assign/assign_controller.rb
+++ b/app/controllers/discourse_assign/assign_controller.rb
@@ -133,24 +133,24 @@ module DiscourseAssign
         SQL
       end
 
-      group_assignment_count = Topic
-        .joins("JOIN assignments a ON a.target_id = topics.id AND a.target_type = 'Topic'")
+      group_assignments = Topic
+        .joins("JOIN assignments a ON a.topic_id = topics.id")
         .where(<<~SQL, group_id: group.id)
           a.assigned_to_id = :group_id AND a.assigned_to_type = 'Group'
         SQL
-        .count
+        .pluck(:topic_id)
 
-      assignment_count = Topic
-        .joins("JOIN assignments a ON a.target_id = topics.id AND a.target_type = 'Topic'")
+      assignments = Topic
+        .joins("JOIN assignments a ON a.topic_id = topics.id")
         .joins("JOIN group_users ON group_users.user_id = a.assigned_to_id ")
         .where("group_users.group_id = ?", group.id)
         .where("a.assigned_to_type = 'User'")
-        .count
+        .pluck(:topic_id)
 
       render json: {
         members: serialize_data(members, GroupUserAssignedSerializer),
-        assignment_count: assignment_count + group_assignment_count,
-        group_assignment_count: group_assignment_count
+        assignment_count: (assignments | group_assignments).count,
+        group_assignment_count: group_assignments.count
       }
     end
 
@@ -174,6 +174,8 @@ module DiscourseAssign
         { error: I18n.t('discourse_assign.forbidden_group_assignee_not_pm_participant', group: assign_to.name) }
       when :forbidden_group_assignee_cant_see_topic
         { error: I18n.t('discourse_assign.forbidden_group_assignee_cant_see_topic', group: assign_to.name) }
+      when :too_many_assigns_for_topic
+        { error: I18n.t('discourse_assign.too_many_assigns_for_topic', limit: Assigner::ASSIGNMENTS_PER_TOPIC_LIMIT) }
       else
         max = SiteSetting.max_assigned_topics
         { error: I18n.t('discourse_assign.too_many_assigns', username: assign_to.username, max: max) }
diff --git a/app/models/assignment.rb b/app/models/assignment.rb
index ac67f17..f687235 100644
--- a/app/models/assignment.rb
+++ b/app/models/assignment.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Assignment < ActiveRecord::Base
-  VALID_TYPES = %w(topic).freeze
+  VALID_TYPES = %w(topic post).freeze
 
   belongs_to :topic
   belongs_to :assigned_to, polymorphic: true
diff --git a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
index f291f94..d89520b 100644
--- a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
+++ b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
@@ -5,6 +5,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
 import { not, or } from "@ember/object/computed";
 import { isEmpty } from "@ember/utils";
 import { action } from "@ember/object";
+import discourseComputed from "discourse-common/utils/decorators";
 
 export default Controller.extend({
   topicBulkActions: controller(),
@@ -38,6 +39,16 @@ export default Controller.extend({
     });
   },
 
+  @discourseComputed("model.targetType")
+  i18nSuffix(targetType) {
+    switch (targetType) {
+      case "Post":
+        return "_post_modal";
+      case "Topic":
+        return "_modal";
+    }
+  },
+
   @action
   assignUser(name) {
     if (this.isBulkAction) {
@@ -73,11 +84,11 @@ export default Controller.extend({
     let path = "/assign/assign";
 
     if (isEmpty(this.get("model.username"))) {
-      this.model.topic.set("assigned_to_user", null);
+      this.model.target.set("assigned_to_user", null);
     }
 
     if (isEmpty(this.get("model.group_name"))) {
-      this.model.topic.set("assigned_to_group", null);
+      this.model.target.set("assigned_to_group", null);
     }
 
     if (
@@ -94,8 +105,8 @@ export default Controller.extend({
       data: {
         username: this.get("model.username"),
         group_name: this.get("model.group_name"),
-        target_id: this.get("model.topic.id"),
-        target_type: "Topic",
+        target_id: this.get("model.target.id"),
+        target_type: this.get("model.targetType"),
       },
     })
       .then(() => {
diff --git a/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6 b/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6
index 93d19b5..d6640e2 100644
--- a/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6
+++ b/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6
@@ -48,9 +48,9 @@ export default UserTopicsList.extend({
   },
 
   @action
-  unassign(topic) {
+  unassign(targetId, targetType = "Topic") {
     this.taskActions
-      .unassign(topic.get("id"))
+      .unassign(targetId, targetType)
       .then(() => this.send("changeAssigned"));
   },
 
diff --git a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
index d32fc27..a5172ae 100644
--- a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
+++ b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
@@ -58,9 +58,9 @@ export default UserTopicsList.extend({
   },
 
   @action
-  unassign(topic) {
+  unassign(targetId, targetType = "Topic") {
     this.taskActions
-      .unassign(topic.get("id"))
+      .unassign(targetId, targetType)
       .then(() => this.send("changeAssigned"));
   },
 
diff --git a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
index ae00c4d..f88ec09 100644
--- a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
+++ b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
@@ -95,7 +95,7 @@ function registerTopicFooterButtons(api) {
       if (topic.assigned_to_user || topic.assigned_to_group) {
         this.set("topic.assigned_to_user", null);
         this.set("topic.assigned_to_group", null);
-        taskActions.unassign(topic.id).then(() => {
+        taskActions.unassign(topic.id, "Topic").then(() => {
           this.appEvents.trigger("post-stream:refresh", {
             id: topic.postStream.firstPostId,
           });
@@ -151,6 +151,38 @@ function initialize(api) {
       },
       before: "top",
     });
+    if (api.getCurrentUser() && api.getCurrentUser().can_assign) {
+      api.addPostMenuButton("assign", (post) => {
+        if (post.firstPost) {
+          return;
+        }
+        if (post.assigned_to_user || post.assigned_to_group) {
+          return {
+            action: "unassignPost",
+            icon: "user-times",
+            className: "unassign-post",
+            title: "discourse_assign.unassign_post.title",
+            position: "second-last-hidden",
+          };
+        } else {
+          return {
+            action: "assignPost",
+            icon: "user-plus",
+            className: "assign-post",
+            title: "discourse_assign.assign_post.title",
+            position: "second-last-hidden",
+          };
+        }
+      });
+      api.attachWidgetAction("post", "assignPost", function () {
+        const taskActions = getOwner(this).lookup("service:task-actions");
+        taskActions.assign(this.model, "Post");
+      });
+      api.attachWidgetAction("post", "unassignPost", function () {
+        const taskActions = getOwner(this).lookup("service:task-actions");
+        taskActions.unassign(this.model.id, "Post");
+      });
+    }
   }
 
   api.addAdvancedSearchOptions(
@@ -170,52 +202,55 @@ function initialize(api) {
       : {}
   );
 
-  api.modifyClass("model:topic", {

[... diff too long, it was truncated ...]

GitHub sha: c396605d2fc18c6d05743ce3ca750ca8a37ba21b

This commit appears in #224 which was approved by eviltrout. It was merged by lis2.

Just Wow! Thank you so much @lis2 !

1 Like