diff --git a/common/locales/en/api-v3.json b/common/locales/en/api-v3.json index b96fa01694..5ab3b3399e 100644 --- a/common/locales/en/api-v3.json +++ b/common/locales/en/api-v3.json @@ -150,5 +150,6 @@ "eventRequired": "\"req.params.event\" is required.", "countRequired": "\"req.query.count\" is required.", "petsReleased": "Pets released.", - "mountsAndPetsReleased": "Mounts and pets released" + "mountsAndPetsReleased": "Mounts and pets released", + "mountsReleased": "Mounts released" } diff --git a/common/script/index.js b/common/script/index.js index 019dcef817..7482a09fd7 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -120,6 +120,7 @@ import readCard from './ops/readCard'; import openMysteryItem from './ops/openMysteryItem'; import releasePets from './ops/releasePets'; import releaseBoth from './ops/releaseBoth'; +import releaseMounts from './ops/releaseMounts'; api.ops = { scoreTask, @@ -141,6 +142,7 @@ api.ops = { openMysteryItem, releasePets, releaseBoth, + releaseMounts, }; import handleTwoHanded from './fns/handleTwoHanded'; diff --git a/common/script/ops/releaseMounts.js b/common/script/ops/releaseMounts.js index 4aefab6b40..55d2c23fcb 100644 --- a/common/script/ops/releaseMounts.js +++ b/common/script/ops/releaseMounts.js @@ -1,32 +1,42 @@ import content from '../content/index'; import i18n from '../i18n'; +import { + NotAuthorized, +} from '../libs/errors'; +import splitWhitespace from '../libs/splitWhitespace'; + +module.exports = function releaseMounts (user, req = {}, analytics) { + let mount; -module.exports = function(user, req, cb, analytics) { - var analyticsData, mount; if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - user.balance -= 1; - user.items.currentMount = ""; - for (mount in content.pets) { - user.items.mounts[mount] = null; - } - if (!user.achievements.mountMasterCount) { - user.achievements.mountMasterCount = 0; - } - user.achievements.mountMasterCount++; + throw new NotAuthorized(i18n.t('notEnoughGems', req.language)); } - analyticsData = { - uuid: user._id, - acquireMethod: 'Gems', - gemCost: 4, - category: 'behavior' + + user.balance -= 1; + user.items.currentMount = ''; + + for (mount in content.pets) { + user.items.mounts[mount] = null; + } + + if (!user.achievements.mountMasterCount) { + user.achievements.mountMasterCount = 0; + } + user.achievements.mountMasterCount++; + + if (analytics) { + analytics.track('release mounts', { + uuid: user._id, + acquireMethod: 'Gems', + gemCost: 4, + category: 'behavior' + }); + } + + let response = { + data: _.pick(user, splitWhitespace('mounts')), + message: i18n.t('mountsReleased'), }; - if (analytics != null) { - analytics.track('release mounts', analyticsData); - } - return typeof cb === "function" ? cb(null, user) : void 0; + + return response; }; diff --git a/test/api/v3/integration/user/POST-user_release_mounts.test.js b/test/api/v3/integration/user/POST-user_release_mounts.test.js new file mode 100644 index 0000000000..86391599f0 --- /dev/null +++ b/test/api/v3/integration/user/POST-user_release_mounts.test.js @@ -0,0 +1,42 @@ +import { + generateUser, + translate as t, +} from '../../../../helpers/api-integration/v3'; + +describe('POST /user/release-mounts', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(async () => { + user = await generateUser({ + 'items.currentMount': animal, + 'items.mounts': {animal: true}, + }); + }); + + it('returns an error when user balance is too low', async () => { + await expect(user.post('/user/release-mounts')) + .to.eventually.be.rejected.and.to.eql({ + code: 401, + error: 'NotAuthorized', + message: t('notEnoughGems'), + }); + }); + + // More tests in common code unit tests + + it('releases mounts', async () => { + await user.update({ + balance: 1, + }); + + let response = await user.post('/user/release-mounts'); + await user.sync(); + + expect(response.message).to.equal(t('mountsReleased')); + expect(user.balance).to.equal(0); + expect(user.items.currentMount).to.be.empty; + expect(user.items.mounts[animal]).to.equal(null); + expect(user.achievements.mountMasterCount).to.equal(1); + }); +}); diff --git a/test/common/ops/releaseMounts.js b/test/common/ops/releaseMounts.js new file mode 100644 index 0000000000..80429b726f --- /dev/null +++ b/test/common/ops/releaseMounts.js @@ -0,0 +1,57 @@ +import releaseMounts from '../../../common/script/ops/releaseMounts'; +import i18n from '../../../common/script/i18n'; +import { + generateUser, +} from '../../helpers/common.helper'; +import { + NotAuthorized, +} from '../../../common/script/libs/errors'; + +describe('shared.ops.releaseMounts', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(() => { + user = generateUser(); + user.items.currentMount = animal; + user.items.mounts[animal] = true; + user.balance = 1; + }); + + it('returns an error when user balance is too low', (done) => { + user.balance = 0; + + try { + releaseMounts(user); + } catch (err) { + expect(err).to.be.an.instanceof(NotAuthorized); + expect(err.message).to.equal(i18n.t('notEnoughGems')); + done(); + } + }); + + it('releases mounts', () => { + let response = releaseMounts(user); + + expect(response.message).to.equal(i18n.t('mountsReleased')); + expect(user.items.mounts[animal]).to.equal(null); + }); + + it('removes currentMount', () => { + releaseMounts(user); + + expect(user.items.currentMount).to.be.empty; + }); + + it('increases mountMasterCount achievement', () => { + releaseMounts(user); + + expect(user.achievements.mountMasterCount).to.equal(1); + }); + + it('subtracts gems from balance', () => { + releaseMounts(user); + + expect(user.balance).to.equal(0); + }); +}); diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index ec21c36d0b..445c72d34e 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -804,4 +804,24 @@ api.userReleaseBoth = { }, }; +/* +* @api {post} /user/release-mounts Released mounts. +* @apiVersion 3.0.0 +* @apiName UserReleaseMounts +* @apiGroup User +* +* @apiSuccess {Object} data `mounts` +*/ +api.userReleaseMounts = { + method: 'POST', + middlewares: [authWithHeaders(), cron], + url: '/user/release-mounts', + async handler (req, res) { + let user = res.locals.user; + let releaseMountsResponse = common.ops.releaseMounts(user, req, res.analytics); + await user.save(); + res.respond(200, releaseMountsResponse); + }, +}; + module.exports = api;