Merge pull request #2537 from ligthyear/group-member-management-on-user

Improved Group Member Management on User Administration
This commit is contained in:
Robin Ward 2014-07-17 11:00:05 -04:00
commit f06f8abedd
9 changed files with 103 additions and 9 deletions

View file

@ -0,0 +1,34 @@
export default Ember.Component.extend({
tagName: 'div',
didInsertElement: function(){
this.$("input").select2({
multiple: true,
width: '100%',
query: function(opts){
opts.callback({
results: this.get("available").map(this._format)
});
}.bind(this)
}).on("change", function(evt) {
if (evt.added){
this.triggerAction({action: "groupAdded",
actionContext: this.get("available"
).findBy("id", evt.added.id)});
} else if (evt.removed) {
this.triggerAction({action:"groupRemoved",
actionContext: this.get("selected"
).findBy("id", evt.removed.id)});
}
}.bind(this));
this._refreshOnReset();
},
_format: function(item){
return {"text": item.name, "id": item.id, "locked": item.automatic};
},
_refreshOnReset: function() {
this.$("input").select2("data", this.get("selected").map(this._format));
}.observes("selected")
});

View file

@ -25,6 +25,10 @@ Discourse.AdminUserIndexController = Discourse.ObjectController.extend({
primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'primary_group_id'), primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'primary_group_id'),
custom_groups: Ember.computed.filter("model.groups", function(g){
return (!g.automatic && g.visible);
}),
actions: { actions: {
toggleTitleEdit: function() { toggleTitleEdit: function() {
this.toggleProperty('editingTitle'); this.toggleProperty('editingTitle');
@ -45,6 +49,18 @@ Discourse.AdminUserIndexController = Discourse.ObjectController.extend({
this.get('model').generateApiKey(); this.get('model').generateApiKey();
}, },
groupAdded: function(added){
this.get('model').groupAdded(added).catch(function() {
bootbox.alert(I18n.t('generic_error'));
});
},
groupRemoved: function(removed){
this.get('model').groupRemoved(removed).catch(function() {
bootbox.alert(I18n.t('generic_error'));
});
},
savePrimaryGroup: function() { savePrimaryGroup: function() {
var self = this; var self = this;
Discourse.ajax("/admin/users/" + this.get('id') + "/primary_group", { Discourse.ajax("/admin/users/" + this.get('id') + "/primary_group", {

View file

@ -23,6 +23,25 @@ Discourse.AdminUser = Discourse.User.extend({
}); });
}, },
groupAdded: function(added){
var self = this;
return Discourse.ajax("/admin/users/" + this.get('id') + "/groups", {
type: 'POST',
data: {group_id: added.id}
}).then(function () {
self.get('groups').pushObject(added);
});
},
groupRemoved: function(removed){
var self = this;
return Discourse.ajax("/admin/users/" + this.get('id') + "/groups/" + removed.id, {
type: 'DELETE'
}).then(function () {
self.set('groups.[]', self.get('groups').rejectBy("id", removed.id));
});
},
/** /**
Revokes a user's current API key Revokes a user's current API key

View file

@ -23,6 +23,11 @@ Discourse.AdminUserRoute = Discourse.Route.extend({
afterModel: function(adminUser) { afterModel: function(adminUser) {
var controller = this.controllerFor('adminUser'); var controller = this.controllerFor('adminUser');
Discourse.Group.findAll().then(function(groups){
controller.set("availableGroups", groups.filterBy("automatic", false));
}.bind(this));
return adminUser.loadDetails().then(function () { return adminUser.loadDetails().then(function () {
adminUser.setOriginalTrustLevel(); adminUser.setOriginalTrustLevel();
controller.set('model', adminUser); controller.set('model', adminUser);

View file

@ -53,20 +53,18 @@
</div> </div>
<div class='display-row'> <div class='display-row'>
<div class='field'>{{i18n admin.groups.primary}}</div> <div class='field'>{{i18n admin.groups.title}}</div>
<div class='value'> <div class='value'>
{{#if custom_groups}} {{admin-group-selector selected=model.groups available=availableGroups}}
{{combo-box content=custom_groups value=primary_group_id nameProperty="name" none="admin.groups.no_primary"}}
{{else}}
&mdash;
{{/if}}
</div> </div>
<div class='controls'> <div class='controls'>
{{#if custom_groups}}
{{i18n admin.groups.primary}}
{{combo-box content=custom_groups value=primary_group_id nameProperty="name" none="admin.groups.no_primary"}}
{{/if}}
{{#if primaryGroupDirty}} {{#if primaryGroupDirty}}
<div>
<button class='btn ok no-text' {{action savePrimaryGroup}}><i class='fa fa-check'></i></button> <button class='btn ok no-text' {{action savePrimaryGroup}}><i class='fa fa-check'></i></button>
<button class='btn cancel no-text' {{action resetPrimaryGroup}}><i class='fa fa-times'></i></button> <button class='btn cancel no-text' {{action resetPrimaryGroup}}><i class='fa fa-times'></i></button>
</div>
{{/if}} {{/if}}
</div> </div>
</div> </div>

View file

@ -0,0 +1,3 @@
<input type="text">

View file

@ -17,6 +17,8 @@ class Admin::UsersController < Admin::AdminController
:block, :block,
:unblock, :unblock,
:trust_level, :trust_level,
:add_group,
:remove_group,
:primary_group, :primary_group,
:generate_api_key, :generate_api_key,
:revoke_api_key] :revoke_api_key]
@ -101,6 +103,21 @@ class Admin::UsersController < Admin::AdminController
render_serialized(@user, AdminUserSerializer) render_serialized(@user, AdminUserSerializer)
end end
def add_group
group = Group.find(params[:group_id].to_i)
return render_json_error group unless group && !group.automatic
group.users << @user
render nothing: true
end
def remove_group
group = Group.find(params[:group_id].to_i)
return render_json_error group unless group && !group.automatic
group.users.delete(@user)
render nothing: true
end
def primary_group def primary_group
guardian.ensure_can_change_primary_group!(@user) guardian.ensure_can_change_primary_group!(@user)
@user.primary_group_id = params[:primary_group_id] @user.primary_group_id = params[:primary_group_id]

View file

@ -22,7 +22,7 @@ class AdminDetailedUserSerializer < AdminUserSerializer
has_one :api_key, serializer: ApiKeySerializer, embed: :objects has_one :api_key, serializer: ApiKeySerializer, embed: :objects
has_one :suspended_by, serializer: BasicUserSerializer, embed: :objects has_one :suspended_by, serializer: BasicUserSerializer, embed: :objects
has_one :leader_requirements, serializer: LeaderRequirementsSerializer, embed: :objects has_one :leader_requirements, serializer: LeaderRequirementsSerializer, embed: :objects
has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer has_many :groups, embed: :object, serializer: BasicGroupSerializer
def can_revoke_admin def can_revoke_admin
scope.can_revoke_admin?(object) scope.can_revoke_admin?(object)

View file

@ -70,6 +70,8 @@ Discourse::Application.routes.draw do
put "unblock" put "unblock"
put "trust_level" put "trust_level"
put "primary_group" put "primary_group"
post "groups" => "users#add_group", constraints: AdminConstraint.new
delete "groups/:group_id" => "users#remove_group", constraints: AdminConstraint.new
get "badges" get "badges"
get "leader_requirements" get "leader_requirements"
end end