Merge pull request #11707 from cvuorinen/11682-quest-invitation-webhook

Quest invitation webhook
This commit is contained in:
Matteo Pagliazzi 2020-01-14 13:06:31 +01:00 committed by GitHub
commit fa9f962e45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 6 deletions

View file

@ -43,6 +43,7 @@ describe('webhooks', () => {
options: {
questStarted: true,
questFinised: true,
questInvited: true,
},
}, {
id: 'userActivity',
@ -576,7 +577,7 @@ describe('webhooks', () => {
};
});
['questStarted', 'questFinised'].forEach(type => {
['questStarted', 'questFinised', 'questInvited'].forEach(type => {
it(`sends ${type} webhooks`, () => {
data.type = type;

View file

@ -183,6 +183,7 @@ describe('Webhook Model', () => {
options: {
questStarted: true,
questFinished: true,
questInvited: true,
},
};
});
@ -197,6 +198,7 @@ describe('Webhook Model', () => {
expect(wh.options).to.eql({
questStarted: false,
questFinished: false,
questInvited: false,
});
});
@ -210,6 +212,7 @@ describe('Webhook Model', () => {
expect(wh.options).to.eql({
questStarted: false,
questFinished: true,
questInvited: true,
});
});
@ -224,6 +227,7 @@ describe('Webhook Model', () => {
expect(wh.options).to.eql({
questStarted: true,
questFinished: true,
questInvited: true,
});
});

View file

@ -2,6 +2,7 @@ import { v4 as generateUUID } from 'uuid';
import {
createAndPopulateGroup,
translate as t,
server,
sleep,
} from '../../../../helpers/api-integration/v3';
import { quests as questScrolls } from '../../../../../website/common/script/content/quests';
@ -210,5 +211,39 @@ describe('POST /groups/:groupId/quests/invite/:questKey', () => {
const returnedGroup = await groupLeader.get(`/groups/${group._id}`);
expect(returnedGroup.chat[0]._meta).to.be.undefined;
});
context('sending quest activity webhooks', () => {
before(async () => {
await server.start();
});
after(async () => {
await server.close();
});
it('sends quest invited webhook', async () => {
const uuid = generateUUID();
await member.post('/user/webhook', {
url: `http://localhost:${server.port}/webhooks/${uuid}`,
type: 'questActivity',
enabled: true,
options: {
questInvited: true,
},
});
await leader.post(`/groups/${questingGroup._id}/quests/invite/${PET_QUEST}`);
await sleep();
const body = server.getWebhookData(uuid);
expect(body.type).to.eql('questInvited');
expect(body.group.id).to.eql(questingGroup.id);
expect(body.group.name).to.eql(questingGroup.name);
expect(body.quest.key).to.eql(PET_QUEST);
});
});
});
});

View file

@ -226,6 +226,69 @@ describe('POST /user/webhook', () => {
});
});
it('defaults questActivity options', async () => {
body.type = 'questActivity';
const webhook = await user.post('/user/webhook', body);
expect(webhook.options).to.eql({
questStarted: false,
questFinished: false,
questInvited: false,
});
});
it('can set questActivity options', async () => {
body.type = 'questActivity';
body.options = {
questStarted: true,
questFinished: true,
questInvited: true,
};
const webhook = await user.post('/user/webhook', body);
expect(webhook.options).to.eql({
questStarted: true,
questFinished: true,
questInvited: true,
});
});
it('discards extra properties in questActivity options', async () => {
body.type = 'questActivity';
body.options = {
questStarted: false,
questFinished: true,
questInvited: true,
foo: 'bar',
};
const webhook = await user.post('/user/webhook', body);
expect(webhook.options.foo).to.not.exist;
expect(webhook.options).to.eql({
questStarted: false,
questFinished: true,
questInvited: true,
});
});
['questStarted', 'questFinished', 'questInvited'].forEach(option => {
it(`requires questActivity option ${option} to be a boolean`, async () => {
body.type = 'questActivity';
body.options = {
[option]: 'not a boolean',
};
await expect(user.post('/user/webhook', body)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('webhookBooleanOption', { option }),
});
});
});
it('discards extra properties in globalActivity options', async () => {
body.type = 'globalActivity';
body.options = {

View file

@ -18,6 +18,7 @@ import {
import common from '../../../common';
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
import apiError from '../../libs/apiError';
import { questActivityWebhook } from '../../libs/webhook';
const questScrolls = common.content.quests;
@ -79,7 +80,7 @@ api.inviteToQuest = {
'party._id': group._id,
_id: { $ne: user._id },
})
.select('auth.facebook auth.google auth.local preferences.emailNotifications preferences.pushNotifications preferences.language profile.name pushDevices')
.select('auth.facebook auth.google auth.local preferences.emailNotifications preferences.pushNotifications preferences.language profile.name pushDevices webhooks')
.exec();
group.markModified('quest');
@ -132,6 +133,13 @@ api.inviteToQuest = {
);
}
// Send webhooks
questActivityWebhook.send(member, {
type: 'questInvited',
group,
quest,
});
return member.preferences.emailNotifications.invitedQuest !== false;
});
sendTxnEmail(membersToEmail, `invite-${quest.boss ? 'boss' : 'collection'}-quest`, [

View file

@ -35,8 +35,8 @@ const api = {};
* @apiParam (Body) {String} [label] A label to remind you what this webhook does
* @apiParam (Body) {Boolean} [enabled=true] If the webhook should be enabled
* @apiParam (Body) {String="taskActivity","groupChatReceived",
"userActivity"} [type="taskActivity"] The webhook's type.
* @apiParam (Body) {Object} [options] The webhook's options. Wil differ depending on type.
"userActivity","questActivity"} [type="taskActivity"] The webhook's type.
* @apiParam (Body) {Object} [options] The webhook's options. Will differ depending on type.
* Required for `groupChatReceived` type.
* If a webhook supports options, the default values
* are displayed in the examples below
@ -63,6 +63,30 @@ const api = {};
* "groupId": "required-uuid-of-group"
* }
* }
* @apiParamExample {json} User Activity Example
* {
* "enabled": true,
* "url": "http://some-webhook-url.com",
* "label": "My Activity Webhook",
* "type": "userActivity",
* "options": { // set at least one to true
* "petHatched": false, // default
* "mountRaised": false, // default
* "leveledUp": false, // default
* }
* }
* @apiParamExample {json} Quest Activity Example
* {
* "enabled": true,
* "url": "http://some-webhook-url.com",
* "label": "My Quest Webhook",
* "type": "questActivity",
* "options": { // set at least one to true
* "questStarted": false, // default
* "questFinished": false, // default
* "questInvited": false, // default
* }
* }
* @apiParamExample {json} Minimal Example
* {
* "url": "http://some-webhook-url.com"
@ -131,8 +155,9 @@ api.getWebhook = {
* @apiParam (Body) {String} [url] The webhook's URL
* @apiParam (Body) {String} [label] A label to remind you what this webhook does
* @apiParam (Body) {Boolean} [enabled] If the webhook should be enabled
* @apiParam (Body) {String="taskActivity","groupChatReceived"} [type] The webhook's type.
* @apiParam (Body) {Object} [options] The webhook's options. Wil differ depending on type.
* @apiParam (Body) {String="taskActivity","groupChatReceived",
* "userActivity","questActivity"} [type] The webhook's type.
* @apiParam (Body) {Object} [options] The webhook's options. Will differ depending on type.
* The options are enumerated in the
* [add webhook examples](#api-Webhook-UserAddWebhook).
* @apiParamExample {json} Update Enabled and Type Properties

View file

@ -28,6 +28,7 @@ const USER_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
const QUEST_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
questStarted: false,
questFinished: false,
questInvited: false,
});
export const schema = new Schema({