From c743a985a415b4701a86538b99b98be78a2b8d92 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 23 Dec 2013 15:46:00 +0100 Subject: [PATCH 1/2] Allow groups to be used as aliases for user mention when configured by the admin a group can be found through the @mentions feature in both the compose/reply and the private message user-selectors and once selected the mention will be replaced by the list of users in the group --- app/assets/javascripts/admin/models/group.js | 12 +++++++ .../admin/templates/groups.js.handlebars | 20 +++++++---- .../javascripts/discourse/lib/autocomplete.js | 23 +++++++----- .../javascripts/discourse/lib/user_search.js | 30 ++++++++++++---- .../templates/composer.js.handlebars | 1 + .../modal/invite_private.js.handlebars | 2 +- .../discourse/views/composer/composer_view.js | 11 ++++-- .../discourse/views/user_selector_view.js | 35 ++++++++++++++++--- app/controllers/admin/groups_controller.rb | 16 +++++---- app/controllers/users_controller.rb | 8 ++++- app/models/group.rb | 17 +++++++++ app/serializers/basic_group_serializer.rb | 2 +- config/locales/client.en.yml | 8 ++++- ...0140102104229_add_alias_level_to_groups.rb | 5 +++ .../admin/groups_controller_spec.rb | 3 +- 15 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 db/migrate/20140102104229_add_alias_level_to_groups.rb diff --git a/app/assets/javascripts/admin/models/group.js b/app/assets/javascripts/admin/models/group.js index ce556edd88f..55b4da0e4cf 100644 --- a/app/assets/javascripts/admin/models/group.js +++ b/app/assets/javascripts/admin/models/group.js @@ -35,6 +35,16 @@ Discourse.Group = Discourse.Model.extend({ return usernames; }.property('users'), + validValues: function() { + return Em.A([ + { name: I18n.t("admin.groups.alias_levels.nobody"), value: 0}, + { name: I18n.t("admin.groups.alias_levels.only_admins"), value: 1}, + { name: I18n.t("admin.groups.alias_levels.mods_and_admins"), value: 2}, + { name: I18n.t("admin.groups.alias_levels.members_mods_and_admins"), value: 3}, + { name: I18n.t("admin.groups.alias_levels.everyone"), value: 99} + ]); + }.property(), + destroy: function(){ if(!this.id) return; @@ -58,6 +68,7 @@ Discourse.Group = Discourse.Model.extend({ return Discourse.ajax("/admin/groups", {type: "POST", data: { group: { name: this.get('name'), + alias_level: this.get('alias_level'), usernames: this.get('usernames') } }}).then(function(resp) { @@ -83,6 +94,7 @@ Discourse.Group = Discourse.Model.extend({ data: { group: { name: this.get('name'), + alias_level: this.get('alias_level'), usernames: this.get('usernames') } }, diff --git a/app/assets/javascripts/admin/templates/groups.js.handlebars b/app/assets/javascripts/admin/templates/groups.js.handlebars index cfff5e5a2ce..79b3c66104c 100644 --- a/app/assets/javascripts/admin/templates/groups.js.handlebars +++ b/app/assets/javascripts/admin/templates/groups.js.handlebars @@ -24,15 +24,23 @@ {{textField value=name placeholderKey="admin.groups.name_placeholder"}} {{/if}} - {{userSelector usernames=usernames id="group-users" placeholderKey="admin.groups.selector_placeholder" tabindex="1" disabledBinding="automatic"}} +
+ +
+ {{userSelector usernames=usernames id="group-users" placeholderKey="admin.groups.selector_placeholder" tabindex="1" disabledBinding="automatic"}} +
+
+
+ +
+ {{combobox valueAttribute="value" value=alias_level content=validValues}} +
+
+ {{#unless automatic}} - - {{#if id}} {{i18n admin.customize.delete}} - {{/if}} - {{else}} - {{i18n admin.groups.can_not_edit_automatic}} {{/unless}}
{{/with}} diff --git a/app/assets/javascripts/discourse/lib/autocomplete.js b/app/assets/javascripts/discourse/lib/autocomplete.js index 33d3715a1eb..9f65d6b99ae 100644 --- a/app/assets/javascripts/discourse/lib/autocomplete.js +++ b/app/assets/javascripts/discourse/lib/autocomplete.js @@ -92,19 +92,26 @@ $.fn.autocomplete = function(options) { // dump what we have in single mode, just in case inputSelectedItems = []; } - var d = $("
" + (transformed || item) + "
"); - var prev = me.parent().find('.item:last'); - if (prev.length === 0) { - me.parent().prepend(d); - } else { - prev.after(d); + if (!_.isArray(transformed)) { + transformed = [transformed || item]; } - inputSelectedItems.push(item); + var divs = transformed.map(function(itm) { + var d = $("
" + (itm) + "
"); + var prev = me.parent().find('.item:last'); + if (prev.length === 0) { + me.parent().prepend(d); + } else { + prev.after(d); + } + inputSelectedItems.push(itm); + return divs; + }); + if (options.onChangeItems) { options.onChangeItems(inputSelectedItems); } - d.find('a').click(function() { + $(divs).find('a').click(function() { closeAutocomplete(); inputSelectedItems.splice($.inArray(item, inputSelectedItems), 1); $(this).parent().parent().remove(); diff --git a/app/assets/javascripts/discourse/lib/user_search.js b/app/assets/javascripts/discourse/lib/user_search.js index 3a8aae6dd29..c0a11c80f70 100644 --- a/app/assets/javascripts/discourse/lib/user_search.js +++ b/app/assets/javascripts/discourse/lib/user_search.js @@ -9,11 +9,12 @@ var cache = {}; var cacheTopicId = null; var cacheTime = null; -var debouncedSearch = Discourse.debouncePromise(function(term, topicId) { +var debouncedSearch = Discourse.debouncePromise(function(term, topicId, include_groups) { return Discourse.ajax('/users/search/users', { data: { term: term, - topic_id: topicId + topic_id: topicId, + include_groups: include_groups } }).then(function (r) { cache[term] = r; @@ -26,6 +27,7 @@ Discourse.UserSearch = { search: function(options) { var term = options.term || ""; + var include_groups = options.include_groups || false; var exclude = options.exclude || []; var topicId = options.topicId; var limit = options.limit || 5; @@ -46,21 +48,35 @@ Discourse.UserSearch = { cacheTopicId = topicId; var organizeResults = function(r) { - var result = []; + var users = [], groups = [], results = []; _.each(r.users,function(u) { if (exclude.indexOf(u.username) === -1) { - result.push(u); + users.push(u); + results.push(u); } - if (result.length > limit) return false; + if (results.length > limit) return false; return true; }); - promise.resolve(result); + + _.each(r.groups,function(g) { + if (results.length > limit) return false; + if (exclude.indexOf(g.name) === -1) { + groups.push(g); + results.push(g); + } + return true; + }); + + results.users = users; + results.groups = groups; + + promise.resolve(results); }; if (cache[term]) { organizeResults(cache[term]); } else { - debouncedSearch(term, topicId).then(organizeResults); + debouncedSearch(term, topicId, include_groups).then(organizeResults); } return promise; } diff --git a/app/assets/javascripts/discourse/templates/composer.js.handlebars b/app/assets/javascripts/discourse/templates/composer.js.handlebars index c188611cc0f..d0c8c9bb457 100644 --- a/app/assets/javascripts/discourse/templates/composer.js.handlebars +++ b/app/assets/javascripts/discourse/templates/composer.js.handlebars @@ -28,6 +28,7 @@ {{userSelector topicId=controller.controllers.topic.model.id excludeCurrentUser="true" id="private-message-users" + include_groups="true" class="span8" placeholderKey="composer.users_placeholder" tabindex="1" diff --git a/app/assets/javascripts/discourse/templates/modal/invite_private.js.handlebars b/app/assets/javascripts/discourse/templates/modal/invite_private.js.handlebars index a427dc0acd3..4fab3aa1836 100644 --- a/app/assets/javascripts/discourse/templates/modal/invite_private.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/invite_private.js.handlebars @@ -10,7 +10,7 @@ {{i18n topic.invite_private.success}} {{else}} - {{userSelector single=true allowAny=true usernames=emailOrUsername placeholderKey="topic.invite_private.email_or_username_placeholder"}} + {{userSelector single=true allowAny=true usernames=emailOrUsername include_groups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}} {{/if}}