front/auth: implement privileges + top nav auth

This commit is contained in:
rr- 2016-03-30 22:05:57 +02:00
parent 28c90a25f3
commit d8f11d87e5
5 changed files with 68 additions and 12 deletions

View file

@ -2,11 +2,14 @@
const request = require('superagent');
const config = require('./config.js');
const EventListener = require('./event_listener.js');
class Api {
constructor() {
this.user = null;
this.userName = null;
this.userPassword = null;
this.authenticated = new EventListener();
}
get(url) {
@ -36,9 +39,25 @@ class Api {
});
}
hasPrivilege() {
/* TODO: implement */
return true;
hasPrivilege(lookup) {
let minViableRank = null;
for (let privilege of Object.keys(config.privileges)) {
if (!privilege.startsWith(lookup)) {
continue;
}
const rankName = config.privileges[privilege];
const rankIndex = config.service.userRanks.indexOf(rankName);
if (minViableRank === null || rankIndex < minViableRank) {
minViableRank = rankIndex;
}
}
if (minViableRank === null) {
console.error('Bad privilege name: ' + lookup);
}
let myRank = this.user !== null ?
config.service.userRanks.indexOf(this.user.accessRank) :
0;
return myRank >= minViableRank;
}
login(userName, userPassword) {
@ -46,10 +65,14 @@ class Api {
this.userName = userName;
this.userPassword = userPassword;
this.get('/user/' + userName)
.then(() => { resolve(); })
.catch(response => {
.then(response => {
this.user = response.user;
resolve();
this.authenticated.fire();
}).catch(response => {
reject(response.description);
this.logout();
this.authenticated.fire();
});
});
}
@ -57,6 +80,7 @@ class Api {
logout() {
this.userName = null;
this.userPassword = null;
this.authenticated.fire();
}
isLoggedIn() {

View file

@ -36,7 +36,7 @@ class AuthController {
options);
resolve();
page('/');
/* TODO: notify top navigation */
/* TODO: notify about login */
}).catch(errorMessage => { reject(errorMessage); });
});
}});
@ -46,7 +46,7 @@ class AuthController {
this.api.logout();
cookies.remove('auth');
page('/');
/* TODO: notify top navigation */
/* TODO: notify about logout */
}
}

View file

@ -12,6 +12,7 @@ class TopNavigationController {
constructor(topNavigationView, api) {
this.api = api;
this.topNavigationView = topNavigationView;
this.activeItem = null;
this.items = {
'home': new NavigationItem('Home', '/'),
@ -27,9 +28,15 @@ class TopNavigationController {
'help': new NavigationItem('Help', '/help'),
};
this.updateVisibility();
this.api.authenticated.listen(() => {
this.updateVisibility();
this.topNavigationView.render(this.items, this.activeItem);
this.topNavigationView.activate(this.activeItem);
});
this.topNavigationView.render(this.items);
this.updateVisibility();
this.topNavigationView.render(this.items, this.activeItem);
this.topNavigationView.activate(this.activeItem);
}
updateVisibility() {
@ -40,7 +47,7 @@ class TopNavigationController {
if (!this.api.hasPrivilege('posts:list')) {
this.items.posts.available = false;
}
if (!this.api.hasPrivilege('posts:upload')) {
if (!this.api.hasPrivilege('posts:create')) {
this.items.upload.available = false;
}
if (!this.api.hasPrivilege('comments:list')) {
@ -62,7 +69,8 @@ class TopNavigationController {
}
activate(itemName) {
this.topNavigationView.activate(itemName);
this.activeItem = itemName;
this.topNavigationView.activate(this.activeItem);
}
}

View file

@ -0,0 +1,24 @@
class EventListener {
constructor() {
this.listeners = [];
}
listen(callback) {
this.listeners.push(callback);
}
unlisten(callback) {
const index = this.listeners.indexOf(callback);
if (index !== -1) {
this.listeners.splice(index, 1);
}
}
fire(data) {
for (let listener of this.listeners) {
listener(data);
}
}
}
module.exports = EventListener;

View file

@ -73,7 +73,7 @@ class UserDetailApi(object):
self._auth_service.verify_privilege(request.context.user, 'users:view')
session = request.context.session
user = self._user_service.get_by_name(session, user_name)
request.context.result = _serialize_user(user)
request.context.result = {'user': _serialize_user(user)}
def on_put(self, request, response, user_name):
''' Updates an existing user. '''