diff --git a/test/api/v3/integration/tasks/POST-tasks_id_score_direction.test.js b/test/api/v3/integration/tasks/POST-tasks_id_score_direction.test.js index 43455d2d44..0ee5f710b6 100644 --- a/test/api/v3/integration/tasks/POST-tasks_id_score_direction.test.js +++ b/test/api/v3/integration/tasks/POST-tasks_id_score_direction.test.js @@ -82,48 +82,48 @@ describe('POST /tasks/:id/score/:direction', () => { expect(body.delta).to.be.greaterThan(0); }); - // context('sending user activity webhooks', () => { - // before(async () => { - // await server.start(); - // }); - // - // after(async () => { - // await server.close(); - // }); - // - // it('sends user activity webhook when the user levels up', async () => { - // let uuid = generateUUID(); - // - // await user.post('/user/webhook', { - // url: `http://localhost:${server.port}/webhooks/${uuid}`, - // type: 'userActivity', - // enabled: true, - // options: { - // leveledUp: true, - // }, - // }); - // - // const initialLvl = user.stats.lvl; - // - // await user.update({ - // 'stats.exp': 3000, - // }); - // let task = await user.post('/tasks/user', { - // text: 'test habit', - // type: 'habit', - // }); - // - // await user.post(`/tasks/${task.id}/score/up`); - // await user.sync(); - // await sleep(); - // - // let body = server.getWebhookData(uuid); - // - // expect(body.type).to.eql('leveledUp'); - // expect(body.initialLvl).to.eql(initialLvl); - // expect(body.finalLvl).to.eql(user.stats.lvl); - // }); - // }); + context('sending user activity webhooks', () => { + before(async () => { + await server.start(); + }); + + after(async () => { + await server.close(); + }); + + it('sends user activity webhook when the user levels up', async () => { + let uuid = generateUUID(); + + await user.post('/user/webhook', { + url: `http://localhost:${server.port}/webhooks/${uuid}`, + type: 'userActivity', + enabled: true, + options: { + leveledUp: true, + }, + }); + + const initialLvl = user.stats.lvl; + + await user.update({ + 'stats.exp': 3000, + }); + let task = await user.post('/tasks/user', { + text: 'test habit', + type: 'habit', + }); + + await user.post(`/tasks/${task.id}/score/up`); + await user.sync(); + await sleep(); + + let body = server.getWebhookData(uuid); + + expect(body.type).to.eql('leveledUp'); + expect(body.initialLvl).to.eql(initialLvl); + expect(body.finalLvl).to.eql(user.stats.lvl); + }); + }); }); context('todos', () => { diff --git a/test/common/fns/updateStats.test.js b/test/common/fns/updateStats.test.js index e10ad63c98..de14a8ffff 100644 --- a/test/common/fns/updateStats.test.js +++ b/test/common/fns/updateStats.test.js @@ -8,7 +8,7 @@ describe('common.fns.updateStats', () => { beforeEach(() => { user = generateUser(); - // user.addNotification = sinon.spy(); + user.addNotification = sinon.spy(); }); context('No Hp', () => { @@ -110,26 +110,25 @@ 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, }); - expect(user.addNotification).to.be.calledTwice; // once is for drops enabled - expect(user.addNotification).to.be.calledWith('LEVELED_UP', { + expect(user._tmp.leveledUp).to.eql([{ initialLvl, newLvl: user.stats.lvl, - }); + }]); }); - 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 diff --git a/website/common/script/fns/updateStats.js b/website/common/script/fns/updateStats.js index cfe3310153..65d466f1b0 100644 --- a/website/common/script/fns/updateStats.js +++ b/website/common/script/fns/updateStats.js @@ -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._tmp.leveledUp) user._tmp.leveledUp = []; + user._tmp.leveledUp.push({ + initialLvl, + newLvl, + }); } user.stats.exp = stats.exp; diff --git a/website/server/models/user/hooks.js b/website/server/models/user/hooks.js index 81d4e8b06d..2de4550627 100644 --- a/website/server/models/user/hooks.js +++ b/website/server/models/user/hooks.js @@ -6,7 +6,9 @@ import * as Tasks from '../task'; import { model as UserNotification, } from '../userNotification'; - +import { + userActivityWebhook, +} from '../../libs/webhook'; import schema from './schema'; schema.plugin(baseModel, { @@ -15,6 +17,11 @@ schema.plugin(baseModel, { private: ['auth.local.hashed_password', 'auth.local.passwordHashMethod', 'auth.local.salt', '_cronSignature', '_ABtests'], toJSONTransform: function userToJSON (plainObj, originalDoc) { plainObj._tmp = originalDoc._tmp; // be sure to send down drop notifs + + if (plainObj._tmp && plainObj._tmp.leveledUp) { + delete plainObj._tmp.leveledUp; + } + delete plainObj.filters; if (originalDoc.notifications) { @@ -314,3 +321,23 @@ schema.pre('save', true, function preSaveUser (next, done) { schema.pre('update', function preUpdateUser () { this.update({}, {$inc: {_v: 1}}); }); + +schema.post('save', function postSaveUser () { + // Send a webhook notification when the user has leveled up + if (this._tmp && this._tmp.leveledUp && this._tmp.leveledUp.length > 0) { + const lvlUpNotifications = this._tmp.leveledUp; + const firstLvlNotification = lvlUpNotifications[0]; + const lastLvlNotification = lvlUpNotifications[lvlUpNotifications.length - 1]; + + const initialLvl = firstLvlNotification.initialLvl; + const finalLvl = lastLvlNotification.newLvl; + + userActivityWebhook.send(this, { + type: 'leveledUp', + initialLvl, + finalLvl, + }); + + this._tmp.leveledUp = []; + } +});