port shared.ops.allocate

This commit is contained in:
Matteo Pagliazzi
2016-03-15 18:41:23 +01:00
parent fb6c927ce9
commit 219ec01ce9
11 changed files with 160 additions and 12 deletions

View File

@@ -100,5 +100,7 @@
"targetIdUUID": "\"targetId\" must be a valid UUID.", "targetIdUUID": "\"targetId\" must be a valid UUID.",
"challengeTasksNoCast": "Casting a spell on challenge tasks is not supported.", "challengeTasksNoCast": "Casting a spell on challenge tasks is not supported.",
"spellNotOwned": "You don't own this spell.", "spellNotOwned": "You don't own this spell.",
"spellLevelTooHigh": "You must be level <%= level %> to use this spell." "spellLevelTooHigh": "You must be level <%= level %> to use this spell.",
"invalidAttribute": "\"<%= attr %>\" is not a valid attribute.",
"notEnoughAttrPoints": "You don't have enough attribute points."
} }

View File

@@ -1,3 +1,4 @@
export const MAX_HEALTH = 50; export const MAX_HEALTH = 50;
export const MAX_LEVEL = 100; export const MAX_LEVEL = 100;
export const MAX_STAT_POINTS = MAX_LEVEL; export const MAX_STAT_POINTS = MAX_LEVEL;
export const ATTRIBUTES = ['str', 'int', 'per', 'con'];

View File

@@ -100,10 +100,12 @@ api.count = count;
// TODO As ops and fns are ported, exported them through the api object // TODO As ops and fns are ported, exported them through the api object
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';
api.ops = { api.ops = {
scoreTask, scoreTask,
sleep, sleep,
allocate,
}; };
api.fns = {}; api.fns = {};

View File

@@ -1,15 +1,30 @@
import _ from 'lodash'; import _ from 'lodash';
import splitWhitespace from '../libs/splitWhitespace'; import splitWhitespace from '../libs/splitWhitespace';
import {
ATTRIBUTES,
} from '../constants';
import {
BadRequest,
NotAuthorized,
} from '../libs/errors';
import i18n from '../i18n';
module.exports = function allocate (user, req = {}) {
let stat = _.get(req, 'query.stat', 'str');
if (ATTRIBUTES.indexOf(stat) === -1) {
throw new BadRequest(i18n.t('invalidAttribute', {attr: stat}, req.language));
}
module.exports = function(user, req, cb) {
var stat;
stat = req.query.stat || 'str';
if (user.stats.points > 0) { if (user.stats.points > 0) {
user.stats[stat]++; user.stats[stat]++;
user.stats.points--; user.stats.points--;
if (stat === 'int') { if (stat === 'int') {
user.stats.mp++; user.stats.mp++;
} }
} else {
throw new NotAuthorized(i18n.t('notEnoughAttrPoints', req.language));
} }
return typeof cb === "function" ? cb(null, _.pick(user, splitWhitespace('stats'))) : void 0;
return _.pick(user, splitWhitespace('stats'));
}; };

View File

@@ -19,7 +19,6 @@ const COMMON_FILES = [
'!./common/script/ops/addTag.js', '!./common/script/ops/addTag.js',
'!./common/script/ops/addTask.js', '!./common/script/ops/addTask.js',
'!./common/script/ops/addWebhook.js', '!./common/script/ops/addWebhook.js',
'!./common/script/ops/allocate.js',
'!./common/script/ops/allocateNow.js', '!./common/script/ops/allocateNow.js',
'!./common/script/ops/blockUser.js', '!./common/script/ops/blockUser.js',
'!./common/script/ops/buy.js', '!./common/script/ops/buy.js',

View File

@@ -0,0 +1,41 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('POST /user/allocate', () => {
let user;
beforeEach(async () => {
user = await generateUser();
});
// More tests in common code unit tests
it('returns an error if an invalid attribute is supplied', async () => {
await expect(user.post(`/user/allocate?stat=invalid`))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidAttribute', {attr: 'invalid'}),
});
});
it('returns an error if the user doesn\'t have attribute points', async () => {
await expect(user.post(`/user/allocate`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('notEnoughAttrPoints'),
});
});
it('allocates attribute points', async () => {
await user.update({'stats.points': 1});
let res = await user.post(`/user/allocate?stat=con`);
await user.sync();
expect(user.stats.con).to.equal(1);
expect(user.stats.points).to.equal(0);
expect(res.stats.con).to.equal(1);
});
});

View File

