diff --git a/test/api/v3/integration/groups/POST-groups_groupId_join.test.js b/test/api/v3/integration/groups/POST-groups_groupId_join.test.js index d24a03cb7e..d20c8b830d 100644 --- a/test/api/v3/integration/groups/POST-groups_groupId_join.test.js +++ b/test/api/v3/integration/groups/POST-groups_groupId_join.test.js @@ -1,6 +1,7 @@ import { generateUser, createAndPopulateGroup, + checkExistence, translate as t, } from '../../../../helpers/api-v3-integration.helper'; import { v4 as generateUUID } from 'uuid'; @@ -185,6 +186,23 @@ describe('POST /group/:groupId/join', () => { await expect(user.get('/user')).to.eventually.have.deep.property('items.quests.basilist', 2); }); + it('deletes previous party where the user was the only member', async () => { + let userToInvite = await generateUser(); + let oldParty = await userToInvite.post('/groups', { // add user to a party + name: 'Another Test Party', + type: 'party', + }); + + await expect(checkExistence('groups', oldParty._id)).to.eventually.equal(true); + await user.post(`/groups/${party._id}/invite`, { + uuids: [userToInvite._id], + }); + await userToInvite.post(`/groups/${party._id}/join`); + + await expect(user.get('/user')).to.eventually.have.deep.property('party._id', party._id); + await expect(checkExistence('groups', oldParty._id)).to.eventually.equal(false); + }); + xit('invites joining member to active quest', async () => { // TODO start quest 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 42719c0fcd..55c25d9153 100644 --- a/test/api/v3/integration/groups/POST-groups_invite.test.js +++ b/test/api/v3/integration/groups/POST-groups_invite.test.js @@ -290,12 +290,14 @@ describe('Post /groups/:groupId/invite', () => { }); }); - it('returns an error when invited user is already in the party', async () => { + it('returns an error when invited user is already in a party of more than 1 member', async () => { let userToInvite = await generateUser(); + let userToInvite2 = await generateUser(); await inviter.post(`/groups/${party._id}/invite`, { - uuids: [userToInvite._id], + uuids: [userToInvite._id, userToInvite2._id], }); await userToInvite.post(`/groups/${party._id}/join`); + await userToInvite2.post(`/groups/${party._id}/join`); await expect(inviter.post(`/groups/${party._id}/invite`, { uuids: [userToInvite._id], @@ -306,5 +308,18 @@ describe('Post /groups/:groupId/invite', () => { message: t('userAlreadyInAParty'), }); }); + + it('allow inviting an user to a party if he\'s partying solo', async () => { + let userToInvite = await generateUser(); + await userToInvite.post('/groups', { // add user to a party + name: 'Another Test Party', + type: 'party', + }); + + 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/src/controllers/api-v3/groups.js b/website/src/controllers/api-v3/groups.js index 48e06a752a..0c6a35330e 100644 --- a/website/src/controllers/api-v3/groups.js +++ b/website/src/controllers/api-v3/groups.js @@ -238,10 +238,18 @@ api.joinGroup = { if (group.quest.key && !group.quest.active) { user.party.quest.RSVPNeeded = true; user.party.quest.key = group.quest.key; + user.party.quest.progress = undefined; // Make sure to reset progress from ay previous quest group.quest.members[user._id] = undefined; group.markModified('quest.members'); } + // If user was in a different party (when partying solo you can be invited to a new party) + // make him leave that party before doing anything + if (user.party._id) { + let userPreviousParty = await Group.getGroup({user, groupId: user.party._id}); + if (userPreviousParty) await userPreviousParty.leave(user); + } + user.party._id = group._id; // Set group as user's party isUserInvited = true; @@ -425,7 +433,7 @@ api.removeGroupMember = { }; async function _inviteByUUID (uuid, group, inviter, req, res) { - // @TODO: Add Push Notifications + // TODO: Add Push Notifications let userToInvite = await User.findById(uuid).exec(); if (!userToInvite) { @@ -444,11 +452,14 @@ async function _inviteByUUID (uuid, group, inviter, req, res) { if (!_.isEmpty(userToInvite.invitations.party)) { throw new NotAuthorized(res.t('userAlreadyPendingInvitation')); } + if (userToInvite.party._id) { - throw new NotAuthorized(res.t('userAlreadyInAParty')); + 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')); } - // @TODO: Why was this here? - // req.body.type in 'guild', 'party' + userToInvite.invitations.party = {id: group._id, name: group.name, inviter: inviter._id}; } diff --git a/website/src/models/group.js b/website/src/models/group.js index d5d83b19b1..8b11a57081 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -118,10 +118,10 @@ schema.statics.getGroup = function getGroup (options = {}) { let query; // When optionalMembership is true it's not required for the user to be a member of the group - if (optionalMembership === true) { - query = {_id: groupId}; - } else if (groupId === 'party' || user.party._id === groupId) { + if (groupId === 'party' || user.party._id === groupId) { query = {type: 'party', _id: user.party._id}; + } else if (optionalMembership === true) { + query = {_id: groupId}; } else if (user.guilds.indexOf(groupId) !== -1) { query = {type: 'guild', _id: groupId}; } else {