From 621e8e89a51a74efbb7af31117b332114696bdc5 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 28 May 2015 19:26:16 +0200 Subject: [PATCH] Implements groups. --- src/api/group.js | 27 +++++------------ src/models/group.js | 47 ++++++++++++++++++++++++++++++ src/xo.js | 70 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 src/models/group.js diff --git a/src/api/group.js b/src/api/group.js index 15410e49a..52bed45f0 100644 --- a/src/api/group.js +++ b/src/api/group.js @@ -1,7 +1,5 @@ -// FIXME All methods are to implement - export async function create ({name}) { - return Date.now() // Dummy id + return (await this.createGroup({name})).id } create.description = 'creates a new group' @@ -14,7 +12,7 @@ create.params = { // Deletes an existing group. async function delete_ ({id}) { - return true + await this.deleteGroup(id) } // delete is not a valid identifier. @@ -29,18 +27,7 @@ delete_.params = { // ------------------------------------------------------------------- export async function getAll () { - return [ - { - id: 'G1', - name: 'Groupe 1', - users: [] - }, - { - id: 'G2', - name: 'Groupe 2', - users: [] - } - ] + return await this._groups.get() } delete_.description = 'returns all the existing group' @@ -53,7 +40,7 @@ delete_.params = { // sets group.users with an array of user ids export async function setUsers ({id, userIds}) { - return true + await this.setGroupUsers(id, userIds) } setUsers.description = 'sets the users belonging to a group' @@ -67,7 +54,7 @@ setUsers.params = { // adds the user id to group.users export async function addUser ({id, userId}) { - return true + await this.addUserToGroup(userId, id) } addUser.description = 'adds a user to a group' @@ -81,7 +68,7 @@ addUser.params = { // remove the user id from group.users export async function removeUser ({id, userId}) { - return true + await this.removeUserFromGroup(userId, id) } // ------------------------------------------------------------------- @@ -96,7 +83,7 @@ removeUser.params = { // ------------------------------------------------------------------- export async function set ({id, name}) { - return true + await this.updateGroup(id, {name}) } set.description = 'changes the properties of an existing group' diff --git a/src/models/group.js b/src/models/group.js new file mode 100644 index 000000000..8a7467104 --- /dev/null +++ b/src/models/group.js @@ -0,0 +1,47 @@ +import forEach from 'lodash.foreach' + +import Collection from '../collection/redis' +import Model from '../model' + +// =================================================================== + +export default class Group extends Model {} + +// =================================================================== + +export class Groups extends Collection { + get Model () { + return Group + } + + create (name) { + return this.add(new Group({ + name, + users: '[]' + })) + } + + async save (group) { + // Serializes. + group.users = JSON.stringify(group.users) + + return await this.update(group) + } + + async get (properties) { + const groups = await super.get(properties) + + // Deserializes. + forEach(groups, group => { + const {users} = group + try { + group.users = JSON.parse(users) + } catch (error) { + console.warn('cannot parse group.user:', users) + group.users = [] + } + }) + + return groups + } +} diff --git a/src/xo.js b/src/xo.js index 06bae4098..5c0e724bd 100644 --- a/src/xo.js +++ b/src/xo.js @@ -1,4 +1,5 @@ import Bluebird from 'bluebird' +import filter from 'lodash.filter' import forEach from 'lodash.foreach' import includes from 'lodash.includes' import isEmpty from 'lodash.isempty' @@ -18,6 +19,7 @@ import Xapi from './xapi' import {Acls} from './models/acl' import {autobind} from './decorators' import {generateToken} from './utils' +import {Groups} from './models/group' import {JsonRpcError, NoSuchObject, Unauthorized} from './api-errors' import {ModelAlreadyExists} from './collection' import {Servers} from './models/server' @@ -31,6 +33,12 @@ class NoSuchAuthenticationToken extends NoSuchObject { } } +class NoSuchGroup extends NoSuchObject { + constructor (id) { + super(id, 'group') + } +} + class NoSuchUser extends NoSuchObject { constructor (id) { super(id, 'user') @@ -56,6 +64,7 @@ export default class Xo extends EventEmitter { // // TODO: remove and put everything in the `_objects` collection. this._acls = null + this._groups = null this._servers = null this._tokens = null this._users = null @@ -90,6 +99,10 @@ export default class Xo extends EventEmitter { prefix: 'xo:acl', indexes: ['subject', 'object'] }) + this._groups = new Groups({ + connection: redis, + prefix: 'xo:group' + }) this._servers = new Servers({ connection: redis, prefix: 'xo:server', @@ -211,6 +224,63 @@ export default class Xo extends EventEmitter { // ----------------------------------------------------------------- + async createGroup ({name}) { + // TODO: use plain objects. + const group = (await this._groups.create(name)).properties + + group.users = JSON.parse(group.users) + return group + } + + async deleteGroup (id) { + if (!await this._groups.remove(id)) { + throw new NoSuchGroup(id) + } + } + + async updateGroup (id, {name}) { + const group = await this.getGroup(id) + + if (name) group.name = name + + await this._groups.save(group) + } + + async getGroup (id) { + const group = (await this._groups.first(id)).properties + if (!group) { + throw new NoSuchGroup(id) + } + + return group + } + + async addUserToGroup (userId, groupId) { + const group = await this.getGroup(groupId) + + group.users.push(userId) + + await this._groupss.save(group) + } + + async removeUserFromGroup (userId, groupId) { + const group = await this.getGroup(groupId) + + group.users = filter(group.users, id => id !== userId) + + await this._groups.save(group) + } + + async setGroupUsers (groupId, userIds) { + const group = await this.getGroup(groupId) + + group.users = userIds + + await this._groups.save(group) + } + + // ----------------------------------------------------------------- + async createAuthenticationToken ({userId}) { // TODO: use plain objects const token = await this._tokens.generate(userId)