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}"