From bba56b8c29caee7a22091944fae75ac1a817819c Mon Sep 17 00:00:00 2001 From: Husman Date: Sat, 6 Aug 2016 17:28:07 -0700 Subject: [PATCH] fix: remove guild or party when user looks it up if it does not exist closes #7878 fixes #7724 --- .../integration/groups/GET-groups_id.test.js | 40 +++++++++++++++++++ .../groups/POST-groups_groupId_leave.js | 27 +++++++++++++ .../groups/POST-groups_invite.test.js | 13 +++++- website/server/controllers/api-v3/groups.js | 16 +++++--- website/server/models/group.js | 11 +++++ 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/test/api/v3/integration/groups/GET-groups_id.test.js b/test/api/v3/integration/groups/GET-groups_id.test.js index 2ecb53a33f..ec8da5e1bd 100644 --- a/test/api/v3/integration/groups/GET-groups_id.test.js +++ b/test/api/v3/integration/groups/GET-groups_id.test.js @@ -3,6 +3,7 @@ import { createAndPopulateGroup, translate as t, } from '../../../../helpers/api-v3-integration.helper'; +import { v4 as generateUUID } from 'uuid'; import { each, @@ -170,6 +171,45 @@ describe('GET /groups/:id', () => { message: t('groupNotFound'), }); }); + + it('removes non-existant guild from user\'s guild list', async () => { + let guildId = generateUUID(); + + await user.update({ + guilds: [guildId, generateUUID()], + }); + + await expect(user.get(`/groups/${guildId}`)) + .to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('groupNotFound'), + }); + + await user.sync(); + + expect(user.guilds).to.have.a.lengthOf(1); + expect(user.guilds).to.not.include(guildId); + }); + + it('removes non-existant party from user\'s party object', async () => { + let partyId = generateUUID(); + + await user.update({ + party: { _id: partyId }, + }); + + await expect(user.get(`/groups/${partyId}`)) + .to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('groupNotFound'), + }); + + await user.sync(); + + expect(user.party).to.eql({}); + }); }); context('Flagged messages', () => { diff --git a/test/api/v3/integration/groups/POST-groups_groupId_leave.js b/test/api/v3/integration/groups/POST-groups_groupId_leave.js index 3e13634bd8..ae16fb256e 100644 --- a/test/api/v3/integration/groups/POST-groups_groupId_leave.js +++ b/test/api/v3/integration/groups/POST-groups_groupId_leave.js @@ -6,6 +6,7 @@ import { generateUser, translate as t, } from '../../../../helpers/api-v3-integration.helper'; +import { v4 as generateUUID } from 'uuid'; import { each, } from 'lodash'; @@ -171,6 +172,19 @@ describe('POST /groups/:groupId/leave', () => { expect(userWithoutInvitation.invitations.guilds).to.not.be.empty; }); + + it('deletes non existant guild from user when user tries to leave', async () => { + let nonExistentGuildId = generateUUID(); + let userWithNonExistentGuild = await generateUser({guilds: [nonExistentGuildId]}); + expect(userWithNonExistentGuild.guilds).to.contain(nonExistentGuildId); + + await expect(userWithNonExistentGuild.post(`/groups/${nonExistentGuildId}/leave`)) + .to.eventually.be.rejected; + + await userWithNonExistentGuild.sync(); + + expect(userWithNonExistentGuild.guilds).to.not.contain(nonExistentGuildId); + }); }); context('party', () => { @@ -206,5 +220,18 @@ describe('POST /groups/:groupId/leave', () => { expect(userWithoutInvitation.invitations.party).to.be.empty; }); }); + + it('deletes non existant party from user when user tries to leave', async () => { + let nonExistentPartyId = generateUUID(); + let userWithNonExistentParty = await generateUser({'party._id': nonExistentPartyId}); + expect(userWithNonExistentParty.party._id).to.be.eql(nonExistentPartyId); + + await expect(userWithNonExistentParty.post(`/groups/${nonExistentPartyId}/leave`)) + .to.eventually.be.rejected; + + await userWithNonExistentParty.sync(); + + expect(userWithNonExistentParty.party).to.eql({}); + }); }); }); diff --git a/test/api/v3/integration/groups/POST-groups_invite.test.js b/test/api/v3/integration/groups/POST-groups_invite.test.js index 3e6ed0be30..cbc8109482 100644 --- a/test/api/v3/integration/groups/POST-groups_invite.test.js +++ b/test/api/v3/integration/groups/POST-groups_invite.test.js @@ -327,7 +327,7 @@ describe('Post /groups/:groupId/invite', () => { }); }); - it('allow inviting a user to a party if he\'s partying solo', async () => { + it('allow inviting a user to a party if they are partying solo', async () => { let userToInvite = await generateUser(); await userToInvite.post('/groups', { // add user to a party name: 'Another Test Party', @@ -339,5 +339,16 @@ describe('Post /groups/:groupId/invite', () => { }); expect((await userToInvite.get('/user')).invitations.party.id).to.equal(party._id); }); + + it('allow inviting a user if party id is not associated with a real party', async () => { + let userToInvite = await generateUser({ + party: { _id: generateUUID() }, + }); + + await inviter.post(`/groups/${party._id}/invite`, { + uuids: [userToInvite._id], + }); + expect((await userToInvite.get('/user')).invitations.party.id).to.equal(party._id); + }); }); }); diff --git a/website/server/controllers/api-v3/groups.js b/website/server/controllers/api-v3/groups.js index f909bc188e..80e803a116 100644 --- a/website/server/controllers/api-v3/groups.js +++ b/website/server/controllers/api-v3/groups.js @@ -124,8 +124,11 @@ api.getGroup = { let validationErrors = req.validationErrors(); if (validationErrors) throw validationErrors; - let group = await Group.getGroup({user, groupId: req.params.groupId, populateLeader: false}); - if (!group) throw new NotFound(res.t('groupNotFound')); + let groupId = req.params.groupId; + let group = await Group.getGroup({user, groupId, populateLeader: false}); + if (!group) { + throw new NotFound(res.t('groupNotFound')); + } group = Group.toJSONCleanChat(group, user); // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 @@ -347,8 +350,11 @@ api.leaveGroup = { let validationErrors = req.validationErrors(); if (validationErrors) throw validationErrors; - let group = await Group.getGroup({user, groupId: req.params.groupId, fields: '-chat', requireMembership: true}); - if (!group) throw new NotFound(res.t('groupNotFound')); + let groupId = req.params.groupId; + let group = await Group.getGroup({user, groupId, fields: '-chat', requireMembership: true}); + if (!group) { + throw new NotFound(res.t('groupNotFound')); + } // During quests, checke wheter user can leave if (group.type === 'party') { @@ -510,7 +516,7 @@ async function _inviteByUUID (uuid, group, inviter, req, res) { let userParty = await Group.getGroup({user: userToInvite, groupId: 'party', fields: 'memberCount'}); // Allow user to be invited to a new party when they're partying solo - if (userParty.memberCount !== 1) throw new NotAuthorized(res.t('userAlreadyInAParty')); + if (userParty && userParty.memberCount !== 1) throw new NotAuthorized(res.t('userAlreadyInAParty')); } userToInvite.invitations.party = {id: group._id, name: group.name, inviter: inviter._id}; diff --git a/website/server/models/group.js b/website/server/models/group.js index 7abbe42135..f009d5e3ab 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -159,6 +159,17 @@ schema.statics.getGroup = async function getGroup (options = {}) { if (fields) mQuery.select(fields); if (populateLeader === true) mQuery.populate('leader', nameFields); let group = await mQuery.exec(); + + if (!group) { + if (groupId === user.party._id) { + // reset party object to default state + user.party = {}; + } else { + removeFromArray(user.guilds, groupId); + } + await user.save(); + } + return group; };