diff --git a/common/locales/en/api-v3.json b/common/locales/en/api-v3.json index 9dcec829a9..f66c403aac 100644 --- a/common/locales/en/api-v3.json +++ b/common/locales/en/api-v3.json @@ -150,5 +150,8 @@ "eventRequired": "\"req.params.event\" is required.", "countRequired": "\"req.query.count\" is required.", "invalidUrl": "invalid url", - "invalidEnabled": "the \"enabled\" parameter should be a boolean" + "invalidEnabled": "the \"enabled\" parameter should be a boolean", + "petsReleased": "Pets released.", + "mountsAndPetsReleased": "Mounts and pets released", + "mountsReleased": "Mounts released" } diff --git a/common/script/index.js b/common/script/index.js index 10540046c4..ace26cf8da 100644 --- a/common/script/index.js +++ b/common/script/index.js @@ -121,6 +121,9 @@ import openMysteryItem from './ops/openMysteryItem'; import addWebhook from './ops/addWebhook'; import updateWebhook from './ops/updateWebhook'; import deleteWebhook from './ops/deleteWebhook'; +import releasePets from './ops/releasePets'; +import releaseBoth from './ops/releaseBoth'; +import releaseMounts from './ops/releaseMounts'; api.ops = { scoreTask, @@ -143,6 +146,9 @@ api.ops = { addWebhook, updateWebhook, deleteWebhook, + releasePets, + releaseBoth, + releaseMounts, }; import handleTwoHanded from './fns/handleTwoHanded'; diff --git a/common/script/ops/addWebhook.js b/common/script/ops/addWebhook.js index 0300afef28..ea6b32ed68 100644 --- a/common/script/ops/addWebhook.js +++ b/common/script/ops/addWebhook.js @@ -2,16 +2,16 @@ import refPush from '../libs/refPush'; import validator from 'validator'; import i18n from '../i18n'; import { - NotFound, BadRequest, } from '../libs/errors'; +import _ from 'lodash'; -module.exports = function(user, req) { - var wh; +module.exports = function addWebhook (user, req = {}) { + let wh; wh = user.preferences.webhooks; - if(!validator.isURL(req.body.url)) throw new BadRequest(i18n.t('invalidUrl', req.language)); - if(!validator.isBoolean(req.body.enabled)) throw new BadRequest(i18n.t('invalidEnabled', req.language)); + if (!validator.isURL(_.get(req, 'body.url'))) throw new BadRequest(i18n.t('invalidUrl', req.language)); + if (!validator.isBoolean(_.get(req, 'body.enabled'))) throw new BadRequest(i18n.t('invalidEnabled', req.language)); user.markModified('preferences.webhooks'); diff --git a/common/script/ops/deleteWebhook.js b/common/script/ops/deleteWebhook.js index 45a5c4388c..03eb622892 100644 --- a/common/script/ops/deleteWebhook.js +++ b/common/script/ops/deleteWebhook.js @@ -1,5 +1,6 @@ +import _ from 'lodash'; -module.exports = function(user, req) { - delete user.preferences.webhooks[req.params.id]; +module.exports = function deleteWebhook (user, req) { + delete user.preferences.webhooks[_.get(req, 'params.id')]; user.markModified('preferences.webhooks'); }; diff --git a/common/script/ops/releaseBoth.js b/common/script/ops/releaseBoth.js index a782581f85..a17d2e5f00 100644 --- a/common/script/ops/releaseBoth.js +++ b/common/script/ops/releaseBoth.js @@ -1,50 +1,65 @@ import content from '../content/index'; import i18n from '../i18n'; +import { + NotAuthorized, +} from '../libs/errors'; +import splitWhitespace from '../libs/splitWhitespace'; + +module.exports = function releaseBoth (user, req = {}, analytics) { + let animal; -module.exports = function(user, req, cb, analytics) { - var analyticsData, animal, giveTriadBingo; if (user.balance < 1.5 && !user.achievements.triadBingo) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - giveTriadBingo = true; - if (!user.achievements.triadBingo) { - analyticsData = { + throw new NotAuthorized(i18n.t('notEnoughGems', req.language)); + } + + let giveTriadBingo = true; + + if (!user.achievements.triadBingo) { + if (analytics) { + analytics.track('release pets & mounts', { uuid: user._id, acquireMethod: 'Gems', gemCost: 6, category: 'behavior' - }; - if (typeof analytics !== "undefined" && analytics !== null) { - analytics.track('release pets & mounts', analyticsData); - } - user.balance -= 1.5; - } - user.items.currentMount = ""; - user.items.currentPet = ""; - for (animal in content.pets) { - if (user.items.pets[animal] === -1) { - giveTriadBingo = false; - } - user.items.pets[animal] = 0; - user.items.mounts[animal] = null; - } - if (!user.achievements.beastMasterCount) { - user.achievements.beastMasterCount = 0; - } - user.achievements.beastMasterCount++; - if (!user.achievements.mountMasterCount) { - user.achievements.mountMasterCount = 0; - } - user.achievements.mountMasterCount++; - if (giveTriadBingo) { - if (!user.achievements.triadBingoCount) { - user.achievements.triadBingoCount = 0; - } - user.achievements.triadBingoCount++; + }); } + + user.balance -= 1.5; } - return typeof cb === "function" ? cb(null, user) : void 0; + + user.items.currentMount = ""; + user.items.currentPet = ""; + + for (animal in content.pets) { + if (user.items.pets[animal] === -1) { + giveTriadBingo = false; + } + + user.items.pets[animal] = 0; + user.items.mounts[animal] = null; + } + + if (!user.achievements.beastMasterCount) { + user.achievements.beastMasterCount = 0; + } + user.achievements.beastMasterCount++; + + if (!user.achievements.mountMasterCount) { + user.achievements.mountMasterCount = 0; + } + user.achievements.mountMasterCount++; + + if (giveTriadBingo) { + if (!user.achievements.triadBingoCount) { + user.achievements.triadBingoCount = 0; + } + user.achievements.triadBingoCount++; + } + + let response = { + data: _.pick(user, splitWhitespace('achievements')), + message: i18n.t('mountsAndPetsReleased'), + }; + + return response; }; 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/common/script/ops/releasePets.js b/common/script/ops/releasePets.js index a4b452cd86..12bb48a90f 100644 --- a/common/script/ops/releasePets.js +++ b/common/script/ops/releasePets.js @@ -1,32 +1,40 @@ import content from '../content/index'; import i18n from '../i18n'; +import { + NotAuthorized, +} from '../libs/errors'; +import splitWhitespace from '../libs/splitWhitespace'; -module.exports = function(user, req, cb, analytics) { - var analyticsData, pet; +module.exports = function releasePets (user, req = {}, analytics) { if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - user.balance -= 1; - for (pet in content.pets) { - user.items.pets[pet] = 0; - } - if (!user.achievements.beastMasterCount) { - user.achievements.beastMasterCount = 0; - } - user.achievements.beastMasterCount++; - user.items.currentPet = ""; + throw new NotAuthorized(i18n.t('notEnoughGems', req.language)); } - analyticsData = { - uuid: user._id, - acquireMethod: 'Gems', - gemCost: 4, - category: 'behavior' + + user.balance -= 1; + user.items.currentPet = ''; + + for (let pet in content.pets) { + user.items.pets[pet] = 0; + } + + if (!user.achievements.beastMasterCount) { + user.achievements.beastMasterCount = 0; + } + user.achievements.beastMasterCount++; + + if (analytics) { + analytics.track('release pets', { + uuid: user._id, + acquireMethod: 'Gems', + gemCost: 4, + category: 'behavior' + }); + } + + let response = { + data: _.pick(user, splitWhitespace('user.items.pets')), + message: i18n.t('petsReleased'), }; - if (analytics != null) { - analytics.track('release pets', analyticsData); - } - return typeof cb === "function" ? cb(null, user) : void 0; + + return response; }; diff --git a/common/script/ops/updateWebhook.js b/common/script/ops/updateWebhook.js index 27098c4c4a..0de2f5fa47 100644 --- a/common/script/ops/updateWebhook.js +++ b/common/script/ops/updateWebhook.js @@ -1,16 +1,16 @@ -import _ from 'lodash'; import validator from 'validator'; import i18n from '../i18n'; import { - NotFound, BadRequest, } from '../libs/errors'; -module.exports = function(user, req) { - if(!validator.isURL(req.body.url)) throw new BadRequest(i18n.t('invalidUrl', req.language)); - if(!validator.isBoolean(req.body.enabled)) throw new BadRequest(i18n.t('invalidEnabled', req.language)); +module.exports = function updateWebhook (user, req) { + if (!validator.isURL(req.body.url)) throw new BadRequest(i18n.t('invalidUrl', req.language)); + if (!validator.isBoolean(req.body.enabled)) throw new BadRequest(i18n.t('invalidEnabled', req.language)); user.markModified('preferences.webhooks'); user.preferences.webhooks[req.params.id].url = req.body.url; user.preferences.webhooks[req.params.id].enabled = req.body.enabled; + + return user.preferences.webhooks[req.params.id]; }; diff --git a/tasks/gulp-eslint.js b/tasks/gulp-eslint.js index e71cde8258..d8dbf6b992 100644 --- a/tasks/gulp-eslint.js +++ b/tasks/gulp-eslint.js @@ -13,14 +13,12 @@ const COMMON_FILES = [ '!./common/script/ops/addPushDevice.js', '!./common/script/ops/addTag.js', '!./common/script/ops/addTask.js', - '!./common/script/ops/addWebhook.js', '!./common/script/ops/blockUser.js', '!./common/script/ops/clearCompleted.js', '!./common/script/ops/clearPMs.js', '!./common/script/ops/deletePM.js', '!./common/script/ops/deleteTag.js', '!./common/script/ops/deleteTask.js', - '!./common/script/ops/deleteWebhook.js', '!./common/script/ops/getTag.js', '!./common/script/ops/getTags.js', '!./common/script/ops/rebirth.js', @@ -37,7 +35,6 @@ const COMMON_FILES = [ '!./common/script/ops/update.js', '!./common/script/ops/updateTag.js', '!./common/script/ops/updateTask.js', - '!./common/script/ops/updateWebhook.js', '!./common/script/fns/crit.js', '!./common/script/fns/cron.js', '!./common/script/fns/dotGet.js', diff --git a/test/api/v3/integration/user/DELETE-user.test.js b/test/api/v3/integration/user/DELETE-user.test.js index 69e928e343..f954903857 100644 --- a/test/api/v3/integration/user/DELETE-user.test.js +++ b/test/api/v3/integration/user/DELETE-user.test.js @@ -5,7 +5,12 @@ import { generateUser, translate as t, } from '../../../../helpers/api-integration/v3'; -import { find } from 'lodash'; +import { + find, + each, + map, +} from 'lodash'; +import Q from 'q'; describe('DELETE /user', () => { let user; @@ -38,6 +43,24 @@ describe('DELETE /user', () => { }); it('deletes the user', async () => { + // gets the user's tasks ids + let ids = []; + each(user.tasksOrder, (idsForOrder) => { + ids.push(...idsForOrder); + }); + + expect(ids.length).to.be.above(0); // make sure the user has some task to delete + + await user.del('/user', { + password, + }); + + await Q.all(map(ids, id => { + return expect(checkExistence('tasks', id)).to.eventually.eql(false); + })); + }); + + it('delete the user\'s tasks', async () => { await user.del('/user', { password, }); diff --git a/test/api/v3/integration/user/POST-user_release_both.test.js b/test/api/v3/integration/user/POST-user_release_both.test.js new file mode 100644 index 0000000000..8c47d95dfe --- /dev/null +++ b/test/api/v3/integration/user/POST-user_release_both.test.js @@ -0,0 +1,48 @@ +import { + generateUser, + translate as t, +} from '../../../../helpers/api-integration/v3'; + +describe('POST /user/release-both', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(async () => { + user = await generateUser({ + 'items.currentMount': animal, + 'items.currentPet': animal, + 'items.pets': {animal: 5}, + 'items.mounts': {animal: true}, + }); + }); + + it('returns an error when user balance is too low and user does not have triadBingo', async () => { + await expect(user.post('/user/release-both')) + .to.eventually.be.rejected.and.to.eql({ + code: 401, + error: 'NotAuthorized', + message: t('notEnoughGems'), + }); + }); + + // More tests in common code unit tests + + it('grants triad bingo with gems', async () => { + await user.update({ + balance: 1.5, + }); + + let response = await user.post('/user/release-both'); + await user.sync(); + + expect(response.message).to.equal(t('mountsAndPetsReleased')); + expect(user.balance).to.equal(0); + expect(user.items.currentMount).to.be.empty; + expect(user.items.currentPet).to.be.empty; + expect(user.items.pets[animal]).to.be.empty; + expect(user.items.mounts[animal]).to.equal(null); + expect(user.achievements.beastMasterCount).to.equal(1); + expect(user.achievements.mountMasterCount).to.equal(1); + expect(user.achievements.triadBingoCount).to.equal(1); + }); +}); 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/api/v3/integration/user/POST-user_release_pets.test.js b/test/api/v3/integration/user/POST-user_release_pets.test.js new file mode 100644 index 0000000000..a7f7b9b66f --- /dev/null +++ b/test/api/v3/integration/user/POST-user_release_pets.test.js @@ -0,0 +1,42 @@ +import { + generateUser, + translate as t, +} from '../../../../helpers/api-integration/v3'; + +describe('POST /user/release-pets', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(async () => { + user = await generateUser({ + 'items.currentPet': animal, + 'items.pets': {animal: 5}, + }); + }); + + it('returns an error when user balance is too low', async () => { + await expect(user.post('/user/release-pets')) + .to.eventually.be.rejected.and.to.eql({ + code: 401, + error: 'NotAuthorized', + message: t('notEnoughGems'), + }); + }); + + // More tests in common code unit tests + + it('releases pets', async () => { + await user.update({ + balance: 1, + }); + + let response = await user.post('/user/release-pets'); + await user.sync(); + + expect(response.message).to.equal(t('petsReleased')); + expect(user.balance).to.equal(0); + expect(user.items.currentPet).to.be.empty; + expect(user.items.pets[animal]).to.equal(0); + expect(user.achievements.beastMasterCount).to.equal(1); + }); +}); diff --git a/test/api/v3/integration/user/PUT-user_update_webhook.test.js b/test/api/v3/integration/user/PUT-user_update_webhook.test.js index 715070c991..13ca9ff00c 100644 --- a/test/api/v3/integration/user/PUT-user_update_webhook.test.js +++ b/test/api/v3/integration/user/PUT-user_update_webhook.test.js @@ -25,7 +25,7 @@ describe('PUT /user/webhook/:id', () => { await user.sync(); expect(user.preferences.webhooks[response.id].url).to.not.eql(url); let response2 = await user.put(`/user/webhook/${response.id}`, {url, enabled}); - expect(response2).to.eql({}); + expect(response2.url).to.eql(url); await user.sync(); expect(user.preferences.webhooks[response.id].url).to.eql(url); }); diff --git a/test/common/ops/releaseBoth.js b/test/common/ops/releaseBoth.js new file mode 100644 index 0000000000..309734e7d4 --- /dev/null +++ b/test/common/ops/releaseBoth.js @@ -0,0 +1,98 @@ +import releaseBoth from '../../../common/script/ops/releaseBoth'; +import i18n from '../../../common/script/i18n'; +import { + generateUser, +} from '../../helpers/common.helper'; +import { + NotAuthorized, +} from '../../../common/script/libs/errors'; + +describe('shared.ops.releaseBoth', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(() => { + user = generateUser(); + user.items.currentMount = animal; + user.items.currentPet = animal; + user.items.pets[animal] = 5; + user.items.mounts[animal] = true; + user.balance = 1.5; + }); + + it('returns an error when user balance is too low and user does not have triadBingo', (done) => { + user.balance = 0; + + try { + releaseBoth(user); + } catch (err) { + expect(err).to.be.an.instanceof(NotAuthorized); + expect(err.message).to.equal(i18n.t('notEnoughGems')); + done(); + } + }); + + it('grants triad bingo with gems', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.achievements.triadBingoCount).to.equal(1); + }); + + it('grants triad bingo without gems', () => { + user.balance = 0; + user.achievements.triadBingo = 1; + user.achievements.triadBingoCount = 1; + + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.achievements.triadBingoCount).to.equal(2); + }); + + it('releases pets', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.items.pets[animal]).to.be.empty; + expect(user.items.mounts[animal]).to.equal(null); + }); + + it('releases mounts', () => { + let response = releaseBoth(user); + + expect(response.message).to.equal(i18n.t('mountsAndPetsReleased')); + expect(user.items.mounts[animal]).to.equal(null); + }); + + it('removes currentPet', () => { + releaseBoth(user); + + expect(user.items.currentMount).to.be.empty; + expect(user.items.currentPet).to.be.empty; + }); + + it('removes currentMount', () => { + releaseBoth(user); + + expect(user.items.currentMount).to.be.empty; + }); + + it('decreases user\'s balance', () => { + releaseBoth(user); + + expect(user.balance).to.equal(0); + }); + + it('incremenets beastMasterCount', () => { + releaseBoth(user); + + expect(user.achievements.beastMasterCount).to.equal(1); + }); + + it('incremenets mountMasterCount', () => { + releaseBoth(user); + + 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/test/common/ops/releasePets.js b/test/common/ops/releasePets.js new file mode 100644 index 0000000000..11d69a5a31 --- /dev/null +++ b/test/common/ops/releasePets.js @@ -0,0 +1,57 @@ +import releasePets from '../../../common/script/ops/releasePets'; +import i18n from '../../../common/script/i18n'; +import { + generateUser, +} from '../../helpers/common.helper'; +import { + NotAuthorized, +} from '../../../common/script/libs/errors'; + +describe('shared.ops.releasePets', () => { + let user; + let animal = 'Wolf-Base'; + + beforeEach(() => { + user = generateUser(); + user.items.currentPet = animal; + user.items.pets[animal] = 5; + user.balance = 1; + }); + + it('returns an error when user balance is too low', (done) => { + user.balance = 0; + + try { + releasePets(user); + } catch (err) { + expect(err).to.be.an.instanceof(NotAuthorized); + expect(err.message).to.equal(i18n.t('notEnoughGems')); + done(); + } + }); + + it('releases pets', () => { + let response = releasePets(user); + + expect(response.message).to.equal(i18n.t('petsReleased')); + expect(user.items.pets[animal]).to.equal(0); + }); + + it('removes currentPet', () => { + releasePets(user); + + expect(user.items.currentPet).to.be.empty; + }); + + it('decreases user\'s balance', () => { + releasePets(user); + + expect(user.balance).to.equal(0); + }); + + it('incremenets beastMasterCount', () => { + releasePets(user); + + expect(user.achievements.beastMasterCount).to.equal(1); + }); +}); diff --git a/website/src/controllers/api-v3/tasks.js b/website/src/controllers/api-v3/tasks.js index e2adcffedb..f931283102 100644 --- a/website/src/controllers/api-v3/tasks.js +++ b/website/src/controllers/api-v3/tasks.js @@ -399,6 +399,7 @@ api.scoreTask = { if (direction === 'up') user.fns.randomDrop({task, delta}, req); // If a todo was completed or uncompleted move it in or out of the user.tasksOrder.todos list + // TODO move to common code? if (task.type === 'todo') { if (!wasCompleted && task.completed) { removeFromArray(user.tasksOrder.todos, task._id); @@ -406,9 +407,7 @@ api.scoreTask = { let hasTask = removeFromArray(user.tasksOrder.todos, task._id); if (!hasTask) { user.tasksOrder.todos.push(task._id); // TODO push at the top? - } else { // If for some reason it hadn't been removed TODO ok? - user.tasksOrder.push(task._id); - } + } // If for some reason it hadn't been removed previously don't do anything TODO ok? } } diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index df2ce1888e..25dc5d5a73 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -219,6 +219,10 @@ api.deleteUser = { await Q.all(groupLeavePromises); + await Tasks.Task.remove({ + userId: user._id, + }).exec(); + await user.remove(); res.respond(200, {}); @@ -779,7 +783,7 @@ api.addWebhook = { let user = res.locals.user; let result = common.ops.addWebhook(user, req); await user.save(); - res.respond(200, {id: result.id}); + res.respond(200, result); }, }; @@ -796,9 +800,9 @@ api.updateWebhook = { url: '/user/webhook/:id', async handler (req, res) { let user = res.locals.user; - common.ops.updateWebhook(user, req); + let result = common.ops.updateWebhook(user, req); await user.save(); - res.respond(200, {}); + res.respond(200, result); }, }; @@ -822,4 +826,63 @@ api.deleteWebhook = { }; +/* @api {post} /user/release-pets Releases pets. +* @apiVersion 3.0.0 +* @apiName UserReleasePets +* @apiGroup User +* +* @apiSuccess {Object} data `user.items.pets` +*/ +api.userReleasePets = { + method: 'POST', + middlewares: [authWithHeaders(), cron], + url: '/user/release-pets', + async handler (req, res) { + let user = res.locals.user; + let releasePetsResponse = common.ops.releasePets(user, req, res.analytics); + await user.save(); + res.respond(200, releasePetsResponse); + }, +}; + +/* +* @api {post} /user/release-both Releases Pets and Mounts and grants Triad Bingo. +* @apiVersion 3.0.0 +* @apiName UserReleaseBoth +* @apiGroup User +* +* @apiSuccess {Object} data `user.items.gear.owned` +*/ +api.userReleaseBoth = { + method: 'POST', + middlewares: [authWithHeaders(), cron], + url: '/user/release-both', + async handler (req, res) { + let user = res.locals.user; + let releaseBothResponse = common.ops.releaseBoth(user, req, res.analytics); + await user.save(); + res.respond(200, releaseBothResponse); + }, +}; + +/* +* @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; diff --git a/website/src/models/user.js b/website/src/models/user.js index b552236c1b..b9946fb3e7 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -508,7 +508,6 @@ export let schema = new Schema({ habits: [{type: String, ref: 'Task'}], dailys: [{type: String, ref: 'Task'}], todos: [{type: String, ref: 'Task'}], - completedTodos: [{type: String, ref: 'Task'}], rewards: [{type: String, ref: 'Task'}], }, extra: {type: Schema.Types.Mixed, default: () => {