From 1685b7285f4e61830b0d62b6072c7022ea06f519 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Fri, 8 Apr 2016 15:56:11 -0500 Subject: [PATCH] Ported reroll. Added unit tests. Added reroll route. Added integration tests --- common/locales/en/api-v3.json | 3 +- common/script/index.js | 2 + common/script/ops/releaseBoth.js | 7 ++- common/script/ops/releaseMounts.js | 3 +- common/script/ops/releasePets.js | 3 +- common/script/ops/reroll.js | 43 +++++++------ tasks/gulp-eslint.js | 4 -- .../integration/user/POST-user_reroll.test.js | 54 ++++++++++++++++ test/common/ops/reroll.js | 63 +++++++++++++++++++ website/src/controllers/api-v3/user.js | 30 +++++++++ 10 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 test/api/v3/integration/user/POST-user_reroll.test.js create mode 100644 test/common/ops/reroll.js diff --git a/common/locales/en/api-v3.json b/common/locales/en/api-v3.json index 41fca419f9..0eb2d4b7a3 100644 --- a/common/locales/en/api-v3.json +++ b/common/locales/en/api-v3.json @@ -162,5 +162,6 @@ "alreadyUnlocked": "Item already unlocked", "cannotRevive": "Cannot revive if not dead", "rebirthComplete": "You have been reborn!", - "petNotOwned": "You do not own this pet." + "petNotOwned": "You do not own this pet.", + "rerollComplete": "Reroll complete!" } diff --git a/common/script/index.js b/common/script/index.js index e4eaca082b..ebd383c326 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -128,6 +128,7 @@ import sell from './ops/sell'; import unlock from './ops/unlock'; import revive from './ops/revive'; import rebirth from './ops/rebirth'; +import reroll from './ops/reroll'; api.ops = { scoreTask, @@ -157,6 +158,7 @@ api.ops = { unlock, revive, rebirth, + reroll, }; import handleTwoHanded from './fns/handleTwoHanded'; diff --git a/common/script/ops/releaseBoth.js b/common/script/ops/releaseBoth.js index a17d2e5f00..0ae25f6fe7 100644 --- a/common/script/ops/releaseBoth.js +++ b/common/script/ops/releaseBoth.js @@ -4,6 +4,7 @@ import { NotAuthorized, } from '../libs/errors'; import splitWhitespace from '../libs/splitWhitespace'; +import _ from 'lodash'; module.exports = function releaseBoth (user, req = {}, analytics) { let animal; @@ -20,15 +21,15 @@ module.exports = function releaseBoth (user, req = {}, analytics) { uuid: user._id, acquireMethod: 'Gems', gemCost: 6, - category: 'behavior' + category: 'behavior', }); } user.balance -= 1.5; } - user.items.currentMount = ""; - user.items.currentPet = ""; + user.items.currentMount = ''; + user.items.currentPet = ''; for (animal in content.pets) { if (user.items.pets[animal] === -1) { diff --git a/common/script/ops/releaseMounts.js b/common/script/ops/releaseMounts.js index 55d2c23fcb..0ec6fb6e7f 100644 --- a/common/script/ops/releaseMounts.js +++ b/common/script/ops/releaseMounts.js @@ -4,6 +4,7 @@ import { NotAuthorized, } from '../libs/errors'; import splitWhitespace from '../libs/splitWhitespace'; +import _ from 'lodash'; module.exports = function releaseMounts (user, req = {}, analytics) { let mount; @@ -29,7 +30,7 @@ module.exports = function releaseMounts (user, req = {}, analytics) { uuid: user._id, acquireMethod: 'Gems', gemCost: 4, - category: 'behavior' + category: 'behavior', }); } diff --git a/common/script/ops/releasePets.js b/common/script/ops/releasePets.js index 12bb48a90f..597054299a 100644 --- a/common/script/ops/releasePets.js +++ b/common/script/ops/releasePets.js @@ -4,6 +4,7 @@ import { NotAuthorized, } from '../libs/errors'; import splitWhitespace from '../libs/splitWhitespace'; +import _ from 'lodash'; module.exports = function releasePets (user, req = {}, analytics) { if (user.balance < 1) { @@ -27,7 +28,7 @@ module.exports = function releasePets (user, req = {}, analytics) { uuid: user._id, acquireMethod: 'Gems', gemCost: 4, - category: 'behavior' + category: 'behavior', }); } diff --git a/common/script/ops/reroll.js b/common/script/ops/reroll.js index f6a0862f1d..79c5eb1bbe 100644 --- a/common/script/ops/reroll.js +++ b/common/script/ops/reroll.js @@ -1,29 +1,36 @@ import i18n from '../i18n'; import _ from 'lodash'; +import { + NotAuthorized, +} from '../libs/errors'; -module.exports = function(user, req, cb, analytics) { - var analyticsData; +module.exports = function reroll (user, tasks = [], req = {}, analytics) { if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; + throw new NotAuthorized(i18n.t('notEnoughGems', req.language)); } + user.balance--; - _.each(user.tasks, function(task) { + user.stats.hp = 50; + + _.each(tasks, function resetTaskValues (task) { if (task.type !== 'reward') { - return task.value = 0; + task.value = 0; } }); - user.stats.hp = 50; - analyticsData = { - uuid: user._id, - acquireMethod: 'Gems', - gemCost: 4, - category: 'behavior' - }; - if (analytics != null) { - analytics.track('Fortify Potion', analyticsData); + + if (analytics) { + analytics.track('Fortify Potion', { + uuid: user._id, + acquireMethod: 'Gems', + gemCost: 4, + category: 'behavior', + }); } - return typeof cb === "function" ? cb(null, user) : void 0; + + let response = { + data: {user, tasks}, + message: i18n.t('rerollComplete'), + }; + + return response; }; diff --git a/tasks/gulp-eslint.js b/tasks/gulp-eslint.js index 3aaf961fb7..6bfc9599e8 100644 --- a/tasks/gulp-eslint.js +++ b/tasks/gulp-eslint.js @@ -21,10 +21,6 @@ const COMMON_FILES = [ '!./common/script/ops/deleteTask.js', '!./common/script/ops/getTag.js', '!./common/script/ops/getTags.js', - '!./common/script/ops/releaseBoth.js', - '!./common/script/ops/releaseMounts.js', - '!./common/script/ops/releasePets.js', - '!./common/script/ops/reroll.js', '!./common/script/ops/reset.js', '!./common/script/ops/sortTag.js', '!./common/script/ops/sortTask.js', diff --git a/test/api/v3/integration/user/POST-user_reroll.test.js b/test/api/v3/integration/user/POST-user_reroll.test.js new file mode 100644 index 0000000000..ac11b0d463 --- /dev/null +++ b/test/api/v3/integration/user/POST-user_reroll.test.js @@ -0,0 +1,54 @@ +import { + generateUser, + generateDaily, + generateReward, + translate as t, +} from '../../../../helpers/api-integration/v3'; + +describe('POST /user/reroll', () => { + let user; + + beforeEach(async () => { + user = await generateUser(); + }); + + it('returns an error when user balance is too low', async () => { + await expect(user.post('/user/reroll')) + .to.eventually.be.rejected.and.to.eql({ + code: 401, + error: 'NotAuthorized', + message: t('notEnoughGems'), + }); + }); + + // More tests in common code unit tests + + it('resets user\'s tasks', async () => { + await user.update({ + balance: 2, + }); + + let daily = await generateDaily({ + text: 'test habit', + type: 'daily', + userId: user._id, + }); + + let reward = await generateReward({ + text: 'test reward', + type: 'reward', + value: 1, + userId: user._id, + }); + + let response = await user.post('/user/reroll'); + await user.sync(); + + let updatedDaily = await user.get(`/tasks/${daily._id}`); + let updatedReward = await user.get(`/tasks/${reward._id}`); + + expect(response.message).to.equal(t('rerollComplete')); + expect(updatedDaily.value).to.equal(0); + expect(updatedReward.value).to.equal(1); + }); +}); diff --git a/test/common/ops/reroll.js b/test/common/ops/reroll.js new file mode 100644 index 0000000000..8cadd3fa6c --- /dev/null +++ b/test/common/ops/reroll.js @@ -0,0 +1,63 @@ +import reroll from '../../../common/script/ops/reroll'; +import i18n from '../../../common/script/i18n'; +import { + generateUser, + generateDaily, + generateReward, +} from '../../helpers/common.helper'; +import { + NotAuthorized, +} from '../../../common/script/libs/errors'; + +describe('shared.ops.reroll', () => { + let user; + let tasks = []; + + beforeEach(() => { + user = generateUser(); + user.balance = 1; + tasks = [generateDaily(), generateReward()]; + }); + + it('returns an error when user balance is too low', (done) => { + user.balance = 0; + + try { + reroll(user); + } catch (err) { + expect(err).to.be.an.instanceof(NotAuthorized); + expect(err.message).to.equal(i18n.t('notEnoughGems')); + done(); + } + }); + + it('rerolls a user with enough gems', () => { + let response = reroll(user); + + expect(response.message).to.equal(i18n.t('rerollComplete')); + }); + + it('reduces a user\'s balance', () => { + reroll(user); + + expect(user.balance).to.equal(0); + }); + + it('resets a user\'s health points', () => { + user.stats.hp = 40; + + reroll(user); + + expect(user.stats.hp).to.equal(50); + }); + + it('resets user\'s taks values except for rewards to 0', () => { + tasks[0].value = 1; + tasks[1].value = 1; + + reroll(user, tasks); + + expect(tasks[0].value).to.equal(0); + expect(tasks[1].value).to.equal(1); + }); +}); diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index 1691d78f88..a1021cb7ed 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -974,4 +974,34 @@ api.userRebirth = { }, }; +/* +* @api {post} /user/reroll Rerolls a user. +* @apiVersion 3.0.0 +* @apiName UserReroll +* @apiGroup User +* +* @apiSuccess {Object} data `user` +*/ +api.userReroll = { + method: 'POST', + middlewares: [authWithHeaders(), cron], + url: '/user/reroll', + async handler (req, res) { + let user = res.locals.user; + let query = { + userId: user._id, + type: {$in: ['daily', 'habit', 'todo']}, + }; + let tasks = await Tasks.Task.find(query).exec(); + let rerollResponse = common.ops.reroll(user, tasks, req, res.analytics); + + let promises = tasks.map(task => task.save()); + promises.push(user.save()); + + await Q.all(promises); + + res.respond(200, rerollResponse); + }, +}; + module.exports = api;