mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-01 23:37:43 +03:00
Merge pull request #3436 from novaugust/user-role-dropdown
User role dropdown
This commit is contained in:
commit
ed788ef723
13
ghost/admin/components/gh-role-selector.js
Normal file
13
ghost/admin/components/gh-role-selector.js
Normal file
@ -0,0 +1,13 @@
|
||||
import GhostSelect from 'ghost/components/gh-select';
|
||||
|
||||
var RolesSelector = GhostSelect.extend({
|
||||
roles: Ember.computed.alias('options'),
|
||||
options: Ember.computed(function () {
|
||||
var rolesPromise = this.store.find('role', { permissions: 'assign' });
|
||||
|
||||
return Ember.ArrayProxy.extend(Ember.PromiseProxyMixin)
|
||||
.create({promise: rolesPromise});
|
||||
})
|
||||
});
|
||||
|
||||
export default RolesSelector;
|
69
ghost/admin/components/gh-select.js
Normal file
69
ghost/admin/components/gh-select.js
Normal file
@ -0,0 +1,69 @@
|
||||
//GhostSelect is a solution to Ember.Select being evil and worthless.
|
||||
// (Namely, this solves problems with async data in Ember.Select)
|
||||
//Inspired by (that is, totally ripped off from) this JSBin
|
||||
//http://emberjs.jsbin.com/rwjblue/40/edit
|
||||
|
||||
//Usage:
|
||||
//Extend this component and create a template for your component.
|
||||
//Your component must define the `options` property.
|
||||
//Optionally use `initialValue` to set the object
|
||||
// you want to have selected to start with.
|
||||
//Both options and initalValue are promise safe.
|
||||
//Set onChange in your template to be the name
|
||||
// of the action you want called in your
|
||||
//For an example, see gh-roles-selector
|
||||
|
||||
var GhostSelect = Ember.Component.extend({
|
||||
tagName: 'span',
|
||||
classNames: ['gh-select'],
|
||||
|
||||
options: null,
|
||||
initialValue: null,
|
||||
|
||||
resolvedOptions: null,
|
||||
resolvedInitialValue: null,
|
||||
|
||||
//Convert promises to their values
|
||||
init: function () {
|
||||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
Ember.RSVP.hash({
|
||||
resolvedOptions: this.get('options'),
|
||||
resolvedInitialValue: this.get('initialValue')
|
||||
}).then(function (resolvedHash) {
|
||||
self.setProperties(resolvedHash);
|
||||
|
||||
//Run after render to ensure the <option>s have rendered
|
||||
Ember.run.schedule('afterRender', function () {
|
||||
self.setInitialValue();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setInitialValue: function () {
|
||||
var initialValue = this.get('resolvedInitialValue'),
|
||||
options = this.get('resolvedOptions'),
|
||||
initialValueIndex = options.indexOf(initialValue);
|
||||
if (initialValueIndex > -1) {
|
||||
this.$('option:eq(' + initialValueIndex + ')').prop('selected', true);
|
||||
}
|
||||
},
|
||||
//Called by DOM events, weee!
|
||||
change: function () {
|
||||
this._changeSelection();
|
||||
},
|
||||
//Send value to specified action
|
||||
_changeSelection: function () {
|
||||
var value = this._selectedValue();
|
||||
Ember.set(this, 'value', value);
|
||||
this.sendAction('onChange', value);
|
||||
},
|
||||
_selectedValue: function () {
|
||||
var selectedIndex = this.$('select')[0].selectedIndex;
|
||||
|
||||
return this.get('options').objectAt(selectedIndex);
|
||||
}
|
||||
});
|
||||
|
||||
export default GhostSelect;
|
@ -1,5 +1,15 @@
|
||||
var InviteNewUserController = Ember.Controller.extend({
|
||||
|
||||
//Used to set the initial value for the dropdown
|
||||
authorRole: Ember.computed(function () {
|
||||
var self = this;
|
||||
return this.store.find('role').then(function (roles) {
|
||||
var authorRole = roles.findBy('name', 'Author');
|
||||
//Initialize role as well.
|
||||
self.set('role', authorRole);
|
||||
return authorRole;
|
||||
});
|
||||
}),
|
||||
|
||||
confirm: {
|
||||
accept: {
|
||||
text: 'send invitation now'
|
||||
@ -8,45 +18,23 @@ var InviteNewUserController = Ember.Controller.extend({
|
||||
buttonClass: 'hidden'
|
||||
}
|
||||
},
|
||||
|
||||
roles: Ember.computed(function () {
|
||||
var roles = {},
|
||||
self = this;
|
||||
|
||||
roles.promise = this.store.find('role', { permissions: 'assign' }).then(function (roles) {
|
||||
return roles.rejectBy('name', 'Owner').sortBy('id');
|
||||
}).then(function (roles) {
|
||||
// After the promise containing the roles has been resolved and the array
|
||||
// has been sorted, explicitly set the selectedRole for the Ember.Select.
|
||||
// The explicit set is needed because the data-select-text attribute is
|
||||
// not being set until a change is made in the dropdown list.
|
||||
// This is only required with Ember.Select when it is bound to async data.
|
||||
self.set('selectedRole', roles.get('firstObject'));
|
||||
|
||||
return roles;
|
||||
});
|
||||
|
||||
return Ember.ArrayProxy.extend(Ember.PromiseProxyMixin).create(roles);
|
||||
}),
|
||||
|
||||
|
||||
actions: {
|
||||
setRole: function (role) {
|
||||
this.set('role', role);
|
||||
},
|
||||
confirmAccept: function () {
|
||||
var email = this.get('email'),
|
||||
role_id = this.get('role'),
|
||||
role = this.get('role'),
|
||||
self = this,
|
||||
newUser,
|
||||
role;
|
||||
newUser;
|
||||
|
||||
newUser = self.store.createRecord('user', {
|
||||
email: email,
|
||||
status: 'invited'
|
||||
status: 'invited',
|
||||
role: role
|
||||
});
|
||||
|
||||
// no need to make an API request, the store will already have this role
|
||||
role = self.store.getById('role', role_id);
|
||||
|
||||
newUser.get('roles').pushObject(role);
|
||||
|
||||
newUser.save().then(function () {
|
||||
var notificationText = 'Invitation sent! (' + email + ')';
|
||||
|
||||
|
@ -36,7 +36,6 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
var lastLogin = this.get('user.last_login');
|
||||
|
||||
return lastLogin ? lastLogin.fromNow() : '';
|
||||
|
||||
}.property('user.last_login'),
|
||||
|
||||
created_at: function () {
|
||||
@ -44,12 +43,11 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
|
||||
return createdAt ? createdAt.fromNow() : '';
|
||||
}.property('user.created_at'),
|
||||
|
||||
isAuthor: function () {
|
||||
return this.get('user.isAuthor');
|
||||
}.property('user.isAuthor'),
|
||||
|
||||
|
||||
actions: {
|
||||
changeRole: function (newRole) {
|
||||
this.set('model.role', newRole);
|
||||
},
|
||||
revoke: function () {
|
||||
var self = this,
|
||||
email = this.get('email');
|
||||
|
10
ghost/admin/initializers/store-injector.js
Normal file
10
ghost/admin/initializers/store-injector.js
Normal file
@ -0,0 +1,10 @@
|
||||
//Used to surgically insert the store into things that wouldn't normally have them.
|
||||
var StoreInjector = {
|
||||
name: 'store-injector',
|
||||
after: 'store',
|
||||
initialize: function (container, application) {
|
||||
application.inject('component:gh-role-selector', 'store', 'store:main');
|
||||
}
|
||||
};
|
||||
|
||||
export default StoreInjector;
|
@ -26,18 +26,22 @@ var User = DS.Model.extend(NProgressSaveMixin, SelectiveSaveMixin, ValidationEng
|
||||
updated_by: DS.attr('number'),
|
||||
roles: DS.hasMany('role', { embedded: 'always' }),
|
||||
|
||||
|
||||
// TODO: Once client-side permissions are in place,
|
||||
// remove the hard role check.
|
||||
isAuthor: Ember.computed('roles', function () {
|
||||
return this.get('roles').objectAt(0).get('name').toLowerCase() === 'author';
|
||||
role: Ember.computed('roles', function (name, value) {
|
||||
if (arguments.length > 1) {
|
||||
//Only one role per user, so remove any old data.
|
||||
this.get('roles').clear();
|
||||
this.get('roles').pushObject(value);
|
||||
return value;
|
||||
}
|
||||
return this.get('roles.firstObject');
|
||||
}),
|
||||
|
||||
// TODO: Once client-side permissions are in place,
|
||||
// remove the hard role check.
|
||||
isEditor: Ember.computed('roles', function () {
|
||||
return this.get('roles').objectAt(0).get('name').toLowerCase() === 'editor';
|
||||
}),
|
||||
isAuthor: Ember.computed.equal('role.name', 'Author'),
|
||||
isEditor: Ember.computed.equal('role.name', 'Editor'),
|
||||
isAdmin: Ember.computed.equal('role.name', 'Administrator'),
|
||||
isOwner: Ember.computed.equal('role.name', 'Owner'),
|
||||
|
||||
saveNewPassword: function () {
|
||||
var url = this.get('ghostPaths.url').api('users', 'password');
|
||||
|
5
ghost/admin/templates/components/gh-role-selector.hbs
Normal file
5
ghost/admin/templates/components/gh-role-selector.hbs
Normal file
@ -0,0 +1,5 @@
|
||||
<select {{bind-attr id=selectId name=selectName}}>
|
||||
{{#each roles}}
|
||||
<option {{bind-attr value=id}}>{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
@ -10,16 +10,10 @@
|
||||
|
||||
<div class="form-group for-select">
|
||||
<label for="new-user-role">Role</label>
|
||||
<span class="gh-select" {{bind-attr data-select-text=selectedRole.name}}>
|
||||
{{view Ember.Select
|
||||
content=roles
|
||||
id="new-user-role"
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
name="role"
|
||||
value=role
|
||||
selection=selectedRole}}
|
||||
</span>
|
||||
{{gh-role-selector
|
||||
initialValue=authorRole
|
||||
onChange="setRole"
|
||||
selectId="new-user-role"}}
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
@ -67,23 +67,16 @@
|
||||
{{input type="email" value=user.email id="user-email" placeholder="Email Address" autocapitalize="off" autocorrect="off" autocomplete="off"}}
|
||||
<p>Used for notifications</p>
|
||||
</div>
|
||||
|
||||
{{!-- The correct markup for select boxes. Needs changing to the correct data --}}
|
||||
{{!-- <div class="form-group">
|
||||
{{#if view.rolesDropdownIsVisible}}
|
||||
<div class="form-group">
|
||||
<label for="user-role">Role</label>
|
||||
<span class="gh-select">
|
||||
{{view Ember.Select
|
||||
id="activeTheme"
|
||||
name="general[activeTheme]"
|
||||
content=themes
|
||||
optionValuePath="content.name"
|
||||
optionLabelPath="content.label"
|
||||
value=activeTheme
|
||||
selection=selectedTheme}}
|
||||
</span>
|
||||
{{gh-role-selector
|
||||
initialValue=role
|
||||
onChange="changeRole"
|
||||
selectId="user-role"}}
|
||||
<p>What permissions should this user have?</p>
|
||||
</div> --}}
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="form-group">
|
||||
<label for="user-location">Location</label>
|
||||
{{input type="text" value=user.location id="user-location"}}
|
||||
|
13
ghost/admin/views/settings/users/user.js
Normal file
13
ghost/admin/views/settings/users/user.js
Normal file
@ -0,0 +1,13 @@
|
||||
var SettingsUserView = Ember.View.extend({
|
||||
currentUser: Ember.computed.alias('controller.session.user'),
|
||||
|
||||
isNotOwnProfile: Ember.computed('controller.user.id', 'currentUser.id', function () {
|
||||
return this.get('controller.user.id') !== this.get('currentUser.id');
|
||||
}),
|
||||
|
||||
canAssignRoles: Ember.computed.or('currentUser.isAdmin', 'currentUser.isOwner'),
|
||||
|
||||
rolesDropdownIsVisible: Ember.computed.and('isNotOwnProfile', 'canAssignRoles')
|
||||
});
|
||||
|
||||
export default SettingsUserView;
|
Loading…
Reference in New Issue
Block a user