Skip to content

Commit

Permalink
add questStarted webhook and questActivity type
Browse files Browse the repository at this point in the history
  • Loading branch information
paglias committed Apr 29, 2018
1 parent 22b1140 commit 68e5b6e
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 41 deletions.
24 changes: 24 additions & 0 deletions website/server/libs/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,30 @@ export let userActivityWebhook = new WebhookSender({
},
});

export let questActivityWebhook = new WebhookSender({
type: 'questActivity',
webhookFilter (hook, data) {
let { type } = data;
return hook.options[type];
},
transformData (data) {
let { group, quest, type } = data;

let dataToSend = {
type,
group: {
id: group.id,
name: group.name,
},
quest: {
key: quest.key,
},
};

return dataToSend;
},
});

export let groupChatReceivedWebhook = new WebhookSender({
type: 'groupChatReceived',
webhookFilter (hook, data) {
Expand Down
102 changes: 61 additions & 41 deletions website/server/models/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import * as Tasks from './task';
import validator from 'validator';
import { removeFromArray } from '../libs/collectionManipulators';
import payments from '../libs/payments/payments';
import { groupChatReceivedWebhook } from '../libs/webhook';
import {
groupChatReceivedWebhook,
questActivityWebhook,
} from '../libs/webhook';
import {
InternalServerError,
BadRequest,
Expand Down Expand Up @@ -648,20 +651,25 @@ schema.methods.startQuest = async function startQuest (user) {
removeFromArray(nonUserQuestMembers, user._id);

// remove any users from quest.members who aren't in the party
let partyId = this._id;
let questMembers = this.quest.members;
await Promise.all(Object.keys(this.quest.members).map(memberId => {
return User.findOne({_id: memberId, 'party._id': partyId})
.select('_id')
.lean()
.exec()
.then((member) => {
// and get the data necessary to send webhooks
const members = [];

await User.find({
_id: {$in: Object.keys(this.quest.members)},
'party._id': this._id,
})
.select('party.quest items.quests auth preferences.emailNotifications preferences.pushNotifications pushDevices profile.name webhooks')
.exec()
.then(partyMembers => {
partyMembers.forEach(member => {
if (!member) {
delete questMembers[memberId];
delete this.quest.members[member._id];
} else {
members.push(member);
}
return;
});
}));
});


if (userIsParticipating) {
user.party.quest.key = this.quest.key;
Expand All @@ -670,28 +678,33 @@ schema.methods.startQuest = async function startQuest (user) {
user.markModified('party.quest');
}

const promises = [];

// Remove the quest from the quest leader items (if they are the current user)
if (this.quest.leader === user._id) {
user.items.quests[this.quest.key] -= 1;
user.markModified('items.quests');
promises.push(user.save());
} else { // another user is starting the quest, update the leader separately
await User.update({_id: this.quest.leader}, {
promises.push(User.update({_id: this.quest.leader}, {
$inc: {
[`items.quests.${this.quest.key}`]: -1,
},
}).exec();
}).exec());
}

// update the remaining users
await User.update({
promises.push(User.update({
_id: { $in: nonUserQuestMembers },
}, {
$set: {
'party.quest.key': this.quest.key,
'party.quest.progress.down': 0,
'party.quest.completed': null,
},
}, { multi: true }).exec();
}, { multi: true }).exec());

await Promise.all(promises);

// update the users who are not participating
// Do not block updates
Expand All @@ -703,38 +716,45 @@ schema.methods.startQuest = async function startQuest (user) {
},
}, { multi: true }).exec();

// send notifications in the background without blocking
User.find(
{ _id: { $in: nonUserQuestMembers } },
'party.quest items.quests auth.facebook auth.local preferences.emailNotifications preferences.pushNotifications pushDevices profile.name'
).exec().then((membersToNotify) => {
let membersToEmail = _.filter(membersToNotify, (member) => {
const newMessage = this.sendChat(`\`Your quest, ${quest.text('en')}, has started.\``, null, {
participatingMembers: this.getParticipatingQuestMembers().join(', '),
});
await newMessage.save();

const membersToEmail = [];
const pushTitle = quest.text();
const pushMessage = `${shared.i18n.t('questStarted')}: ${quest.text()}`;

// send notifications and webhooks in the background without blocking
members.forEach(member => {
if (member._id !== user._id) {
// send push notifications and filter users that disabled emails
return member.preferences.emailNotifications.questStarted !== false &&
member._id !== user._id;
});
sendTxnEmail(membersToEmail, 'quest-started', [
{ name: 'PARTY_URL', content: '/party' },
]);
let membersToPush = _.filter(membersToNotify, (member) => {
if (member.preferences.emailNotifications.questStarted !== false) {
membersToEmail.push(member);
}

// send push notifications and filter users that disabled emails
return member.preferences.pushNotifications.questStarted !== false &&
member._id !== user._id;
});
_.each(membersToPush, (member) => {
sendPushNotification(member,
{
title: quest.text(),
message: `${shared.i18n.t('questStarted')}: ${quest.text()}`,
if (member.preferences.pushNotifications.questStarted !== false) {
sendPushNotification(member, {
title: pushTitle,
message: pushMessage,
identifier: 'questStarted',
});
}
}

// Send webhooks
questActivityWebhook.send(user, {
type: 'questStarted',
group: this,
quest,
});
});
const newMessage = this.sendChat(`\`Your quest, ${quest.text('en')}, has started.\``, null, {
participatingMembers: this.getParticipatingQuestMembers().join(', '),
});

await newMessage.save();
// Send emails in bulk
sendTxnEmail(membersToEmail, 'quest-started', [
{ name: 'PARTY_URL', content: '/party' },
]);
};

schema.methods.sendGroupChatReceivedWebhooks = function sendGroupChatReceivedWebhooks (chat) {
Expand Down
15 changes: 15 additions & 0 deletions website/server/models/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ const USER_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
leveledUp: false,
});

const QUEST_ACTIVITY_DEFAULT_OPTIONS = Object.freeze({
questStarted: false,
questFinished: false,
});

export let schema = new Schema({
id: {
type: String,
Expand Down Expand Up @@ -96,6 +101,16 @@ schema.methods.formatOptions = function formatOptions (res) {
_.defaults(this.options, USER_ACTIVITY_DEFAULT_OPTIONS);
this.options = _.pick(this.options, Object.keys(USER_ACTIVITY_DEFAULT_OPTIONS));

let invalidOption = Object.keys(this.options)
.find(option => typeof this.options[option] !== 'boolean');

if (invalidOption) {
throw new BadRequest(res.t('webhookBooleanOption', { option: invalidOption }));
}
} else if (this.type === 'questActivity') {
_.defaults(this.options, QUEST_ACTIVITY_DEFAULT_OPTIONS);
this.options = _.pick(this.options, Object.keys(QUEST_ACTIVITY_DEFAULT_OPTIONS));

let invalidOption = Object.keys(this.options)
.find(option => typeof this.options[option] !== 'boolean');

Expand Down

0 comments on commit 68e5b6e

Please sign in to comment.