diff --git a/src/api/groups.js b/src/api/groups.js index 3f251d189c20..41c8b089b9b4 100644 --- a/src/api/groups.js +++ b/src/api/groups.js @@ -3,6 +3,8 @@ const privileges = require('../privileges'); const events = require('../events'); const groups = require('../groups'); +const user = require('../user'); +const meta = require('../meta'); const groupsAPI = module.exports; @@ -27,9 +29,60 @@ groupsAPI.create = async function (caller, data) { return groupData; }; -// groupsAPI.join = async function (caller, data) { -// // TODO: -// }; +groupsAPI.join = async function (caller, data) { + if (caller.uid <= 0 || !data.uid) { + throw new Error('[[error:invalid-uid]]'); + } + + const isSelf = parseInt(caller.uid, 10) === parseInt(data.uid, 10); + const groupName = await groups.getGroupNameByGroupSlug(data.slug); + if (!groupName) { + throw new Error('[[error:no-group]]'); + } + + if (groups.systemGroups.includes(groupName) || groups.isPrivilegeGroup(groupName)) { + throw new Error('[[error:not-allowed]]'); + } + + const [groupData, isCallerAdmin, isCallerOwner, userExists] = await Promise.all([ + groups.getGroupData(groupName), + user.isAdministrator(caller.uid), + groups.ownership.isOwner(caller.uid, groupName), + user.exists(data.uid), + ]); + + if (!userExists) { + throw new Error('[[error:invalid-uid]]'); + } + + if (!meta.config.allowPrivateGroups && isSelf) { + // all groups are public! + await groups.join(groupName, data.uid); + logGroupEvent(caller, 'group-join', { + groupName: groupName, + targetUid: data.uid, + }); + return; + } + + if (groupData.private && groupData.disableJoinRequests) { + throw new Error('[[error:group-join-disabled]]'); + } + + if ((!groupData.private && isSelf) || isCallerAdmin || isCallerOwner) { + await groups.join(groupName, data.uid); + logGroupEvent(caller, 'group-join', { + groupName: groupName, + targetUid: data.uid, + }); + } else if (isSelf) { + await groups.requestMembership(groupName, caller.uid); + logGroupEvent(caller, 'group-request-membership', { + groupName: groupName, + targetUid: data.uid, + }); + } +}; // groupsAPI.leave = async function (caller, data) { // // TODO: diff --git a/src/controllers/write/groups.js b/src/controllers/write/groups.js index 3b887122c133..d6c8b041d4a0 100644 --- a/src/controllers/write/groups.js +++ b/src/controllers/write/groups.js @@ -5,7 +5,6 @@ const validator = require('validator'); const user = require('../../user'); const groups = require('../../groups'); const events = require('../../events'); -const meta = require('../../meta'); const slugify = require('../../slugify'); const notifications = require('../../notifications'); const api = require('../../api'); @@ -40,40 +39,8 @@ Groups.delete = async (req, res) => { }; Groups.join = async (req, res) => { - const group = await groups.getByGroupslug(req.params.slug, { - uid: req.params.uid, - }); - const [isCallerOwner, userExists] = await Promise.all([ - groups.ownership.isOwner(req.user.uid, group.name), - user.exists(req.params.uid), - ]); - - if (!userExists) { - throw new Error('[[error:invalid-uid]]'); - } else if (group.isMember) { - // No change - return helpers.formatApiResponse(200, res); - } - - if (!res.locals.privileges.isAdmin) { - // Admin and privilege groups unjoinable client-side - if (groups.systemGroups.includes(group.name) || groups.isPrivilegeGroup(group.name)) { - throw new Error('[[error:not-allowed]]'); - } - - if (!isCallerOwner && parseInt(meta.config.allowPrivateGroups, 10) !== 0 && group.private) { - await groups.requestMembership(group.name, req.params.uid); - } else { - await groups.join(group.name, req.params.uid); - } - } else { - await groups.join(group.name, req.params.uid); - } - + await api.groups.join(req, req.params); helpers.formatApiResponse(200, res); - logGroupEvent(req, 'group-join', { - groupName: group.name, - }); }; Groups.leave = async (req, res) => { diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index d7e72ede6aaf..cacc69b83cf5 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -2,7 +2,6 @@ const validator = require('validator'); const groups = require('../groups'); -const meta = require('../meta'); const user = require('../user'); const utils = require('../utils'); const slugify = require('../slugify'); @@ -21,52 +20,8 @@ SocketGroups.before = async (socket, method, data) => { SocketGroups.join = async (socket, data) => { sockets.warnDeprecated(socket, 'PUT /api/v3/groups/:slug/membership/:uid'); - - if (socket.uid <= 0) { - throw new Error('[[error:invalid-uid]]'); - } - - if (typeof data.groupName !== 'string') { - throw new Error('[[error:invalid-group-name]]'); - } - - if (groups.systemGroups.includes(data.groupName) || groups.isPrivilegeGroup(data.groupName)) { - throw new Error('[[error:not-allowed]]'); - } - - const exists = await groups.exists(data.groupName); - if (!exists) { - throw new Error('[[error:no-group]]'); - } - - if (!meta.config.allowPrivateGroups) { - await groups.join(data.groupName, socket.uid); - logGroupEvent(socket, 'group-join', { - groupName: data.groupName, - }); - return; - } - - const results = await utils.promiseParallel({ - isAdmin: await user.isAdministrator(socket.uid), - groupData: await groups.getGroupData(data.groupName), - }); - - if (results.groupData.private && results.groupData.disableJoinRequests) { - throw new Error('[[error:group-join-disabled]]'); - } - - if (!results.groupData.private || results.isAdmin) { - await groups.join(data.groupName, socket.uid); - logGroupEvent(socket, 'group-join', { - groupName: data.groupName, - }); - } else { - await groups.requestMembership(data.groupName, socket.uid); - logGroupEvent(socket, 'group-request-membership', { - groupName: data.groupName, - }); - } + const slug = await groups.getGroupField(data.groupName, 'slug'); + await api.groups.join(socket, { slug: slug, uid: data.uid || socket.uid }); }; SocketGroups.leave = async (socket, data) => { diff --git a/test/groups.js b/test/groups.js index a388a5a929a4..1605c712e8bd 100644 --- a/test/groups.js +++ b/test/groups.js @@ -640,7 +640,7 @@ describe('Groups', function () { const isMember = await Groups.isMember(newUid, 'administrators'); assert(!isMember); } catch (err) { - assert.strictEqual(err.message, '[[error:invalid-group-name]]'); + assert.strictEqual(err.message, '[[error:no-group]]'); } meta.config.allowPrivateGroups = oldValue; });