diff --git a/app/controllers/discourse_assign/assign_controller.rb b/app/controllers/discourse_assign/assign_controller.rb
index fe73720..7df479a 100644
--- a/app/controllers/discourse_assign/assign_controller.rb
+++ b/app/controllers/discourse_assign/assign_controller.rb
@@ -25,7 +25,7 @@ module DiscourseAssign
render json: {
assign_allowed_on_groups: Group.visible_groups(current_user).assign_allowed_groups.pluck(:name),
- assign_allowed_for_groups: Group.visible_groups(current_user).messageable(current_user).pluck(:name),
+ assign_allowed_for_groups: Group.visible_groups(current_user).assignable(current_user).pluck(:name),
suggestions: ActiveModel::ArraySerializer.new(users, scope: guardian, each_serializer: BasicUserSerializer),
}
end
diff --git a/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.hbs b/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.hbs
new file mode 100644
index 0000000..b3647a8
--- /dev/null
+++ b/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.hbs
@@ -0,0 +1,13 @@
+
+
+
+
+ {{combo-box
+ name="alias"
+ valueProperty="value"
+ value=assignableLevel
+ content=assignableLevelOptions
+ class="groups-form-assignable-level"
+ onChange=(action (mut model.assignable_level))
+ }}
+
diff --git a/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.js.es6 b/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.js.es6
new file mode 100644
index 0000000..ddbcf30
--- /dev/null
+++ b/assets/javascripts/discourse-assign/connectors/groups-interaction-custom-options/assignable-interaction-fields.js.es6
@@ -0,0 +1,24 @@
+import I18n from "I18n";
+import { or } from "@ember/object/computed";
+import { defineProperty } from "@ember/object";
+
+export default {
+ name: "assignable-interaction-fields",
+
+ setupComponent(args, component) {
+ this.assignableLevelOptions = [
+ { name: I18n.t("groups.alias_levels.nobody"), value: 0 },
+ { name: I18n.t("groups.alias_levels.only_admins"), value: 1 },
+ { name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 },
+ { name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 },
+ { name: I18n.t("groups.alias_levels.owners_mods_and_admins"), value: 4 },
+ { name: I18n.t("groups.alias_levels.everyone"), value: 99 },
+ ];
+
+ defineProperty(
+ component,
+ "assignableLevel",
+ or("model.assignable_level", "assignableLevelOptions.firstObject.value")
+ );
+ },
+};
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 6c45c96..e361a7b 100644
--- a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
+++ b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
@@ -273,6 +273,14 @@ function initialize(api) {
},
});
+ api.modifyClass("model:group", {
+ asJSON() {
+ return Object.assign({}, this._super(...arguments), {
+ assignable_level: this.assignable_level,
+ });
+ },
+ });
+
api.modifyClass("controller:topic", {
pluginId: PLUGIN_ID,
@@ -442,5 +450,8 @@ export default {
api.addGroupPostSmallActionCode("assigned_group");
api.addGroupPostSmallActionCode("unassigned_group");
});
+ withPluginApi("0.12.3", (api) => {
+ api.addUserSearchOption("assignableGroups");
+ });
},
};
diff --git a/assets/javascripts/discourse/templates/modal/assign-user.hbs b/assets/javascripts/discourse/templates/modal/assign-user.hbs
index dcf847c..4a89eca 100644
--- a/assets/javascripts/discourse/templates/modal/assign-user.hbs
+++ b/assets/javascripts/discourse/templates/modal/assign-user.hbs
@@ -9,8 +9,8 @@
options=(hash
placementStrategy="absolute"
filterPlaceholder=placeholderKey
- includeGroups=false
- includeMessageableGroups=true
+ includeGroups=true
+ assignableGroups=true
groupMembersOf=allowedGroups
maximum=1
autofocus=autofocus
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index aa5b216..ede5320 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -47,6 +47,13 @@ en:
weekly: "Weekly"
monthly: "Monthly"
quarterly: "Quarterly"
+ admin:
+ groups:
+ manage:
+ interaction:
+ assign: "Assign"
+ assignable_levels:
+ title: "Who can assign this group"
user:
messages:
assigned_title: "Assigned (%{count})"
diff --git a/db/migrate/20210830024453_add_assignable_level_to_groups.rb b/db/migrate/20210830024453_add_assignable_level_to_groups.rb
new file mode 100644
index 0000000..01118ef
--- /dev/null
+++ b/db/migrate/20210830024453_add_assignable_level_to_groups.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddAssignableLevelToGroups < ActiveRecord::Migration[6.1]
+ def change
+ add_column :groups, :assignable_level, :integer, default: 0, null: false
+ end
+end
diff --git a/lib/topic_assigner.rb b/lib/topic_assigner.rb
index 13067a9..c0d914b 100644
--- a/lib/topic_assigner.rb
+++ b/lib/topic_assigner.rb
@@ -126,7 +126,7 @@ class ::TopicAssigner
end
def allowed_group_ids
- @allowed_group_ids ||= Group.messageable(@assigned_by).pluck(:id)
+ @allowed_group_ids ||= Group.assignable(@assigned_by).pluck(:id)
end
def can_assign_to?(assign_to)
diff --git a/plugin.rb b/plugin.rb
index 3d0ff41..413bbb4 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -36,10 +36,33 @@ after_initialize do
require 'topic_assigner'
require 'pending_assigns_reminder'
+ # TODO: Drop when Discourse stable 2.8.0 is released
+ if respond_to?(:register_group_param)
+ register_group_param(:assignable_level)
+ end
+ if respond_to?(:register_groups_callback_for_users_search_controller_action)
+ register_groups_callback_for_users_search_controller_action(:assignable_groups) do |groups, user|
+ groups.assignable(user)
+ end
+ end
+
class ::Topic
has_one :assignment, dependent: :destroy
end
+ class ::Group
+ scope :assignable, ->(user) {
+ where("assignable_level in (:levels) OR
+ (
+ assignable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in (
+ SELECT group_id FROM group_users WHERE user_id = :user_id)
+ ) OR (
+ assignable_level = #{ALIAS_LEVELS[:owners_mods_and_admins]} AND id in (
+ SELECT group_id FROM group_users WHERE user_id = :user_id AND owner IS TRUE)
+ )", levels: alias_levels(user), user_id: user && user.id)
+ }
+ end
+
frequency_field = PendingAssignsReminder::REMINDERS_FREQUENCY
register_editable_user_custom_field frequency_field
User.register_custom_field_type frequency_field, :integer
@@ -73,6 +96,10 @@ after_initialize do
scope.can_assign?
end
+ add_to_serializer(:group_show, :assignable_level) do
+ object.assignable_level
+ end
+
add_to_serializer(:group_show, :can_show_assigned_tab?) do
object.can_show_assigned_tab?
end
diff --git a/spec/serializers/group_show_serializer_spec.rb b/spec/serializers/group_show_serializer_spec.rb
index 0a1a23d..1e2aaff 100644
--- a/spec/serializers/group_show_serializer_spec.rb
+++ b/spec/serializers/group_show_serializer_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe GroupShowSerializer do
fab!(:user) { Fabricate(:user) }
- fab!(:group) { Fabricate(:group, messageable_level: Group::ALIAS_LEVELS[:everyone]) }
+ fab!(:group) { Fabricate(:group, assignable_level: Group::ALIAS_LEVELS[:everyone]) }
fab!(:group_user) { Fabricate(:group_user, group: group, user: user) }
fab!(:topic) { Fabricate(:topic) }
fab!(:post) { Fabricate(:post, topic: topic) }
diff --git a/spec/support/assign_allowed_group.rb b/spec/support/assign_allowed_group.rb
index 92e3fb0..2855278 100644
--- a/spec/support/assign_allowed_group.rb
+++ b/spec/support/assign_allowed_group.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
shared_context 'A group that is allowed to assign' do
- fab!(:assign_allowed_group) { Fabricate(:group, messageable_level: Group::ALIAS_LEVELS[:everyone]) }
+ fab!(:assign_allowed_group) { Fabricate(:group, assignable_level: Group::ALIAS_LEVELS[:everyone]) }
before do
SiteSetting.assign_allowed_on_groups += "|#{assign_allowed_group.id}"