feat(api): group ownership API route, switch client-side to use API route

This commit is contained in:
Julian Lam
2020-12-22 14:26:31 -05:00
parent 98550d61d7
commit 32e36f7b2e
8 changed files with 53 additions and 36 deletions

View File

@@ -177,6 +177,28 @@ groupsAPI.leave = async function (caller, data) {
});
};
groupsAPI.grant = async (caller, data) => {
const groupName = await groups.getGroupNameByGroupSlug(data.slug);
await isOwner(caller, groupName);
await groups.ownership.grant(data.uid, groupName);
logGroupEvent(caller, 'group-owner-grant', {
groupName: groupName,
targetUid: data.uid,
});
};
groupsAPI.rescind = async (caller, data) => {
const groupName = await groups.getGroupNameByGroupSlug(data.slug);
await isOwner(caller, groupName);
await groups.ownership.rescind(data.uid, groupName);
logGroupEvent(caller, 'group-owner-rescind', {
groupName: groupName,
targetUid: data.uid,
});
};
async function isOwner(caller, groupName) {
if (typeof groupName !== 'string') {
throw new Error('[[error:invalid-group-name]]');

View File

@@ -37,3 +37,13 @@ Groups.leave = async (req, res) => {
await api.groups.leave(req, req.params);
helpers.formatApiResponse(200, res);
};
Groups.grant = async (req, res) => {
await api.groups.grant(req, req.params);
helpers.formatApiResponse(200, res);
};
Groups.rescind = async (req, res) => {
await api.groups.rescind(req, req.params);
helpers.formatApiResponse(200, res);
};

View File

@@ -22,16 +22,15 @@ module.exports = function (Groups) {
};
Groups.ownership.grant = async function (toUid, groupName) {
// Note: No ownership checking is done here on purpose!
await db.setAdd('group:' + groupName + ':owners', toUid);
plugins.hooks.fire('action:group.grantOwnership', { uid: toUid, groupName: groupName });
};
Groups.ownership.rescind = async function (toUid, groupName) {
// Note: No ownership checking is done here on purpose!
// If the owners set only contains one member, error out!
// If the owners set only contains one member (and toUid is that member), error out!
const numOwners = await db.setCount('group:' + groupName + ':owners');
if (numOwners <= 1) {
const isOwner = await db.isSortedSetMember(`group:${groupName}:owners`);
if (numOwners <= 1 && isOwner) {
throw new Error('[[error:group-needs-owner]]');
}
await db.setRemove('group:' + groupName + ':owners', toUid);

View File

@@ -16,6 +16,8 @@ module.exports = function () {
setupApiRoute(router, 'delete', '/:slug', [...middlewares, middleware.assert.group], controllers.write.groups.delete);
setupApiRoute(router, 'put', '/:slug/membership/:uid', [...middlewares, middleware.assert.group], controllers.write.groups.join);
setupApiRoute(router, 'delete', '/:slug/membership/:uid', [...middlewares, middleware.assert.group], controllers.write.groups.leave);
setupApiRoute(router, 'put', '/:slug/ownership/:uid', [...middlewares, middleware.assert.group], controllers.write.groups.grant);
setupApiRoute(router, 'delete', '/:slug/ownership/:uid', [...middlewares, middleware.assert.group], controllers.write.groups.rescind);
return router;
};

View File

@@ -79,6 +79,8 @@ async function isInvited(socket, data) {
}
SocketGroups.grant = async (socket, data) => {
sockets.warnDeprecated(socket, 'PUT /api/v3/groups/:slug/ownership/:uid');
await isOwner(socket, data);
await groups.ownership.grant(data.toUid, data.groupName);
logGroupEvent(socket, 'group-owner-grant', {
@@ -88,6 +90,8 @@ SocketGroups.grant = async (socket, data) => {
};
SocketGroups.rescind = async (socket, data) => {
sockets.warnDeprecated(socket, 'DELETE /api/v3/groups/:slug/ownership/:uid');
await isOwner(socket, data);
await groups.ownership.rescind(data.toUid, data.groupName);
logGroupEvent(socket, 'group-owner-rescind', {