@@ -9,6 +9,8 @@ describe('POST /user/sleep', () => {
user = await generateUser(); user = await generateUser();
}); });
// More tests in common code unit tests
it('toggles sleep status', async () => { it('toggles sleep status', async () => {
let res = await user.post(`/user/sleep`); let res = await user.post(`/user/sleep`);
expect(res).to.eql({ expect(res).to.eql({

11
test/common/constants.js Normal file
View File

@@ -0,0 +1,11 @@
import {
ATTRIBUTES,
} from '../../common/script/constants';
describe('constants', () => {
describe('ATTRIBUTES', () => {
it('provides a list of attributes', () => {
expect(ATTRIBUTES).to.eql(['str', 'int', 'per', 'con']);
});
});
});

View File

@@ -0,0 +1,59 @@
import allocate from '../../../common/script/ops/allocate';
import {
BadRequest,
NotAuthorized,
} from '../../../common/script/libs/errors';
import i18n from '../../../common/script/i18n';
import {
generateUser,
} from '../../helpers/common.helper';
describe('shared.ops.allocate', () => {
let user;
beforeEach(() => {
user = generateUser();
});
it('throws an error if an invalid attribute is supplied', () => {
try {
expect(allocate(user, {
query: {stat: 'notValid'},
})).to.throw(BadRequest);
} catch (err) {
expect(err.message).to.equal(i18n.t('invalidAttribute', {attr: 'notValid'}));
}
});
it('throws an error if the user doesn\'t have attribute points', () => {
try {
expect(allocate(user)).to.throw(NotAuthorized);
} catch (err) {
expect(err.message).to.equal(i18n.t('notEnoughAttrPoints'));
}
});
it('defaults to the "str" attribute', () => {
expect(user.stats.str).to.equal(0);
user.stats.points = 1;
allocate(user);
expect(user.stats.str).to.equal(1);
});
it('allocates attribute points', () => {
expect(user.stats.con).to.equal(0);
user.stats.points = 1;
allocate(user, {query: {stat: 'con'}});
expect(user.stats.con).to.equal(1);
expect(user.stats.points).to.equal(0);
});
it('increases mana when allocating to "int"', () => {
expect(user.stats.int).to.equal(0);
expect(user.stats.mp).to.equal(10);
user.stats.points = 1;
allocate(user, {query: {stat: 'int'}});
expect(user.stats.int).to.equal(1);
expect(user.stats.mp).to.equal(11);
});
});

View File

@@ -16,8 +16,6 @@ import _ from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { preenHistory } from '../../libs/api-v3/preening'; import { preenHistory } from '../../libs/api-v3/preening';
const scoreTask = common.ops.scoreTask;
let api = {}; let api = {};
// challenge must be passed only when a challenge task is being created // challenge must be passed only when a challenge task is being created
@@ -401,7 +399,7 @@ api.scoreTask = {
task.completed = direction === 'up'; // TODO move into scoreTask task.completed = direction === 'up'; // TODO move into scoreTask
} }
let delta = scoreTask({task, user, direction}, req); let delta = common.ops.scoreTask({task, user, direction}, req);
// Drop system (don't run on the client, as it would only be discarded since ops are sent to the API, not the results) // Drop system (don't run on the client, as it would only be discarded since ops are sent to the API, not the results)
if (direction === 'up') user.fns.randomDrop({task, delta}, req); if (direction === 'up') user.fns.randomDrop({task, delta}, req);

View File

@@ -13,8 +13,6 @@ import Q from 'q';
import _ from 'lodash'; import _ from 'lodash';
import * as passwordUtils from '../../libs/api-v3/password'; import * as passwordUtils from '../../libs/api-v3/password';
const sleep = common.ops.sleep;
let api = {}; let api = {};
/** /**
@@ -293,10 +291,30 @@ api.sleep = {
url: '/user/sleep', url: '/user/sleep',
async handler (req, res) { async handler (req, res) {
let user = res.locals.user; let user = res.locals.user;
let sleepRes = sleep(user); let sleepRes = common.ops.sleep(user);
await user.save(); await user.save();
res.respond(200, sleepRes); res.respond(200, sleepRes);
}, },
}; };
/**
* @api {post} /user/allocate Allocate an attribute point.
* @apiVersion 3.0.0
* @apiName UserAllocate
* @apiGroup User
*
* @apiSuccess {Object} Returs `user.stats`
*/
api.allocate = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
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);
},
};
module.exports = api; module.exports = api;