diff --git a/test/api/v3/integration/quests/POST-groups_groupid_quests_cancel.test.js b/test/api/v3/integration/quests/POST-groups_groupid_quests_cancel.test.js index 40e7d1a4986..a8095a3cee8 100644 --- a/test/api/v3/integration/quests/POST-groups_groupid_quests_cancel.test.js +++ b/test/api/v3/integration/quests/POST-groups_groupid_quests_cancel.test.js @@ -4,6 +4,7 @@ import { generateUser, } from '../../../../helpers/api-integration/v3'; import { v4 as generateUUID } from 'uuid'; +import { model as Group } from '../../../../../website/server/models/group'; describe('POST /groups/:groupId/quests/cancel', () => { let questingGroup; @@ -99,6 +100,10 @@ describe('POST /groups/:groupId/quests/cancel', () => { it('cancels a quest', async () => { await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`); await partyMembers[0].post(`/groups/${questingGroup._id}/quests/accept`); + // partyMembers[1] hasn't accepted the invitation, because if he accepts, invitation phase ends. + // The cancel command can be done only in the invitation phase. + + let stub = sandbox.spy(Group.prototype, 'sendChat'); let res = await leader.post(`/groups/${questingGroup._id}/quests/cancel`); @@ -135,5 +140,9 @@ describe('POST /groups/:groupId/quests/cancel', () => { }, members: {}, }); + expect(Group.prototype.sendChat).to.be.calledOnce; + expect(Group.prototype.sendChat).to.be.calledWithMatch(/cancelled the party quest Wail of the Whale.`/); + + stub.restore(); }); }); diff --git a/website/server/controllers/api-v3/quests.js b/website/server/controllers/api-v3/quests.js index cac17c61118..c8b2b25ebe9 100644 --- a/website/server/controllers/api-v3/quests.js +++ b/website/server/controllers/api-v3/quests.js @@ -363,17 +363,22 @@ api.cancelQuest = { if (validationErrors) throw validationErrors; let group = await Group.getGroup({user, groupId, fields: basicGroupFields.concat(' quest')}); + if (!group) throw new NotFound(res.t('groupNotFound')); if (group.type !== 'party') throw new NotAuthorized(res.t('guildQuestsNotSupported')); if (!group.quest.key) throw new NotFound(res.t('questInvitationDoesNotExist')); if (user._id !== group.leader && group.quest.leader !== user._id) throw new NotAuthorized(res.t('onlyLeaderCancelQuest')); if (group.quest.active) throw new NotAuthorized(res.t('cantCancelActiveQuest')); + let questName = questScrolls[group.quest.key].text('en'); + const newChatMessage = group.sendChat(`\`${user.profile.name} cancelled the party quest ${questName}.\``); + group.quest = Group.cleanGroupQuest(); group.markModified('quest'); let [savedGroup] = await Promise.all([ group.save(), + newChatMessage.save(), User.update( {'party._id': groupId}, Group.cleanQuestParty(), @@ -405,7 +410,7 @@ api.abortQuest = { url: '/groups/:groupId/quests/abort', middlewares: [authWithHeaders()], async handler (req, res) { - // Abort a quest AFTER it has begun (see questCancel for BEFORE) + // Abort a quest AFTER it has begun let user = res.locals.user; let groupId = req.params.groupId;