I have an app where users can edit organisations in various 'pages'.
App.Router.map(function() {
this.resource('organisation', {path: '/:orgname'}, function () {
this.route('foo');
this.route('bar');
});
});
I want users to be able to view any organisation but the various pages should become editable if the user has admin rights over the organisation.
Organisations are editable based on some tricky logic handled by the server. The user model has an organisations attribute to reflect these admin rights. This is mirrored in the organisation object. On the server its a many-to-many table plus some other logic.
App.User = DS.Model.extend({
primaryKey: 'username',
fullname: DS.attr('string'),
username: DS.attr('string'),
organisations: DS.hasMany('organisation', {async: true})
});
App.Organisation = DS.Model.extend({
primaryKey: 'orgname',
orgname: DS.attr('string'),
fullname: DS.attr('string', {defaultValue: 'Unnamed Organisation'}),
description: DS.attr('string'),
users: DS.hasMany('user', {async: true}),
});
I am using Ember SimpleAuth to authenticate via a login page and to authorise requests to my API. I use a custom session to load in data for the authenticated user.
var CustomSession = SimpleAuth.Session.extend({
user: function() {
var username = this.get('username');
if (!Ember.isEmpty(username)) {
return this.container.lookup('store:main').find('user', username);
}
}.property('username')
});
I have a controller like this which makes attributes editable in my template.
App.OrganisationController = Ember.Controller.extend({
actions: {
ToggleEditFullname: function() {
this.set('editingFullname', !this.get('editingFullname'));
},
save: function() {
this.set('editingFullname', false);
return true;
}
}
});
So in my template I do something like this...
{{#if editingFullname}}
{{view Ember.TextField valueBinding="model.fullname" placeholder="Full name"}}
<a href="#"><i {{action 'ToggleEditFullname'}} class="fa fa-times" title="cancel"></i></a>
{{else}}
{{#if model.fullname}}
{{model.fullname}}
{{else}}
No name provided...
{{/if}}
{{#if session.isAuthenticated}}
<a href="#"><i {{action 'ToggleEditFullname'}} class="fa fa-pencil" title="edit name"></i></a>
{{/if}}
{{/if}}
The key being the {{#if session.isAuthenticated}}
statement. This ensures that users only get access to the restricted features if they are logged in.
All pretty normal so far (I think).
However, I want to be able to ask my session whether the current user is authorised to access the organisation in question. So I'd like to change the {{#if session.isAuthenticated}}
to {{#if session.isAuthorised}}
and have it check the current model/route against my data.
How can I best do this? Is there a better alternative? How do I protect resources individually?
P.S. Apologies for my English spelling of 'authorized'.
You'd want to compute from each organization so that it will be accurate on a per-model basis. So change
{{#if session.isAuthenticated}}
to
{{#if model.userCanAdminister}}
Then you can compute that straight off the model definition (this is probably not suitable for your async case, but could be workable) as seen here: http://emberjs.com/guides/models/defining-models/#toc_defining-attributes
Or you can do it from the itemController
(how I would do it for async). The logic for that should be pretty simple. Check if the current user is contained in the organization's user collection. Return a boolean from the computed property. Have that property bound to session.isAuthenticated
and then users.@each.content
or whatever might change in the organization in real-time.
Hope that helps!