mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
@@ -8,7 +8,7 @@ describe('common.fns.updateStats', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
user = generateUser();
|
||||
// user.addNotification = sinon.spy();
|
||||
user.addNotification = sinon.spy();
|
||||
});
|
||||
|
||||
context('No Hp', () => {
|
||||
@@ -110,14 +110,14 @@ describe('common.fns.updateStats', () => {
|
||||
expect(user.stats.points).to.eql(10);
|
||||
});
|
||||
|
||||
xit('add user notification when drops are enabled', () => {
|
||||
it('add user notification when drops are enabled', () => {
|
||||
user.stats.lvl = 3;
|
||||
updateStats(user, { });
|
||||
expect(user.addNotification).to.be.calledOnce;
|
||||
expect(user.addNotification).to.be.calledWith('DROPS_ENABLED');
|
||||
});
|
||||
|
||||
xit('add user notification when the user levels up', () => {
|
||||
it('add user notification when the user levels up', () => {
|
||||
const initialLvl = user.stats.lvl;
|
||||
updateStats(user, {
|
||||
exp: 3000,
|
||||
@@ -129,7 +129,7 @@ describe('common.fns.updateStats', () => {
|
||||
});
|
||||
});
|
||||
|
||||
xit('add user notification when rebirth is enabled', () => {
|
||||
it('add user notification when rebirth is enabled', () => {
|
||||
user.stats.lvl = 51;
|
||||
updateStats(user, { });
|
||||
expect(user.addNotification).to.be.calledTwice; // once is for drops enabled
|
||||
|
||||
@@ -20,7 +20,7 @@ module.exports = function updateStats (user, stats, req = {}, analytics) {
|
||||
if (stats.exp >= experienceToNextLevel) {
|
||||
user.stats.exp = stats.exp;
|
||||
|
||||
// const initialLvl = user.stats.lvl;
|
||||
const initialLvl = user.stats.lvl;
|
||||
|
||||
while (stats.exp >= experienceToNextLevel) {
|
||||
stats.exp -= experienceToNextLevel;
|
||||
@@ -50,13 +50,12 @@ module.exports = function updateStats (user, stats, req = {}, analytics) {
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: Tmp disable to see if this is causing concurrency
|
||||
// const newLvl = user.stats.lvl;
|
||||
//
|
||||
// if (user.addNotification) user.addNotification('LEVELED_UP', {
|
||||
// initialLvl,
|
||||
// newLvl,
|
||||
// });
|
||||
const newLvl = user.stats.lvl;
|
||||
|
||||
if (user.addNotification) user.addNotification('LEVELED_UP', {
|
||||
initialLvl,
|
||||
newLvl,
|
||||
});
|
||||
}
|
||||
|
||||
user.stats.exp = stats.exp;
|
||||
|
||||
@@ -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,
|
||||
@@ -648,20 +651,24 @@ 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')
|
||||
// and get the data necessary to send webhooks
|
||||
const members = [];
|
||||
|
||||
await User.find({
|
||||
_id: {$in: Object.keys(this.quest.members)},
|
||||
})
|
||||
.select('party.quest party._id items.quests auth preferences.emailNotifications preferences.pushNotifications pushDevices profile.name webhooks')
|
||||
.lean()
|
||||
.exec()
|
||||
.then((member) => {
|
||||
if (!member) {
|
||||
delete questMembers[memberId];
|
||||
.then(partyMembers => {
|
||||
partyMembers.forEach(member => {
|
||||
if (!member.party || member.party._id !== this._id) {
|
||||
delete this.quest.members[member._id];
|
||||
} else {
|
||||
members.push(member);
|
||||
}
|
||||
return;
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
if (userIsParticipating) {
|
||||
user.party.quest.key = this.quest.key;
|
||||
@@ -670,20 +677,23 @@ 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: {
|
||||
@@ -691,7 +701,9 @@ schema.methods.startQuest = async function startQuest (user) {
|
||||
'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
|
||||
@@ -703,38 +715,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) => {
|
||||
// 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) => {
|
||||
// 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()}`,
|
||||
identifier: 'questStarted',
|
||||
});
|
||||
});
|
||||
});
|
||||
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
|
||||
if (member.preferences.emailNotifications.questStarted !== false) {
|
||||
membersToEmail.push(member);
|
||||
}
|
||||
|
||||
// send push notifications and filter users that disabled emails
|
||||
if (member.preferences.pushNotifications.questStarted !== false) {
|
||||
sendPushNotification(member, {
|
||||
title: pushTitle,
|
||||
message: pushMessage,
|
||||
identifier: 'questStarted',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Send webhooks
|
||||
questActivityWebhook.send(member, {
|
||||
type: 'questStarted',
|
||||
group: this,
|
||||
quest,
|
||||
});
|
||||
});
|
||||
|
||||
// Send emails in bulk
|
||||
sendTxnEmail(membersToEmail, 'quest-started', [
|
||||
{ name: 'PARTY_URL', content: '/party' },
|
||||
]);
|
||||
};
|
||||
|
||||
schema.methods.sendGroupChatReceivedWebhooks = function sendGroupChatReceivedWebhooks (chat) {
|
||||
@@ -753,15 +772,14 @@ schema.methods.sendGroupChatReceivedWebhooks = function sendGroupChatReceivedWeb
|
||||
query.guilds = this._id;
|
||||
}
|
||||
|
||||
/* User.find(query).select({webhooks: 1}).lean().exec().then((users) => {
|
||||
User.find(query).select({webhooks: 1}).lean().exec().then((users) => {
|
||||
users.forEach((user) => {
|
||||
let { webhooks } = user;
|
||||
groupChatReceivedWebhook.send(webhooks, {
|
||||
groupChatReceivedWebhook.send(user, {
|
||||
group: this,
|
||||
chat,
|
||||
});
|
||||
});
|
||||
}); */
|
||||
});
|
||||
};
|
||||
|
||||
schema.statics.cleanQuestProgress = _cleanQuestProgress;
|
||||
@@ -907,6 +925,31 @@ schema.methods.finishQuest = async function finishQuest (quest) {
|
||||
}));
|
||||
}
|
||||
|
||||
// Send webhooks in background
|
||||
// @TODO move the find users part to a worker as well, not just the http request
|
||||
User.find({
|
||||
_id: {$in: participants},
|
||||
webhooks: {
|
||||
$elemMatch: {
|
||||
type: 'questActivity',
|
||||
'options.questFinished': true,
|
||||
},
|
||||
},
|
||||
})
|
||||
.select('_id webhooks')
|
||||
.lean()
|
||||
.exec()
|
||||
.then(participantsWithWebhook => {
|
||||
participantsWithWebhook.forEach(participantWithWebhook => {
|
||||
// Send webhooks
|
||||
questActivityWebhook.send(participantWithWebhook, {
|
||||
type: 'questFinished',
|
||||
group: this,
|
||||
quest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return await Promise.all(promises);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user