mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 22:27:26 +01:00
Bulk stats (#9260)
* Reorganized stats * Organized allocation common code * Added bulk allocate to common * Added allocate bulk route * Fixed structure and lint * Fixed import and apidoc
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
translate as t,
|
translate as t,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
describe('POST /user/allocate', () => {
|
describe('POST /user/allocate', () => {
|
||||||
let user;
|
let user;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
translate as t,
|
||||||
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
|
describe('POST /user/allocate-bulk', () => {
|
||||||
|
let user;
|
||||||
|
const statsUpdate = {
|
||||||
|
stats: {
|
||||||
|
con: 1,
|
||||||
|
str: 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
// More tests in common code unit tests
|
||||||
|
|
||||||
|
it('returns an error if user does not have enough points', async () => {
|
||||||
|
await expect(user.post('/user/allocate-bulk', statsUpdate))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('notEnoughAttrPoints'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allocates attribute points', async () => {
|
||||||
|
await user.update({'stats.points': 3});
|
||||||
|
|
||||||
|
await user.post('/user/allocate-bulk', statsUpdate);
|
||||||
|
await user.sync();
|
||||||
|
|
||||||
|
expect(user.stats.con).to.equal(1);
|
||||||
|
expect(user.stats.str).to.equal(2);
|
||||||
|
expect(user.stats.points).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../../../helpers/api-integration/v3';
|
} from '../../../../../helpers/api-integration/v3';
|
||||||
|
|
||||||
describe('POST /user/allocate-now', () => {
|
describe('POST /user/allocate-now', () => {
|
||||||
// More tests in common code unit tests
|
// More tests in common code unit tests
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import allocate from '../../../website/common/script/ops/allocate';
|
import allocate from '../../../../website/common/script/ops/stats/allocate';
|
||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../../website/common/script/libs/errors';
|
} from '../../../../website/common/script/libs/errors';
|
||||||
import i18n from '../../../website/common/script/i18n';
|
import i18n from '../../../../website/common/script/i18n';
|
||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../helpers/common.helper';
|
} from '../../../helpers/common.helper';
|
||||||
|
|
||||||
describe('shared.ops.allocate', () => {
|
describe('shared.ops.allocate', () => {
|
||||||
let user;
|
let user;
|
||||||
98
test/common/ops/stats/allocateBulk.js
Normal file
98
test/common/ops/stats/allocateBulk.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import allocateBulk from '../../../../website/common/script/ops/stats/allocateBulk';
|
||||||
|
import {
|
||||||
|
BadRequest,
|
||||||
|
NotAuthorized,
|
||||||
|
} from '../../../../website/common/script/libs/errors';
|
||||||
|
import i18n from '../../../../website/common/script/i18n';
|
||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../helpers/common.helper';
|
||||||
|
|
||||||
|
describe('shared.ops.allocateBulk', () => {
|
||||||
|
let user;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
user = generateUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if an invalid attribute is supplied', (done) => {
|
||||||
|
try {
|
||||||
|
allocateBulk(user, {
|
||||||
|
body: {
|
||||||
|
stats: {
|
||||||
|
invalid: 1,
|
||||||
|
str: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.an.instanceof(BadRequest);
|
||||||
|
expect(err.message).to.equal(i18n.t('invalidAttribute', {attr: 'invalid'}));
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if the stats are not supplied', (done) => {
|
||||||
|
try {
|
||||||
|
allocateBulk(user);
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.an.instanceof(BadRequest);
|
||||||
|
expect(err.message).to.equal(i18n.t('statsObjectRequired'));
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if the user doesn\'t have attribute points', (done) => {
|
||||||
|
try {
|
||||||
|
allocateBulk(user, {
|
||||||
|
body: {
|
||||||
|
stats: {
|
||||||
|
int: 1,
|
||||||
|
str: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||||
|
expect(err.message).to.equal(i18n.t('notEnoughAttrPoints'));
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if the user doesn\'t have enough attribute points', (done) => {
|
||||||
|
user.stats.points = 1;
|
||||||
|
try {
|
||||||
|
allocateBulk(user, {
|
||||||
|
body: {
|
||||||
|
stats: {
|
||||||
|
int: 1,
|
||||||
|
str: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||||
|
expect(err.message).to.equal(i18n.t('notEnoughAttrPoints'));
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allocates attribute points', () => {
|
||||||
|
user.stats.points = 3;
|
||||||
|
expect(user.stats.int).to.equal(0);
|
||||||
|
expect(user.stats.str).to.equal(0);
|
||||||
|
|
||||||
|
allocateBulk(user, {
|
||||||
|
body: {
|
||||||
|
stats: {
|
||||||
|
int: 1,
|
||||||
|
str: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(user.stats.str).to.equal(2);
|
||||||
|
expect(user.stats.int).to.equal(1);
|
||||||
|
expect(user.stats.points).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import allocateNow from '../../../website/common/script/ops/allocateNow';
|
import allocateNow from '../../../../website/common/script/ops/stats/allocateNow';
|
||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../helpers/common.helper';
|
} from '../../../helpers/common.helper';
|
||||||
|
|
||||||
describe('shared.ops.allocateNow', () => {
|
describe('shared.ops.allocateNow', () => {
|
||||||
let user;
|
let user;
|
||||||
@@ -559,7 +559,7 @@ import keys from 'lodash/keys';
|
|||||||
import { beastMasterProgress, mountMasterProgress } from '../../../common/script/count';
|
import { beastMasterProgress, mountMasterProgress } from '../../../common/script/count';
|
||||||
import statsComputed from '../../../common/script/libs/statsComputed';
|
import statsComputed from '../../../common/script/libs/statsComputed';
|
||||||
import autoAllocate from '../../../common/script/fns/autoAllocate';
|
import autoAllocate from '../../../common/script/fns/autoAllocate';
|
||||||
import allocate from '../../../common/script/ops/allocate';
|
import allocate from '../../../common/script/ops/stats/allocate';
|
||||||
|
|
||||||
import MemberDetails from '../memberDetails';
|
import MemberDetails from '../memberDetails';
|
||||||
import bPopover from 'bootstrap-vue/lib/components/popover';
|
import bPopover from 'bootstrap-vue/lib/components/popover';
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ import { beastMasterProgress, mountMasterProgress } from '../../../common/script
|
|||||||
import statsComputed from '../../../common/script/libs/statsComputed';
|
import statsComputed from '../../../common/script/libs/statsComputed';
|
||||||
import autoAllocate from '../../../common/script/fns/autoAllocate';
|
import autoAllocate from '../../../common/script/fns/autoAllocate';
|
||||||
import changeClass from '../../../common/script/ops/changeClass';
|
import changeClass from '../../../common/script/ops/changeClass';
|
||||||
import allocate from '../../../common/script/ops/allocate';
|
import allocate from '../../../common/script/ops/stats/allocate';
|
||||||
|
|
||||||
const DROP_ANIMALS = keys(Content.pets);
|
const DROP_ANIMALS = keys(Content.pets);
|
||||||
const TOTAL_NUMBER_OF_DROP_ANIMALS = DROP_ANIMALS.length;
|
const TOTAL_NUMBER_OF_DROP_ANIMALS = DROP_ANIMALS.length;
|
||||||
|
|||||||
@@ -222,5 +222,6 @@
|
|||||||
"allocated": "Allocated",
|
"allocated": "Allocated",
|
||||||
"buffs": "Buffs",
|
"buffs": "Buffs",
|
||||||
"pointsAvailable": "Points Available",
|
"pointsAvailable": "Points Available",
|
||||||
"pts": "pts"
|
"pts": "pts",
|
||||||
|
"statsObjectRequired": "Stats update is required"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,9 @@ api.fns = {
|
|||||||
|
|
||||||
import scoreTask from './ops/scoreTask';
|
import scoreTask from './ops/scoreTask';
|
||||||
import sleep from './ops/sleep';
|
import sleep from './ops/sleep';
|
||||||
import allocate from './ops/allocate';
|
import allocateNow from './ops/stats/allocateNow';
|
||||||
|
import allocate from './ops/stats/allocate';
|
||||||
|
import allocateBulk from './ops/stats/allocateBulk';
|
||||||
import buy from './ops/buy';
|
import buy from './ops/buy';
|
||||||
import buyGear from './ops/buyGear';
|
import buyGear from './ops/buyGear';
|
||||||
import buyHealthPotion from './ops/buyHealthPotion';
|
import buyHealthPotion from './ops/buyHealthPotion';
|
||||||
@@ -145,7 +147,6 @@ import buyArmoire from './ops/buyArmoire';
|
|||||||
import buyMysterySet from './ops/buyMysterySet';
|
import buyMysterySet from './ops/buyMysterySet';
|
||||||
import buyQuest from './ops/buyQuest';
|
import buyQuest from './ops/buyQuest';
|
||||||
import buySpecialSpell from './ops/buySpecialSpell';
|
import buySpecialSpell from './ops/buySpecialSpell';
|
||||||
import allocateNow from './ops/allocateNow';
|
|
||||||
import hatch from './ops/hatch';
|
import hatch from './ops/hatch';
|
||||||
import feed from './ops/feed';
|
import feed from './ops/feed';
|
||||||
import equip from './ops/equip';
|
import equip from './ops/equip';
|
||||||
@@ -176,6 +177,7 @@ api.ops = {
|
|||||||
scoreTask,
|
scoreTask,
|
||||||
sleep,
|
sleep,
|
||||||
allocate,
|
allocate,
|
||||||
|
allocateBulk,
|
||||||
buy,
|
buy,
|
||||||
buyGear,
|
buyGear,
|
||||||
buyHealthPotion,
|
buyHealthPotion,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import revive from './revive';
|
|||||||
import reset from './reset';
|
import reset from './reset';
|
||||||
import reroll from './reroll';
|
import reroll from './reroll';
|
||||||
import rebirth from './rebirth';
|
import rebirth from './rebirth';
|
||||||
import allocateNow from './allocateNow';
|
import allocate from './stats/allocate';
|
||||||
|
import allocateBulk from './stats/allocateBulk';
|
||||||
|
import allocateNow from './stats/allocateNow';
|
||||||
import sortTask from './sortTask';
|
import sortTask from './sortTask';
|
||||||
import updateTask from './updateTask';
|
import updateTask from './updateTask';
|
||||||
import deleteTask from './deleteTask';
|
import deleteTask from './deleteTask';
|
||||||
@@ -35,7 +37,6 @@ import hatch from './hatch';
|
|||||||
import unlock from './unlock';
|
import unlock from './unlock';
|
||||||
import changeClass from './changeClass';
|
import changeClass from './changeClass';
|
||||||
import disableClasses from './disableClasses';
|
import disableClasses from './disableClasses';
|
||||||
import allocate from './allocate';
|
|
||||||
import readCard from './readCard';
|
import readCard from './readCard';
|
||||||
import openMysteryItem from './openMysteryItem';
|
import openMysteryItem from './openMysteryItem';
|
||||||
import scoreTask from './scoreTask';
|
import scoreTask from './scoreTask';
|
||||||
@@ -49,6 +50,7 @@ module.exports = {
|
|||||||
reroll,
|
reroll,
|
||||||
rebirth,
|
rebirth,
|
||||||
allocateNow,
|
allocateNow,
|
||||||
|
allocateBulk,
|
||||||
sortTask,
|
sortTask,
|
||||||
updateTask,
|
updateTask,
|
||||||
deleteTask,
|
deleteTask,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import {
|
import {
|
||||||
ATTRIBUTES,
|
ATTRIBUTES,
|
||||||
} from '../constants';
|
} from '../../constants';
|
||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../libs/errors';
|
} from '../../libs/errors';
|
||||||
import i18n from '../i18n';
|
import i18n from '../../i18n';
|
||||||
|
|
||||||
module.exports = function allocate (user, req = {}) {
|
module.exports = function allocate (user, req = {}) {
|
||||||
let stat = get(req, 'query.stat', 'str');
|
let stat = get(req, 'query.stat', 'str');
|
||||||
44
website/common/script/ops/stats/allocateBulk.js
Normal file
44
website/common/script/ops/stats/allocateBulk.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import get from 'lodash/get';
|
||||||
|
import {
|
||||||
|
ATTRIBUTES,
|
||||||
|
} from '../../constants';
|
||||||
|
import {
|
||||||
|
BadRequest,
|
||||||
|
NotAuthorized,
|
||||||
|
} from '../../libs/errors';
|
||||||
|
import i18n from '../../i18n';
|
||||||
|
|
||||||
|
module.exports = function allocateBulk (user, req = {}) {
|
||||||
|
const stats = get(req, 'body.stats');
|
||||||
|
if (!stats) throw new BadRequest(i18n.t('statsObjectRequired', req.language));
|
||||||
|
|
||||||
|
const statKeys = Object.keys(stats);
|
||||||
|
const invalidStats = statKeys.filter(statKey => {
|
||||||
|
return ATTRIBUTES.indexOf(statKey) === -1;
|
||||||
|
});
|
||||||
|
if (invalidStats.length > 0) {
|
||||||
|
throw new BadRequest(i18n.t('invalidAttribute', {attr: invalidStats.join(',')}, req.language));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.stats.points <= 0) {
|
||||||
|
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));
|
||||||
|
}
|
||||||
|
|
||||||
|
const newStatValues = Object.values(stats);
|
||||||
|
const totalPointsToAllocate = newStatValues.reduce((sum, value) => {
|
||||||
|
return sum + value;
|
||||||
|
}, 0);
|
||||||
|
if (user.stats.points < totalPointsToAllocate) {
|
||||||
|
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [stat, value] of Object.entries(stats)) {
|
||||||
|
user.stats[stat] += value;
|
||||||
|
user.stats.points -= value;
|
||||||
|
if (stat === 'int') user.stats.mp += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
user.stats,
|
||||||
|
];
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import times from 'lodash/times';
|
import times from 'lodash/times';
|
||||||
import autoAllocate from '../fns/autoAllocate';
|
import autoAllocate from '../../fns/autoAllocate';
|
||||||
|
|
||||||
module.exports = function allocateNow (user) {
|
module.exports = function allocateNow (user) {
|
||||||
times(user.stats.points, () => autoAllocate(user));
|
times(user.stats.points, () => autoAllocate(user));
|
||||||
@@ -746,95 +746,6 @@ api.sleep = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @api {post} /api/v3/user/allocate Allocate a single attribute point
|
|
||||||
* @apiName UserAllocate
|
|
||||||
* @apiGroup User
|
|
||||||
*
|
|
||||||
* @apiParam (Body) {String="str","con","int","per"} stat Query parameter - Default ='str'
|
|
||||||
*
|
|
||||||
* @apiParamExample {json} Example request
|
|
||||||
* {"stat":"int"}
|
|
||||||
*
|
|
||||||
* @apiSuccess {Object} data Returns stats from the user profile
|
|
||||||
*
|
|
||||||
* @apiError {NotAuthorized} NoPoints Not enough attribute points to increment a stat.
|
|
||||||
*
|
|
||||||
* @apiErrorExample {json}
|
|
||||||
* {
|
|
||||||
* "success": false,
|
|
||||||
* "error": "NotAuthorized",
|
|
||||||
* "message": "You don't have enough attribute points."
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
api.allocate = {
|
|
||||||
method: 'POST',
|
|
||||||
middlewares: [authWithHeaders()],
|
|
||||||
url: '/user/allocate',
|
|
||||||
async handler (req, res) {
|
|
||||||
let user = res.locals.user;
|
|
||||||
let allocateRes = common.ops.allocate(user, req);
|
|
||||||
await user.save();
|
|
||||||
res.respond(200, ...allocateRes);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @api {post} /api/v3/user/allocate-now Allocate all attribute points
|
|
||||||
* @apiDescription Uses the user's chosen automatic allocation method, or if none, assigns all to STR. Note: will return success, even if there are 0 points to allocate.
|
|
||||||
* @apiName UserAllocateNow
|
|
||||||
* @apiGroup User
|
|
||||||
*
|
|
||||||
* @apiSuccessExample {json} Success-Response:
|
|
||||||
* {
|
|
||||||
* "success": true,
|
|
||||||
* "data": {
|
|
||||||
* "hp": 50,
|
|
||||||
* "mp": 38,
|
|
||||||
* "exp": 7,
|
|
||||||
* "gp": 284.8637271160258,
|
|
||||||
* "lvl": 10,
|
|
||||||
* "class": "rogue",
|
|
||||||
* "points": 0,
|
|
||||||
* "str": 2,
|
|
||||||
* "con": 2,
|
|
||||||
* "int": 3,
|
|
||||||
* "per": 3,
|
|
||||||
* "buffs": {
|
|
||||||
* "str": 0,
|
|
||||||
* "int": 0,
|
|
||||||
* "per": 0,
|
|
||||||
* "con": 0,
|
|
||||||
* "stealth": 0,
|
|
||||||
* "streaks": false,
|
|
||||||
* "snowball": false,
|
|
||||||
* "spookySparkles": false,
|
|
||||||
* "shinySeed": false,
|
|
||||||
* "seafoam": false
|
|
||||||
* },
|
|
||||||
* "training": {
|
|
||||||
* "int": 0,
|
|
||||||
* "per": 0,
|
|
||||||
* "str": 0,
|
|
||||||
* "con": 0
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @apiSuccess {Object} data user.stats
|
|
||||||
*/
|
|
||||||
api.allocateNow = {
|
|
||||||
method: 'POST',
|
|
||||||
middlewares: [authWithHeaders()],
|
|
||||||
url: '/user/allocate-now',
|
|
||||||
async handler (req, res) {
|
|
||||||
let user = res.locals.user;
|
|
||||||
let allocateNowRes = common.ops.allocateNow(user);
|
|
||||||
await user.save();
|
|
||||||
res.respond(200, ...allocateNowRes);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/buy/:key Buy gear, armoire or potion
|
* @api {post} /api/v3/user/buy/:key Buy gear, armoire or potion
|
||||||
* @apiDescription Under the hood uses UserBuyGear, UserBuyPotion and UserBuyArmoire
|
* @apiDescription Under the hood uses UserBuyGear, UserBuyPotion and UserBuyArmoire
|
||||||
|
|||||||
136
website/server/controllers/api-v3/user/stats.js
Normal file
136
website/server/controllers/api-v3/user/stats.js
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// @TODO: Can we import only the functions we need instead of the large object?
|
||||||
|
import common from '../../../../common';
|
||||||
|
import { authWithHeaders } from '../../../middlewares/auth';
|
||||||
|
|
||||||
|
let api = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /api/v3/user/allocate Allocate a single attribute point
|
||||||
|
* @apiName UserAllocate
|
||||||
|
* @apiGroup User
|
||||||
|
*
|
||||||
|
* @apiParam (Body) {String="str","con","int","per"} stat Query parameter - Default ='str'
|
||||||
|
*
|
||||||
|
* @apiParamExample {json} Example request
|
||||||
|
* {"stat":"int"}
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data Returns stats from the user profile
|
||||||
|
*
|
||||||
|
* @apiError {NotAuthorized} NoPoints Not enough attribute points to increment a stat.
|
||||||
|
*
|
||||||
|
* @apiErrorExample {json}
|
||||||
|
* {
|
||||||
|
* "success": false,
|
||||||
|
* "error": "NotAuthorized",
|
||||||
|
* "message": "You don't have enough attribute points."
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
api.allocate = {
|
||||||
|
method: 'POST',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
url: '/user/allocate',
|
||||||
|
async handler (req, res) {
|
||||||
|
let user = res.locals.user;
|
||||||
|
let allocateRes = common.ops.allocate(user, req);
|
||||||
|
await user.save();
|
||||||
|
res.respond(200, ...allocateRes);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /api/v3/user/allocate-bulk Allocate multiple attribute points
|
||||||
|
* @apiName UserAllocateBulk
|
||||||
|
* @apiGroup User
|
||||||
|
*
|
||||||
|
* @apiParam (Body) { Object } stats Body parameter
|
||||||
|
*
|
||||||
|
* @apiParamExample {json} Example request
|
||||||
|
* {
|
||||||
|
* stats: {
|
||||||
|
* 'int': int,
|
||||||
|
* 'str': int,
|
||||||
|
* 'con': int,
|
||||||
|
* 'per': int,
|
||||||
|
* },
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data Returns stats from the user profile
|
||||||
|
*
|
||||||
|
* @apiError {NotAuthorized} NoPoints Not enough attribute points to increment a stat.
|
||||||
|
*
|
||||||
|
* @apiErrorExample {json}
|
||||||
|
* {
|
||||||
|
* "success": false,
|
||||||
|
* "error": "NotAuthorized",
|
||||||
|
* "message": "You don't have enough attribute points."
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
api.allocateBulk = {
|
||||||
|
method: 'POST',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
url: '/user/allocate-bulk',
|
||||||
|
async handler (req, res) {
|
||||||
|
let user = res.locals.user;
|
||||||
|
let allocateRes = common.ops.allocateBulk(user, req);
|
||||||
|
await user.save();
|
||||||
|
res.respond(200, ...allocateRes);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /api/v3/user/allocate-now Allocate all attribute points
|
||||||
|
* @apiDescription Uses the user's chosen automatic allocation method, or if none, assigns all to STR. Note: will return success, even if there are 0 points to allocate.
|
||||||
|
* @apiName UserAllocateNow
|
||||||
|
* @apiGroup User
|
||||||
|
*
|
||||||
|
* @apiSuccessExample {json} Success-Response:
|
||||||
|
* {
|
||||||
|
* "success": true,
|
||||||
|
* "data": {
|
||||||
|
* "hp": 50,
|
||||||
|
* "mp": 38,
|
||||||
|
* "exp": 7,
|
||||||
|
* "gp": 284.8637271160258,
|
||||||
|
* "lvl": 10,
|
||||||
|
* "class": "rogue",
|
||||||
|
* "points": 0,
|
||||||
|
* "str": 2,
|
||||||
|
* "con": 2,
|
||||||
|
* "int": 3,
|
||||||
|
* "per": 3,
|
||||||
|
* "buffs": {
|
||||||
|
* "str": 0,
|
||||||
|
* "int": 0,
|
||||||
|
* "per": 0,
|
||||||
|
* "con": 0,
|
||||||
|
* "stealth": 0,
|
||||||
|
* "streaks": false,
|
||||||
|
* "snowball": false,
|
||||||
|
* "spookySparkles": false,
|
||||||
|
* "shinySeed": false,
|
||||||
|
* "seafoam": false
|
||||||
|
* },
|
||||||
|
* "training": {
|
||||||
|
* "int": 0,
|
||||||
|
* "per": 0,
|
||||||
|
* "str": 0,
|
||||||
|
* "con": 0
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data user.stats
|
||||||
|
*/
|
||||||
|
api.allocateNow = {
|
||||||
|
method: 'POST',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
url: '/user/allocate-now',
|
||||||
|
async handler (req, res) {
|
||||||
|
let user = res.locals.user;
|
||||||
|
let allocateNowRes = common.ops.allocateNow(user);
|
||||||
|
await user.save();
|
||||||
|
res.respond(200, ...allocateNowRes);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = api;
|
||||||
Reference in New Issue
Block a user