diff --git a/docs/references/api.md b/docs/references/api.md
index b16ba3d13..193b7ee3a 100644
--- a/docs/references/api.md
+++ b/docs/references/api.md
@@ -860,6 +860,19 @@ Response (200):
}
```
+### Set members
+
+PUT `/api/v1/groups/:groupId` admin
+
+Sets the members of an existing group with id `groupId`.
+
+Request:
+```
+{
+ userIds: [ , ... ] // list of users to be part of this group
+}
+```
+
### List groups
GET `/api/v1/groups` admin
diff --git a/src/groupdb.js b/src/groupdb.js
index 0d63b9403..840c6537f 100644
--- a/src/groupdb.js
+++ b/src/groupdb.js
@@ -12,6 +12,7 @@ exports = module.exports = {
getMembers: getMembers,
addMember: addMember,
removeMember: removeMember,
+ setMembers: setMembers,
isMember: isMember,
getGroups: getGroups,
@@ -147,6 +148,25 @@ function getMembers(groupId, callback) {
});
}
+function setMembers(groupId, userIds, callback) {
+ assert.strictEqual(typeof groupId, 'string');
+ assert(Array.isArray(userIds));
+ assert.strictEqual(typeof callback, 'function');
+
+ var queries = [];
+ queries.push({ query: 'DELETE FROM groupMembers WHERE groupId = ?', args: [ groupId ] });
+ for (var i = 0; i < userIds.length; i++) {
+ queries.push({ query: 'INSERT INTO groupMembers (groupId, userId) VALUES (?, ?)', args: [ groupId, userIds[i] ] });
+ }
+
+ database.transaction(queries, function (error) {
+ if (error && error.code === 'ER_NO_REFERENCED_ROW_2') return callback(new DatabaseError(DatabaseError.NOT_FOUND));
+ if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
+
+ callback(error);
+ });
+}
+
function getGroups(userId, callback) {
assert.strictEqual(typeof userId, 'string');
assert.strictEqual(typeof callback, 'function');
diff --git a/src/groups.js b/src/groups.js
index dd481d20c..3c79dc2b1 100644
--- a/src/groups.js
+++ b/src/groups.js
@@ -12,6 +12,7 @@ exports = module.exports = {
getMembers: getMembers,
addMember: addMember,
+ setMembers: setMembers,
removeMember: removeMember,
isMember: isMember,
@@ -203,6 +204,19 @@ function addMember(groupId, userId, callback) {
});
}
+function setMembers(groupId, userIds, callback) {
+ assert.strictEqual(typeof groupId, 'string');
+ assert(Array.isArray(userIds));
+ assert.strictEqual(typeof callback, 'function');
+
+ groupdb.setMembers(groupId, userIds, function (error) {
+ if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupError(GroupError.NOT_FOUND, 'Invalid group or user id'));
+ if (error) return callback(new GroupError(GroupError.INTERNAL_ERROR, error));
+
+ return callback(null);
+ });
+}
+
function removeMember(groupId, userId, callback) {
assert.strictEqual(typeof groupId, 'string');
assert.strictEqual(typeof userId, 'string');
diff --git a/src/routes/groups.js b/src/routes/groups.js
index 2edfb992e..e968e28c7 100644
--- a/src/routes/groups.js
+++ b/src/routes/groups.js
@@ -4,7 +4,8 @@ exports = module.exports = {
get: get,
list: list,
create: create,
- remove: remove
+ remove: remove,
+ update: update
};
var assert = require('assert'),
@@ -44,6 +45,20 @@ function get(req, res, next) {
});
}
+function update(req, res, next) {
+ assert.strictEqual(typeof req.params.groupId, 'string');
+
+ if (!req.body.userIds) return next(new HttpError(404, 'missing or invalid userIds fields'));
+ if (!Array.isArray(req.body.userIds)) return next(new HttpError(404, 'userIds must be an array'));
+
+ groups.setMembers(req.params.groupId, req.body.userIds, function (error) {
+ if (error && error.reason === GroupError.NOT_FOUND) return next(new HttpError(404, 'Invalid group or user id'));
+ if (error) return next(new HttpError(500, error));
+
+ next(new HttpSuccess(200));
+ });
+}
+
function list(req, res, next) {
groups.getAllWithMembers(function (error, result) {
if (error) return next(new HttpError(500, error));
diff --git a/src/server.js b/src/server.js
index 01edb3ca9..a41c5a364 100644
--- a/src/server.js
+++ b/src/server.js
@@ -123,6 +123,7 @@ function initializeExpressSync() {
router.get ('/api/v1/groups', usersScope, routes.user.requireAdmin, routes.groups.list);
router.post('/api/v1/groups', usersScope, routes.user.requireAdmin, routes.groups.create);
router.get ('/api/v1/groups/:groupId', usersScope, routes.user.requireAdmin, routes.groups.get);
+ router.put ('/api/v1/groups/:groupId', usersScope, routes.user.requireAdmin, routes.groups.update);
router.del ('/api/v1/groups/:groupId', usersScope, routes.user.requireAdmin, routes.user.verifyPassword, routes.groups.remove);
// form based login routes used by oauth2 frame