mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
Merge branch 'api-v3' into Alys-v3-armoire-fix
This commit is contained in:
@@ -194,7 +194,7 @@ spells.rogue = {
|
|||||||
notes: t('spellRogueStealthNotes'),
|
notes: t('spellRogueStealthNotes'),
|
||||||
cast (user) {
|
cast (user) {
|
||||||
if (!user.stats.buffs.stealth) user.stats.buffs.stealth = 0;
|
if (!user.stats.buffs.stealth) user.stats.buffs.stealth = 0;
|
||||||
user.stats.buffs.stealth += Math.ceil(diminishingReturns(user._statsComputed.per, user.dailys.length * 0.64, 55));
|
user.stats.buffs.stealth += Math.ceil(diminishingReturns(user._statsComputed.per, user.tasksOrder.dailys.length * 0.64, 55));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,17 +10,19 @@ import splitWhitespace from '../libs/splitWhitespace';
|
|||||||
function getStatToAllocate (user) {
|
function getStatToAllocate (user) {
|
||||||
let suggested;
|
let suggested;
|
||||||
|
|
||||||
|
let statsObj = user.stats.toObject ? user.stats.toObject() : user.stats;
|
||||||
|
|
||||||
switch (user.preferences.allocationMode) {
|
switch (user.preferences.allocationMode) {
|
||||||
case 'flat': {
|
case 'flat': {
|
||||||
let stats = _.pick(user.stats, splitWhitespace('con str per int'));
|
let stats = _.pick(statsObj, splitWhitespace('con str per int'));
|
||||||
return _.invert(stats)[_.min(stats)];
|
return _.invert(stats)[_.min(stats)];
|
||||||
}
|
}
|
||||||
case 'classbased': {
|
case 'classbased': {
|
||||||
let lvlDiv7 = user.stats.lvl / 7;
|
let lvlDiv7 = statsObj.lvl / 7;
|
||||||
let ideal = [lvlDiv7 * 3, lvlDiv7 * 2, lvlDiv7, lvlDiv7];
|
let ideal = [lvlDiv7 * 3, lvlDiv7 * 2, lvlDiv7, lvlDiv7];
|
||||||
|
|
||||||
let preference;
|
let preference;
|
||||||
switch (user.stats.class) {
|
switch (statsObj.class) {
|
||||||
case 'wizard': {
|
case 'wizard': {
|
||||||
preference = ['int', 'per', 'con', 'str'];
|
preference = ['int', 'per', 'con', 'str'];
|
||||||
break;
|
break;
|
||||||
@@ -39,10 +41,10 @@ function getStatToAllocate (user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let diff = [
|
let diff = [
|
||||||
user.stats[preference[0]] - ideal[0],
|
statsObj[preference[0]] - ideal[0],
|
||||||
user.stats[preference[1]] - ideal[1],
|
statsObj[preference[1]] - ideal[1],
|
||||||
user.stats[preference[2]] - ideal[2],
|
statsObj[preference[2]] - ideal[2],
|
||||||
user.stats[preference[3]] - ideal[3],
|
statsObj[preference[3]] - ideal[3],
|
||||||
];
|
];
|
||||||
|
|
||||||
suggested = _.findIndex(diff, (val) => {
|
suggested = _.findIndex(diff, (val) => {
|
||||||
@@ -52,9 +54,9 @@ function getStatToAllocate (user) {
|
|||||||
return suggested !== -1 ? preference[suggested] : 'str';
|
return suggested !== -1 ? preference[suggested] : 'str';
|
||||||
}
|
}
|
||||||
case 'taskbased': {
|
case 'taskbased': {
|
||||||
suggested = _.invert(user.stats.training)[_.max(user.stats.training)];
|
suggested = _.invert(statsObj.training)[_.max(statsObj.training)];
|
||||||
|
|
||||||
let training = user.stats.training;
|
let training = statsObj.training;
|
||||||
training.str = 0;
|
training.str = 0;
|
||||||
training.int = 0;
|
training.int = 0;
|
||||||
training.con = 0;
|
training.con = 0;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ import sleep from './ops/sleep';
|
|||||||
import allocate from './ops/allocate';
|
import allocate from './ops/allocate';
|
||||||
import buy from './ops/buy';
|
import buy from './ops/buy';
|
||||||
import buyGear from './ops/buyGear';
|
import buyGear from './ops/buyGear';
|
||||||
import buyPotion from './ops/buyPotion';
|
import buyHealthPotion from './ops/buyHealthPotion';
|
||||||
import buyArmoire from './ops/buyArmoire';
|
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';
|
||||||
@@ -155,7 +155,7 @@ api.ops = {
|
|||||||
allocate,
|
allocate,
|
||||||
buy,
|
buy,
|
||||||
buyGear,
|
buyGear,
|
||||||
buyPotion,
|
buyHealthPotion,
|
||||||
buyArmoire,
|
buyArmoire,
|
||||||
buyMysterySet,
|
buyMysterySet,
|
||||||
buySpecialSpell,
|
buySpecialSpell,
|
||||||
@@ -274,7 +274,7 @@ api.wrap = function wrapUser (user, main = true) {
|
|||||||
releaseMounts: _.partial(importedOps.releaseMounts, user),
|
releaseMounts: _.partial(importedOps.releaseMounts, user),
|
||||||
releaseBoth: _.partial(importedOps.releaseBoth, user),
|
releaseBoth: _.partial(importedOps.releaseBoth, user),
|
||||||
buy: _.partial(importedOps.buy, user),
|
buy: _.partial(importedOps.buy, user),
|
||||||
buyPotion: _.partial(importedOps.buyPotion, user),
|
buyHealthPotion: _.partial(importedOps.buyHealthPotion, user),
|
||||||
buyArmoire: _.partial(importedOps.buyArmoire, user),
|
buyArmoire: _.partial(importedOps.buyArmoire, user),
|
||||||
buyGear: _.partial(importedOps.buyGear, user),
|
buyGear: _.partial(importedOps.buyGear, user),
|
||||||
buyQuest: _.partial(importedOps.buyQuest, user),
|
buyQuest: _.partial(importedOps.buyQuest, user),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import _ from 'lodash';
|
|||||||
import {
|
import {
|
||||||
BadRequest,
|
BadRequest,
|
||||||
} from '../libs/errors';
|
} from '../libs/errors';
|
||||||
import buyPotion from './buyPotion';
|
import buyHealthPotion from './buyHealthPotion';
|
||||||
import buyArmoire from './buyArmoire';
|
import buyArmoire from './buyArmoire';
|
||||||
import buyGear from './buyGear';
|
import buyGear from './buyGear';
|
||||||
|
|
||||||
@@ -12,8 +12,8 @@ module.exports = function buy (user, req = {}, analytics) {
|
|||||||
if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language));
|
if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language));
|
||||||
|
|
||||||
let buyRes;
|
let buyRes;
|
||||||
if (key === 'potion') { // health potion
|
if (key === 'potion') {
|
||||||
buyRes = buyPotion(user, req, analytics);
|
buyRes = buyHealthPotion(user, req, analytics);
|
||||||
} else if (key === 'armoire') {
|
} else if (key === 'armoire') {
|
||||||
buyRes = buyArmoire(user, req, analytics);
|
buyRes = buyArmoire(user, req, analytics);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../libs/errors';
|
} from '../libs/errors';
|
||||||
|
|
||||||
module.exports = function buyPotion (user, req = {}, analytics) { // health potion
|
module.exports = function buyHealthPotion (user, req = {}, analytics) {
|
||||||
let item = content.potion;
|
let item = content.potion;
|
||||||
|
|
||||||
if (user.stats.gp < item.value) {
|
if (user.stats.gp < item.value) {
|
||||||
@@ -31,7 +31,7 @@ import releaseMounts from './releaseMounts';
|
|||||||
import releaseBoth from './releaseBoth';
|
import releaseBoth from './releaseBoth';
|
||||||
import buy from './buy';
|
import buy from './buy';
|
||||||
import buyGear from './buyGear';
|
import buyGear from './buyGear';
|
||||||
import buyPotion from './buyPotion';
|
import buyHealthPotion from './buyHealthPotion';
|
||||||
import buyArmoire from './buyArmoire';
|
import buyArmoire from './buyArmoire';
|
||||||
import buyQuest from './buyQuest';
|
import buyQuest from './buyQuest';
|
||||||
import buyMysterySet from './buyMysterySet';
|
import buyMysterySet from './buyMysterySet';
|
||||||
@@ -83,7 +83,7 @@ module.exports = {
|
|||||||
releaseBoth,
|
releaseBoth,
|
||||||
buy,
|
buy,
|
||||||
buyGear,
|
buyGear,
|
||||||
buyPotion,
|
buyHealthPotion,
|
||||||
buyArmoire,
|
buyArmoire,
|
||||||
buyQuest,
|
buyQuest,
|
||||||
buyMysterySet,
|
buyMysterySet,
|
||||||
|
|||||||
@@ -11,16 +11,11 @@ import equip from './equip';
|
|||||||
const USERSTATSLIST = ['per', 'int', 'con', 'str', 'points', 'gp', 'exp', 'mp'];
|
const USERSTATSLIST = ['per', 'int', 'con', 'str', 'points', 'gp', 'exp', 'mp'];
|
||||||
|
|
||||||
module.exports = function rebirth (user, tasks = [], req = {}, analytics) {
|
module.exports = function rebirth (user, tasks = [], req = {}, analytics) {
|
||||||
let analyticsData;
|
|
||||||
let flags;
|
|
||||||
let lvl;
|
|
||||||
let stats;
|
|
||||||
|
|
||||||
if (user.balance < 2 && user.stats.lvl < MAX_LEVEL) {
|
if (user.balance < 2 && user.stats.lvl < MAX_LEVEL) {
|
||||||
throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
|
throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
|
||||||
}
|
}
|
||||||
|
|
||||||
analyticsData = {
|
let analyticsData = {
|
||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
category: 'behavior',
|
category: 'behavior',
|
||||||
};
|
};
|
||||||
@@ -38,18 +33,20 @@ module.exports = function rebirth (user, tasks = [], req = {}, analytics) {
|
|||||||
analytics.track('Rebirth', analyticsData);
|
analytics.track('Rebirth', analyticsData);
|
||||||
}
|
}
|
||||||
|
|
||||||
lvl = capByLevel(user.stats.lvl);
|
let lvl = capByLevel(user.stats.lvl);
|
||||||
|
|
||||||
_.each(tasks, function resetTasks (task) {
|
_.each(tasks, function resetTasks (task) {
|
||||||
|
if (!task.challenge || !task.challenge.id || task.challenge.broken) {
|
||||||
if (task.type !== 'reward') {
|
if (task.type !== 'reward') {
|
||||||
task.value = 0;
|
task.value = 0;
|
||||||
}
|
}
|
||||||
if (task.type === 'daily') {
|
if (task.type === 'daily') {
|
||||||
task.streak = 0;
|
task.streak = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stats = user.stats;
|
let stats = user.stats;
|
||||||
stats.buffs = {};
|
stats.buffs = {};
|
||||||
stats.hp = 50;
|
stats.hp = 50;
|
||||||
stats.lvl = 1;
|
stats.lvl = 1;
|
||||||
@@ -79,7 +76,7 @@ module.exports = function rebirth (user, tasks = [], req = {}, analytics) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = user.flags;
|
let flags = user.flags;
|
||||||
if (!user.achievements.beastMaster) {
|
if (!user.achievements.beastMaster) {
|
||||||
flags.rebirthEnabled = false;
|
flags.rebirthEnabled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ module.exports = function reroll (user, tasks = [], req = {}, analytics) {
|
|||||||
user.stats.hp = 50;
|
user.stats.hp = 50;
|
||||||
|
|
||||||
_.each(tasks, function resetTaskValues (task) {
|
_.each(tasks, function resetTaskValues (task) {
|
||||||
|
if (!task.challenge || !task.challenge.id || task.challenge.broken) {
|
||||||
if (task.type !== 'reward') {
|
if (task.type !== 'reward') {
|
||||||
task.value = 0;
|
task.value = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ module.exports = function reset (user, tasks = [], req = {}) {
|
|||||||
tasksToRemove.push(task._id);
|
tasksToRemove.push(task._id);
|
||||||
let i = user.tasksOrder[`${task.type}s`].indexOf(task._id);
|
let i = user.tasksOrder[`${task.type}s`].indexOf(task._id);
|
||||||
if (i !== -1) user.tasksOrder[`${task.type}s`].splice(i, 1);
|
if (i !== -1) user.tasksOrder[`${task.type}s`].splice(i, 1);
|
||||||
tasksToRemove.push(task._id);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ describe('POST /tasks/user', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`ignores setting userId, history, createdAt,
|
it(`ignores setting userId, history, createdAt,
|
||||||
updatedAt, challenge, completed, streak,
|
updatedAt, challenge, completed,
|
||||||
dateCompleted fields`, async () => {
|
dateCompleted fields`, async () => {
|
||||||
let task = await user.post('/tasks/user', {
|
let task = await user.post('/tasks/user', {
|
||||||
text: 'test daily',
|
text: 'test daily',
|
||||||
@@ -119,7 +119,6 @@ describe('POST /tasks/user', () => {
|
|||||||
updatedAt: 'tomorrow',
|
updatedAt: 'tomorrow',
|
||||||
challenge: 'no',
|
challenge: 'no',
|
||||||
completed: true,
|
completed: true,
|
||||||
streak: 25,
|
|
||||||
dateCompleted: 'never',
|
dateCompleted: 'never',
|
||||||
value: 324, // ignored because not a reward
|
value: 324, // ignored because not a reward
|
||||||
});
|
});
|
||||||
@@ -130,7 +129,6 @@ describe('POST /tasks/user', () => {
|
|||||||
expect(task.updatedAt).not.to.equal('tomorrow');
|
expect(task.updatedAt).not.to.equal('tomorrow');
|
||||||
expect(task.challenge).not.to.equal('no');
|
expect(task.challenge).not.to.equal('no');
|
||||||
expect(task.completed).to.equal(false);
|
expect(task.completed).to.equal(false);
|
||||||
expect(task.streak).to.equal(0);
|
|
||||||
expect(task.streak).not.to.equal('never');
|
expect(task.streak).not.to.equal('never');
|
||||||
expect(task.value).not.to.equal(324);
|
expect(task.value).not.to.equal(324);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ describe('POST /user/buy-armoire', () => {
|
|||||||
await user.update({
|
await user.update({
|
||||||
'stats.gp': 5,
|
'stats.gp': 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
await expect(user.post('/user/buy-armoire'))
|
await expect(user.post('/user/buy-armoire'))
|
||||||
.to.eventually.be.rejected.and.eql({
|
.to.eventually.be.rejected.and.eql({
|
||||||
code: 401,
|
code: 401,
|
||||||
@@ -28,6 +29,7 @@ describe('POST /user/buy-armoire', () => {
|
|||||||
|
|
||||||
it('reduces gold when buying from the armoire', async () => {
|
it('reduces gold when buying from the armoire', async () => {
|
||||||
await user.post('/user/buy-armoire');
|
await user.post('/user/buy-armoire');
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.stats.gp).to.equal(300);
|
expect(user.stats.gp).to.equal(300);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import shared from '../../../../../common/script';
|
|||||||
|
|
||||||
let content = shared.content;
|
let content = shared.content;
|
||||||
|
|
||||||
describe('POST /user/buy-potion', () => {
|
describe('POST /user/buy-health-potion', () => {
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -18,7 +18,7 @@ describe('POST /user/buy-potion', () => {
|
|||||||
// More tests in common code unit tests
|
// More tests in common code unit tests
|
||||||
|
|
||||||
it('returns an error if user does not have enough gold', async () => {
|
it('returns an error if user does not have enough gold', async () => {
|
||||||
await expect(user.post('/user/buy-potion'))
|
await expect(user.post('/user/buy-health-potion'))
|
||||||
.to.eventually.be.rejected.and.eql({
|
.to.eventually.be.rejected.and.eql({
|
||||||
code: 401,
|
code: 401,
|
||||||
error: 'NotAuthorized',
|
error: 'NotAuthorized',
|
||||||
@@ -32,7 +32,7 @@ describe('POST /user/buy-potion', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let potion = content.potion;
|
let potion = content.potion;
|
||||||
let res = await user.post('/user/buy-potion');
|
let res = await user.post('/user/buy-health-potion');
|
||||||
await user.sync();
|
await user.sync();
|
||||||
|
|
||||||
expect(user.stats.hp).to.equal(50);
|
expect(user.stats.hp).to.equal(50);
|
||||||
@@ -31,6 +31,7 @@ describe('POST /user/rebirth', () => {
|
|||||||
let daily = await generateDaily({
|
let daily = await generateDaily({
|
||||||
text: 'test habit',
|
text: 'test habit',
|
||||||
type: 'daily',
|
type: 'daily',
|
||||||
|
value: 1,
|
||||||
streak: 1,
|
streak: 1,
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
} from '../../helpers/common.helper';
|
} from '../../helpers/common.helper';
|
||||||
import buyPotion from '../../../common/script/ops/buyPotion';
|
import buyHealthPotion from '../../../common/script/ops/buyHealthPotion';
|
||||||
import {
|
import {
|
||||||
NotAuthorized,
|
NotAuthorized,
|
||||||
} from '../../../common/script/libs/errors';
|
} from '../../../common/script/libs/errors';
|
||||||
import i18n from '../../../common/script/i18n';
|
import i18n from '../../../common/script/i18n';
|
||||||
|
|
||||||
describe('shared.ops.buyPotion', () => {
|
describe('shared.ops.buyHealthPotion', () => {
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -30,19 +30,19 @@ describe('shared.ops.buyPotion', () => {
|
|||||||
context('Potion', () => {
|
context('Potion', () => {
|
||||||
it('recovers 15 hp', () => {
|
it('recovers 15 hp', () => {
|
||||||
user.stats.hp = 30;
|
user.stats.hp = 30;
|
||||||
buyPotion(user);
|
buyHealthPotion(user);
|
||||||
expect(user.stats.hp).to.eql(45);
|
expect(user.stats.hp).to.eql(45);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not increase hp above 50', () => {
|
it('does not increase hp above 50', () => {
|
||||||
user.stats.hp = 45;
|
user.stats.hp = 45;
|
||||||
buyPotion(user);
|
buyHealthPotion(user);
|
||||||
expect(user.stats.hp).to.eql(50);
|
expect(user.stats.hp).to.eql(50);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deducts 25 gp', () => {
|
it('deducts 25 gp', () => {
|
||||||
user.stats.hp = 45;
|
user.stats.hp = 45;
|
||||||
buyPotion(user);
|
buyHealthPotion(user);
|
||||||
|
|
||||||
expect(user.stats.gp).to.eql(175);
|
expect(user.stats.gp).to.eql(175);
|
||||||
});
|
});
|
||||||
@@ -51,7 +51,7 @@ describe('shared.ops.buyPotion', () => {
|
|||||||
user.stats.hp = 45;
|
user.stats.hp = 45;
|
||||||
user.stats.gp = 5;
|
user.stats.gp = 5;
|
||||||
try {
|
try {
|
||||||
buyPotion(user);
|
buyHealthPotion(user);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||||
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
|
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
|
||||||
@@ -3,7 +3,9 @@ import i18n from '../../../common/script/i18n';
|
|||||||
import { MAX_LEVEL } from '../../../common/script/constants';
|
import { MAX_LEVEL } from '../../../common/script/constants';
|
||||||
import {
|
import {
|
||||||
generateUser,
|
generateUser,
|
||||||
|
generateHabit,
|
||||||
generateDaily,
|
generateDaily,
|
||||||
|
generateTodo,
|
||||||
generateReward,
|
generateReward,
|
||||||
} from '../../helpers/common.helper';
|
} from '../../helpers/common.helper';
|
||||||
import {
|
import {
|
||||||
@@ -19,7 +21,7 @@ describe('shared.ops.rebirth', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
user = generateUser();
|
user = generateUser();
|
||||||
user.balance = 2;
|
user.balance = 2;
|
||||||
tasks = [generateDaily(), generateReward()];
|
tasks = [generateHabit(), generateDaily(), generateTodo(), generateReward()];
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an error when user balance is too low and user is less than max level', (done) => {
|
it('returns an error when user balance is too low and user is less than max level', (done) => {
|
||||||
@@ -49,22 +51,35 @@ describe('shared.ops.rebirth', () => {
|
|||||||
expect(message).to.equal(i18n.t('rebirthComplete'));
|
expect(message).to.equal(i18n.t('rebirthComplete'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resets user\'s taks values except for rewards to 0', () => {
|
it('rebirths a user with not enough gems but more than max level', () => {
|
||||||
|
user.balance = 0;
|
||||||
|
user.stats.lvl = MAX_LEVEL + 1;
|
||||||
|
|
||||||
|
let [, message] = rebirth(user);
|
||||||
|
|
||||||
|
expect(message).to.equal(i18n.t('rebirthComplete'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resets user\'s tasks values except for rewards to 0', () => {
|
||||||
tasks[0].value = 1;
|
tasks[0].value = 1;
|
||||||
tasks[1].value = 1;
|
tasks[1].value = 1;
|
||||||
|
tasks[2].value = 1;
|
||||||
|
tasks[3].value = 1; // Reward
|
||||||
|
|
||||||
rebirth(user, tasks);
|
rebirth(user, tasks);
|
||||||
|
|
||||||
expect(tasks[0].value).to.equal(0);
|
expect(tasks[0].value).to.equal(0);
|
||||||
expect(tasks[1].value).to.equal(1);
|
expect(tasks[1].value).to.equal(0);
|
||||||
|
expect(tasks[2].value).to.equal(0);
|
||||||
|
expect(tasks[3].value).to.equal(1); // Reward
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resets user\'s daily streaks to 0', () => {
|
it('resets user\'s daily streaks to 0', () => {
|
||||||
tasks[0].streak = 1;
|
tasks[1].streak = 1; // Daily
|
||||||
|
|
||||||
rebirth(user, tasks);
|
rebirth(user, tasks);
|
||||||
|
|
||||||
expect(tasks[0].streak).to.equal(0);
|
expect(tasks[1].streak).to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resets a user\'s buffs', () => {
|
it('resets a user\'s buffs', () => {
|
||||||
@@ -156,7 +171,7 @@ describe('shared.ops.rebirth', () => {
|
|||||||
expect(user.flags.dropsEnabled).to.be.false;
|
expect(user.flags.dropsEnabled).to.be.false;
|
||||||
expect(user.flags.classSelected).to.be.false;
|
expect(user.flags.classSelected).to.be.false;
|
||||||
expect(user.flags.rebirthEnabled).to.be.false;
|
expect(user.flags.rebirthEnabled).to.be.false;
|
||||||
expect(user.flags.levelDrops).to.be.emtpy;
|
expect(user.flags.levelDrops).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not reset rebirthEnabled if user has beastMaster', () => {
|
it('does not reset rebirthEnabled if user has beastMaster', () => {
|
||||||
@@ -175,7 +190,7 @@ describe('shared.ops.rebirth', () => {
|
|||||||
expect(user.achievements.rebirthLevel).to.equal(user.stats.lvl);
|
expect(user.achievements.rebirthLevel).to.equal(user.stats.lvl);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('increments rebirth achievemnts', () => {
|
it('increments rebirth achievements', () => {
|
||||||
user.stats.lvl = 2;
|
user.stats.lvl = 2;
|
||||||
user.achievements.rebirths = 1;
|
user.achievements.rebirths = 1;
|
||||||
user.achievements.rebirthLevel = 1;
|
user.achievements.rebirthLevel = 1;
|
||||||
@@ -185,4 +200,37 @@ describe('shared.ops.rebirth', () => {
|
|||||||
expect(user.achievements.rebirths).to.equal(2);
|
expect(user.achievements.rebirths).to.equal(2);
|
||||||
expect(user.achievements.rebirthLevel).to.equal(2);
|
expect(user.achievements.rebirthLevel).to.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not increment rebirth achievements when level is lower than previous', () => {
|
||||||
|
user.stats.lvl = 2;
|
||||||
|
user.achievements.rebirths = 1;
|
||||||
|
user.achievements.rebirthLevel = 3;
|
||||||
|
|
||||||
|
rebirth(user);
|
||||||
|
|
||||||
|
expect(user.achievements.rebirths).to.equal(1);
|
||||||
|
expect(user.achievements.rebirthLevel).to.equal(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('always increments rebirth achievements when level is MAX_LEVEL', () => {
|
||||||
|
user.stats.lvl = MAX_LEVEL;
|
||||||
|
user.achievements.rebirths = 1;
|
||||||
|
user.achievements.rebirthLevel = MAX_LEVEL + 1; // this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
|
||||||
|
|
||||||
|
rebirth(user);
|
||||||
|
|
||||||
|
expect(user.achievements.rebirths).to.equal(2);
|
||||||
|
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('always increments rebirth achievements when level is greater than MAX_LEVEL', () => {
|
||||||
|
user.stats.lvl = MAX_LEVEL + 1;
|
||||||
|
user.achievements.rebirths = 1;
|
||||||
|
user.achievements.rebirthLevel = MAX_LEVEL + 2; // this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
|
||||||
|
|
||||||
|
rebirth(user);
|
||||||
|
|
||||||
|
expect(user.achievements.rebirths).to.equal(2);
|
||||||
|
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (spell.target == 'tasks') {
|
} else if (spell.target == 'tasks') {
|
||||||
var tasks = User.user.habits.concat(User.user.dailys).concat(User.user.rewards);
|
var tasks = User.user.habits.concat(User.user.dailys).concat(User.user.rewards).concat(User.user.todos);
|
||||||
// exclude challenge tasks
|
// exclude challenge tasks
|
||||||
tasks = tasks.filter(function (t) {
|
tasks = tasks.filter(function (t) {
|
||||||
if (!t.challenge) return true;
|
if (!t.challenge) return true;
|
||||||
@@ -316,7 +316,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
|||||||
if (targetId) spellUrl += '?targetId=' + targetId;
|
if (targetId) spellUrl += '?targetId=' + targetId;
|
||||||
|
|
||||||
$http.post(spellUrl)
|
$http.post(spellUrl)
|
||||||
.success(function(){
|
.success(function(){ // TODO response will always include the modified data, no need to sync!
|
||||||
var msg = window.env.t('youCast', {spell: spell.text()});
|
var msg = window.env.t('youCast', {spell: spell.text()});
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'task': msg = window.env.t('youCastTarget', {spell: spell.text(), target: target.text});break;
|
case 'task': msg = window.env.t('youCastTarget', {spell: spell.text(), target: target.text});break;
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ habitrpg.controller('SettingsCtrl',
|
|||||||
|
|
||||||
$scope.reset = function(){
|
$scope.reset = function(){
|
||||||
User.reset({});
|
User.reset({});
|
||||||
|
User.sync();
|
||||||
$rootScope.$state.go('tasks');
|
$rootScope.$state.go('tasks');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,7 @@ angular.module('habitrpg')
|
|||||||
clearCards: clearCards,
|
clearCards: clearCards,
|
||||||
}
|
}
|
||||||
|
|
||||||
//@TOOD: Port when User service is updated
|
|
||||||
function clearCards() {
|
function clearCards() {
|
||||||
User.user.ops.update && User.set({'flags.cardReceived':false});
|
User.user._wrapped && User.set({'flags.cardReceived':false});
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@@ -264,8 +264,8 @@ function($rootScope, User, $timeout, $state, Analytics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Init and show the welcome tour (only after user is pulled from server & wrapped).
|
//Init and show the welcome tour (only after user is pulled from server & wrapped).
|
||||||
var watcher = $rootScope.$watch('User.user.ops.update', function(updateFn){
|
var watcher = $rootScope.$watch('User.user._wrapped', function(wrapped){
|
||||||
if (!updateFn) return; // only run after user has been wrapped
|
if (!wrapped) return; // only run after user has been wrapped
|
||||||
watcher(); // deregister watcher
|
watcher(); // deregister watcher
|
||||||
if (window.env.IS_MOBILE) return; // Don't show tour immediately on mobile devices
|
if (window.env.IS_MOBILE) return; // Don't show tour immediately on mobile devices
|
||||||
if (User.user.flags.welcomed == false) {
|
if (User.user.flags.welcomed == false) {
|
||||||
|
|||||||
@@ -61,21 +61,13 @@ angular.module('habitrpg')
|
|||||||
// replicated. We need to wrap each op to provide a callback to send that operation
|
// replicated. We need to wrap each op to provide a callback to send that operation
|
||||||
$window.habitrpgShared.wrap(user);
|
$window.habitrpgShared.wrap(user);
|
||||||
_.each(user.ops, function(op,k){
|
_.each(user.ops, function(op,k){
|
||||||
user.ops[k] = function(req,cb){
|
user.ops[k] = function(req){
|
||||||
if (cb) return op(req,cb);
|
try {
|
||||||
op(req,function(err,response) {
|
op(req);
|
||||||
for(var updatedItem in req.body) {
|
} catch (err) {
|
||||||
var itemUpdateResponse = userNotifications[updatedItem];
|
Notification.text(err.message);
|
||||||
if(itemUpdateResponse) Notification.text(itemUpdateResponse);
|
return;
|
||||||
}
|
}
|
||||||
if (err) {
|
|
||||||
var message = err.code ? err.message : err;
|
|
||||||
Notification.text(message);
|
|
||||||
// In the case of 200s, they're friendly alert messages like "Your pet has hatched!" - still send the op
|
|
||||||
if ((err.code && err.code >= 400) || !err.code) return;
|
|
||||||
}
|
|
||||||
userServices.log({op:k, params: req.params, query:req.query, body:req.body});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -106,13 +98,27 @@ angular.module('habitrpg')
|
|||||||
function callOpsFunctionAndRequest (opName, endPoint, method, paramString, opData) {
|
function callOpsFunctionAndRequest (opName, endPoint, method, paramString, opData) {
|
||||||
if (!opData) opData = {};
|
if (!opData) opData = {};
|
||||||
|
|
||||||
|
var clientResponse;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$window.habitrpgShared.ops[opName](user, opData);
|
var args = [user];
|
||||||
} catch(err) {
|
if (opName === 'rebirth' || opName === 'reroll' || opName === 'reset') {
|
||||||
|
args.push(user.habits.concat(user.dailys).concat(user.rewards).concat(user.todos));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(opData);
|
||||||
|
clientResponse = $window.habitrpgShared.ops[opName].apply(null, args);
|
||||||
|
} catch (err) {
|
||||||
Notification.text(err.message);
|
Notification.text(err.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientMessage = clientResponse[1];
|
||||||
|
|
||||||
|
if (clientMessage) {
|
||||||
|
Notification.text(clientMessage);
|
||||||
|
}
|
||||||
|
|
||||||
var url = '/api/v3/user/' + endPoint;
|
var url = '/api/v3/user/' + endPoint;
|
||||||
if (paramString) {
|
if (paramString) {
|
||||||
url += '/' + paramString
|
url += '/' + paramString
|
||||||
@@ -130,7 +136,7 @@ angular.module('habitrpg')
|
|||||||
body: body,
|
body: body,
|
||||||
})
|
})
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
if (response.data.message) Notification.text(response.data.message);
|
if (response.data.message && response.data.message !== clientMessage) Notification.text(response.data.message);
|
||||||
save();
|
save();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -182,7 +188,12 @@ angular.module('habitrpg')
|
|||||||
},
|
},
|
||||||
|
|
||||||
score: function (data) {
|
score: function (data) {
|
||||||
|
try {
|
||||||
$window.habitrpgShared.ops.scoreTask({user: user, task: data.params.task, direction: data.params.direction}, data.params);
|
$window.habitrpgShared.ops.scoreTask({user: user, task: data.params.task, direction: data.params.direction}, data.params);
|
||||||
|
} catch (err) {
|
||||||
|
Notification.text(err.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
save();
|
save();
|
||||||
Tasks.scoreTask(data.params.task._id, data.params.direction).then(function (res) {
|
Tasks.scoreTask(data.params.task._id, data.params.direction).then(function (res) {
|
||||||
var tmp = res.data.data._tmp || {}; // used to notify drops, critical hits and other bonuses
|
var tmp = res.data.data._tmp || {}; // used to notify drops, critical hits and other bonuses
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ async function saveContentToDisk (language, content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v3/content Get all available content objects.
|
* @api {get} /api/v3/content Get all available content objects
|
||||||
* @apiDescription Does not require authentication.
|
* @apiDescription Does not require authentication.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName ContentGet
|
* @apiName ContentGet
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import _ from 'lodash';
|
|||||||
let api = {};
|
let api = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/debug/add-ten-gems Add ten gems to the current user.
|
* @api {post} /api/v3/debug/add-ten-gems Add ten gems to the current user
|
||||||
* @apiDescription Only available in development mode.
|
* @apiDescription Only available in development mode.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName AddTenGems
|
* @apiName AddTenGems
|
||||||
@@ -31,7 +31,7 @@ api.addTenGems = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/debug/add-hourglass Add Hourglass to the current user.
|
* @api {post} /api/v3/debug/add-hourglass Add Hourglass to the current user
|
||||||
* @apiDescription Only available in development mode.
|
* @apiDescription Only available in development mode.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName AddHourglass
|
* @apiName AddHourglass
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import _ from 'lodash';
|
|||||||
let api = {};
|
let api = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v3/hall/patrons Get all Patrons.
|
* @api {get} /api/v3/hall/patrons Get all patrons
|
||||||
* @apiDescription Only the first 50 patrons are returned. More can be accessed passing ?page=n.
|
* @apiDescription Only the first 50 patrons are returned. More can be accessed passing ?page=n
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName GetPatrons
|
* @apiName GetPatrons
|
||||||
* @apiGroup Hall
|
* @apiGroup Hall
|
||||||
@@ -79,13 +79,13 @@ api.getHeroes = {
|
|||||||
const heroAdminFields = 'contributor balance profile.name purchased items auth';
|
const heroAdminFields = 'contributor balance profile.name purchased items auth';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v3/hall/heroes/:heroId Get an hero given his _id.
|
* @api {get} /api/v3/hall/heroes/:heroId Get any user ("hero") given the UUID
|
||||||
* @apiDescription Must be an admin to make this request
|
* @apiDescription Must be an admin to make this request.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName GetHero
|
* @apiName GetHero
|
||||||
* @apiGroup Hall
|
* @apiGroup Hall
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data The hero object
|
* @apiSuccess {Object} data The user object
|
||||||
*/
|
*/
|
||||||
api.getHero = {
|
api.getHero = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -117,13 +117,13 @@ api.getHero = {
|
|||||||
const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
|
const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {put} /api/v3/hall/heroes/:heroId Update an hero.
|
* @api {put} /api/v3/hall/heroes/:heroId Update any user ("hero")
|
||||||
* @apiDescription Must be an admin to make this request
|
* @apiDescription Must be an admin to make this request.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UpdateHero
|
* @apiName UpdateHero
|
||||||
* @apiGroup Hall
|
* @apiGroup Hall
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data The updated hero object
|
* @apiSuccess {Object} data The updated user object
|
||||||
*/
|
*/
|
||||||
api.updateHero = {
|
api.updateHero = {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ let tasksModels = ['habit', 'daily', 'todo', 'reward'];
|
|||||||
let allModels = ['user', 'tag', 'challenge', 'group'].concat(tasksModels);
|
let allModels = ['user', 'tag', 'challenge', 'group'].concat(tasksModels);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v3/models/:model/paths Get all paths for the specified model.
|
* @api {get} /api/v3/models/:model/paths Get all paths for the specified model
|
||||||
* @apiDescription Doesn't require authentication
|
* @apiDescription Doesn't require authentication
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName GetUserModelPaths
|
* @apiName GetUserModelPaths
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ async function _createTasks (req, res, user, challenge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/tasks/user Create a new task belonging to the user.
|
* @api {post} /api/v3/tasks/user Create a new task belonging to the user
|
||||||
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
|
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName CreateUserTasks
|
* @apiName CreateUserTasks
|
||||||
@@ -73,13 +73,13 @@ api.createUserTasks = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/tasks/challenge/:challengeId Create a new task belonging to a challenge.
|
* @api {post} /api/v3/tasks/challenge/:challengeId Create a new task belonging to a challenge
|
||||||
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
|
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName CreateChallengeTasks
|
* @apiName CreateChallengeTasks
|
||||||
* @apiGroup Task
|
* @apiGroup Task
|
||||||
*
|
*
|
||||||
* @apiParam {UUID} challengeId The id of the challenge the new task(s) will belong to.
|
* @apiParam {UUID} challengeId The id of the challenge the new task(s) will belong to
|
||||||
*
|
*
|
||||||
* @apiSuccess data An object if a single task was created, otherwise an array of tasks
|
* @apiSuccess data An object if a single task was created, otherwise an array of tasks
|
||||||
*/
|
*/
|
||||||
@@ -171,7 +171,7 @@ async function _getTasks (req, res, user, challenge) {
|
|||||||
* @apiName GetUserTasks
|
* @apiName GetUserTasks
|
||||||
* @apiGroup Task
|
* @apiGroup Task
|
||||||
*
|
*
|
||||||
* @apiParam {string="habits","dailys","todos","rewards","completedTodos"} type Optional query parameter to return just a type of tasks. By default all types will be returned except completed todos that requested separately.
|
* @apiParam {string="habits","dailys","todos","rewards","completedTodos"} type Optional query parameter to return just a type of tasks. By default all types will be returned except completed todos that must be requested separately.
|
||||||
*
|
*
|
||||||
* @apiSuccess {Array} data An array of tasks
|
* @apiSuccess {Array} data An array of tasks
|
||||||
*/
|
*/
|
||||||
@@ -197,7 +197,7 @@ api.getUserTasks = {
|
|||||||
* @apiName GetChallengeTasks
|
* @apiName GetChallengeTasks
|
||||||
* @apiGroup Task
|
* @apiGroup Task
|
||||||
*
|
*
|
||||||
* @apiParam {UUID} challengeId The id of the challenge from which to retrieve the tasks.
|
* @apiParam {UUID} challengeId The id of the challenge from which to retrieve the tasks
|
||||||
* @apiParam {string="habits","dailys","todos","rewards"} type Optional query parameter to return just a type of tasks
|
* @apiParam {string="habits","dailys","todos","rewards"} type Optional query parameter to return just a type of tasks
|
||||||
*
|
*
|
||||||
* @apiSuccess {Array} data An array of tasks
|
* @apiSuccess {Array} data An array of tasks
|
||||||
@@ -427,9 +427,9 @@ api.scoreTask = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// completed todos cannot be moved, they'll be returned ordered by date of completion
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/tasks/:taskId/move/to/:position Move a task to a new position
|
* @api {post} /api/v3/tasks/:taskId/move/to/:position Move a task to a new position
|
||||||
|
* @apiDescription Note: completed To-Dos are not sortable, do not appear in user.tasksOrder.todos, and are ordered by date of completion.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName MoveTask
|
* @apiName MoveTask
|
||||||
* @apiGroup Task
|
* @apiGroup Task
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ let checkPreferencePurchase = (user, path, item) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {put} /api/v3/user Update the user.
|
* @api {put} /api/v3/user Update the user
|
||||||
* @apiDescription Example body: {'stats.hp':50, 'preferences.background': 'beach'}
|
* @apiDescription Example body: {'stats.hp':50, 'preferences.background': 'beach'}
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserUpdate
|
* @apiName UserUpdate
|
||||||
@@ -305,13 +305,13 @@ api.getUserAnonymized = {
|
|||||||
const partyMembersFields = 'profile.name stats achievements items.special';
|
const partyMembersFields = 'profile.name stats achievements items.special';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/class/cast/:spellId Cast a spell on a target.
|
* @api {post} /api/v3/user/class/cast/:spellId Cast a skill (spell) on a target
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserCast
|
* @apiName UserCast
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} spellId The spell to cast.
|
* @apiParam {string} spellId The skill to cast
|
||||||
* @apiParam {UUID} targetId Optional query parameter, the id of the target when casting a spell on a party member or a task.
|
* @apiParam {UUID} targetId Optional query parameter, the id of the target when casting a skill on a party member or a task
|
||||||
*
|
*
|
||||||
* @apiSuccess data Will return the modified targets. For party members only the necessary fields will be populated. The user is always returned.
|
* @apiSuccess data Will return the modified targets. For party members only the necessary fields will be populated. The user is always returned.
|
||||||
*/
|
*/
|
||||||
@@ -443,7 +443,7 @@ api.castSpell = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/sleep Put the user in the inn.
|
* @api {post} /api/v3/user/sleep Make the user start / stop sleeping (resting in the Inn)
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserSleep
|
* @apiName UserSleep
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -463,7 +463,7 @@ api.sleep = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/allocate Allocate an attribute point.
|
* @api {post} /api/v3/user/allocate Allocate an attribute point
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserAllocate
|
* @apiName UserAllocate
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -485,7 +485,8 @@ api.allocate = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/allocate-now Allocate all attribute points.
|
* @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.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserAllocateNow
|
* @apiName UserAllocateNow
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -511,7 +512,7 @@ api.allocateNow = {
|
|||||||
* @apiName UserBuy
|
* @apiName UserBuy
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} key The item to buy.
|
* @apiParam {string} key The item to buy
|
||||||
*/
|
*/
|
||||||
api.buy = {
|
api.buy = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -526,12 +527,12 @@ api.buy = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /user/buy-gear/:key Buy a piece of gear.
|
* @api {post} /user/buy-gear/:key Buy a piece of gear
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuyGear
|
* @apiName UserBuyGear
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} key The item to buy.
|
* @apiParam {string} key The item to buy
|
||||||
*
|
*
|
||||||
* @apiSuccess {object} data.items user.items
|
* @apiSuccess {object} data.items user.items
|
||||||
* @apiSuccess {object} data.flags user.flags
|
* @apiSuccess {object} data.flags user.flags
|
||||||
@@ -552,7 +553,7 @@ api.buyGear = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /user/buy-armoire Buy an armoire item.
|
* @api {post} /user/buy-armoire Buy an armoire item
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuyArmoire
|
* @apiName UserBuyArmoire
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -575,7 +576,7 @@ api.buyArmoire = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /user/buy-potion Buy a health potion
|
* @api {post} /user/buy-health-potion Buy a health potion
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuyPotion
|
* @apiName UserBuyPotion
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -583,25 +584,25 @@ api.buyArmoire = {
|
|||||||
* @apiSuccess {Object} data user.stats
|
* @apiSuccess {Object} data user.stats
|
||||||
* @apiSuccess {string} message Success message
|
* @apiSuccess {string} message Success message
|
||||||
*/
|
*/
|
||||||
api.buyPotion = {
|
api.buyHealthPotion = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
middlewares: [authWithHeaders()],
|
middlewares: [authWithHeaders()],
|
||||||
url: '/user/buy-potion',
|
url: '/user/buy-health-potion',
|
||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
let user = res.locals.user;
|
let user = res.locals.user;
|
||||||
let buyPotionResponse = common.ops.buyPotion(user, req, res.analytics);
|
let buyHealthPotionResponse = common.ops.buyHealthPotion(user, req, res.analytics);
|
||||||
await user.save();
|
await user.save();
|
||||||
res.respond(200, ...buyPotionResponse);
|
res.respond(200, ...buyHealthPotionResponse);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /user/buy-mystery-set/:key Buy a mystery set.
|
* @api {post} /user/buy-mystery-set/:key Buy a mystery set
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuyMysterySet
|
* @apiName UserBuyMysterySet
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} key The mystery set to buy.
|
* @apiParam {string} key The mystery set to buy
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data.items user.items
|
* @apiSuccess {Object} data.items user.items
|
||||||
* @apiSuccess {Object} data.purchasedPlanConsecutive user.purchased.plan.consecutive
|
* @apiSuccess {Object} data.purchasedPlanConsecutive user.purchased.plan.consecutive
|
||||||
@@ -620,12 +621,12 @@ api.buyMysterySet = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/buy-quest/:key Buy a quest with gold.
|
* @api {post} /api/v3/user/buy-quest/:key Buy a quest with gold
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuyQuest
|
* @apiName UserBuyQuest
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} key The quest spell to buy.
|
* @apiParam {string} key The quest scroll to buy
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data `user.items.quests`
|
* @apiSuccess {Object} data `user.items.quests`
|
||||||
* @apiSuccess {string} message Success message
|
* @apiSuccess {string} message Success message
|
||||||
@@ -643,12 +644,13 @@ api.buyQuest = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/buy-special-spell/:key Buy special spell.
|
* @api {post} /api/v3/user/buy-special-spell/:key Buy special "spell" item
|
||||||
|
* @apiDescription Includes gift cards (e.g., birthday card), and avatar Transformation Items and their antidotes (e.g., Snowball item and Salt reward).
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserBuySpecialSpell
|
* @apiName UserBuySpecialSpell
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} key The special spell to buy.
|
* @apiParam {string} key The special item to buy. Must be one of the keys from "content.special", such as birthday, snowball, salt.
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data.stats user.stats
|
* @apiSuccess {Object} data.stats user.stats
|
||||||
* @apiSuccess {Object} data.items user.items
|
* @apiSuccess {Object} data.items user.items
|
||||||
@@ -667,13 +669,13 @@ api.buySpecialSpell = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/hatch/:egg/:hatchingPotion Hatch a pet.
|
* @api {post} /api/v3/user/hatch/:egg/:hatchingPotion Hatch a pet
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserHatch
|
* @apiName UserHatch
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} egg The egg to use.
|
* @apiParam {string} egg The egg to use
|
||||||
* @apiParam {string} hatchingPotion The hatching potion to use.
|
* @apiParam {string} hatchingPotion The hatching potion to use
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data user.items
|
* @apiSuccess {Object} data user.items
|
||||||
* @apiSuccess {string} message
|
* @apiSuccess {string} message
|
||||||
@@ -739,13 +741,13 @@ api.feed = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/change-class Change class.
|
* @api {post} /api/v3/user/change-class Change class
|
||||||
* @apiDescription User must be at least level 10. If ?class is defined and user.flags.classSelected is false it'll change the class. If user.preferences.disableClasses it'll enable classes, otherwise it sets user.flags.classSelected to false (costs 3 gems)
|
* @apiDescription User must be at least level 10. If ?class is defined and user.flags.classSelected is false it'll change the class. If user.preferences.disableClasses it'll enable classes, otherwise it sets user.flags.classSelected to false (costs 3 gems)
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserChangeClass
|
* @apiName UserChangeClass
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} class Query parameter - ?class={warrior|rogue|wizard|healer}.
|
* @apiParam {string} class Query parameter - ?class={warrior|rogue|wizard|healer}
|
||||||
*
|
*
|
||||||
* @apiSuccess {object} data.flags user.flags
|
* @apiSuccess {object} data.flags user.flags
|
||||||
* @apiSuccess {object} data.stats user.stats
|
* @apiSuccess {object} data.stats user.stats
|
||||||
@@ -765,7 +767,7 @@ api.changeClass = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/disable-classes Disable classes.
|
* @api {post} /api/v3/user/disable-classes Disable classes
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserDisableClasses
|
* @apiName UserDisableClasses
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -787,13 +789,13 @@ api.disableClasses = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/purchase/:type/:key Purchase Gem Items.
|
* @api {post} /api/v3/user/purchase/:type/:key Purchase Gem or Gem-purchasable item
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserPurchase
|
* @apiName UserPurchase
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} type Type of item to purchase. Must be one of: gem, gems, eggs, hatchingPotions, food, quests or gear
|
* @apiParam {string} type Type of item to purchase. Must be one of: gems, eggs, hatchingPotions, food, quests, or gear
|
||||||
* @apiParam {string} key Item's key
|
* @apiParam {string} key Item's key (use "gem" for purchasing gems)
|
||||||
*
|
*
|
||||||
* @apiSuccess {object} data.items user.items
|
* @apiSuccess {object} data.items user.items
|
||||||
* @apiSuccess {number} data.balance user.balance
|
* @apiSuccess {number} data.balance user.balance
|
||||||
@@ -812,7 +814,7 @@ api.purchase = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/purchase-hourglass/:type/:key Purchase Hourglass.
|
* @api {post} /api/v3/user/purchase-hourglass/:type/:key Purchase Hourglass-purchasable item
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserPurchaseHourglass
|
* @apiName UserPurchaseHourglass
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -837,7 +839,7 @@ api.userPurchaseHourglass = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/read-card/:cardType Reads a card.
|
* @api {post} /api/v3/user/read-card/:cardType Reads a card
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReadCard
|
* @apiName UserReadCard
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -861,7 +863,7 @@ api.readCard = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/open-mystery-item Open the mystery item.
|
* @api {post} /api/v3/user/open-mystery-item Open the Mystery Item box
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserOpenMysteryItem
|
* @apiName UserOpenMysteryItem
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -881,7 +883,7 @@ api.userOpenMysteryItem = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/webhook Create a new webhook
|
* @api {post} /api/v3/user/webhook Create a new webhook
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserAddWebhook
|
* @apiName UserAddWebhook
|
||||||
@@ -904,7 +906,7 @@ api.addWebhook = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {put} /api/v3/user/webhook/:id Edit a webhook
|
* @api {put} /api/v3/user/webhook/:id Edit a webhook
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserUpdateWebhook
|
* @apiName UserUpdateWebhook
|
||||||
@@ -928,7 +930,7 @@ api.updateWebhook = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {delete} /api/v3/user/webhook/:id Delete a webhook
|
* @api {delete} /api/v3/user/webhook/:id Delete a webhook
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserDeleteWebhook
|
* @apiName UserDeleteWebhook
|
||||||
@@ -951,7 +953,7 @@ api.deleteWebhook = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* @api {post} /api/v3/user/release-pets Releases pets.
|
/* @api {post} /api/v3/user/release-pets Release pets
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReleasePets
|
* @apiName UserReleasePets
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -971,8 +973,8 @@ api.userReleasePets = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/release-both Releases Pets and Mounts and grants Triad Bingo.
|
* @api {post} /api/v3/user/release-both Release pets and mounts and grants Triad Bingo
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReleaseBoth
|
* @apiName UserReleaseBoth
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -994,8 +996,8 @@ api.userReleaseBoth = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/release-mounts Released mounts.
|
* @api {post} /api/v3/user/release-mounts Release mounts
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReleaseMounts
|
* @apiName UserReleaseMounts
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1015,13 +1017,13 @@ api.userReleaseMounts = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/sell/:type/:key Sells a gold item owned by the user.
|
* @api {post} /api/v3/user/sell/:type/:key Sell a gold-sellable item owned by the user
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserSell
|
* @apiName UserSell
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiParam {string} type The type of item to sell. Acceptable types are eggs, hatchingPotions, food
|
* @apiParam {string} type The type of item to sell. Must be one of: eggs, hatchingPotions, or food
|
||||||
* @apiParam {string} key The key of the item
|
* @apiParam {string} key The key of the item
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data.stats
|
* @apiSuccess {Object} data.stats
|
||||||
@@ -1040,8 +1042,8 @@ api.userSell = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/unlock Unlocks items by purchase.
|
* @api {post} /api/v3/user/unlock Unlock item or set of items by purchase
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserUnlock
|
* @apiName UserUnlock
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1049,9 +1051,9 @@ api.userSell = {
|
|||||||
* @apiParam {string} path Query parameter. The path to unlock
|
* @apiParam {string} path Query parameter. The path to unlock
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data.purchased
|
* @apiSuccess {Object} data.purchased
|
||||||
* @apiSuccess {Object} data.items`
|
* @apiSuccess {Object} data.items
|
||||||
* @apiSuccess {Object} data.preferences`
|
* @apiSuccess {Object} data.preferences
|
||||||
* @apiSuccess {string} message`
|
* @apiSuccess {string} message
|
||||||
*/
|
*/
|
||||||
api.userUnlock = {
|
api.userUnlock = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -1066,7 +1068,7 @@ api.userUnlock = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/revive Revives user from death.
|
* @api {post} /api/v3/user/revive Revive user from death
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserRevive
|
* @apiName UserRevive
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1086,13 +1088,13 @@ api.userRevive = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/rebirth Resets a user.
|
* @api {post} /api/v3/user/rebirth Use Orb of Rebirth on user
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserRebirth
|
* @apiName UserRebirth
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data.userr
|
* @apiSuccess {Object} data.user
|
||||||
* @apiSuccess {array} data.tasks User's modified tasks (no rewards)
|
* @apiSuccess {array} data.tasks User's modified tasks (no rewards)
|
||||||
* @apiSuccess {string} message Success message
|
* @apiSuccess {string} message Success message
|
||||||
*/
|
*/
|
||||||
@@ -1102,23 +1104,30 @@ api.userRebirth = {
|
|||||||
url: '/user/rebirth',
|
url: '/user/rebirth',
|
||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
let user = res.locals.user;
|
let user = res.locals.user;
|
||||||
let query = {
|
let tasks = await Tasks.Task.find({
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
type: {$in: ['daily', 'habit', 'todo']},
|
type: {$in: ['daily', 'habit', 'todo']},
|
||||||
};
|
$or: [ // exclude challenge tasks
|
||||||
let tasks = await Tasks.Task.find(query).exec();
|
{'challenge.id': {$exists: false}},
|
||||||
|
{'challenge.broken': {$exists: true}},
|
||||||
|
],
|
||||||
|
}).exec();
|
||||||
|
|
||||||
let rebirthRes = common.ops.rebirth(user, tasks, req, res.analytics);
|
let rebirthRes = common.ops.rebirth(user, tasks, req, res.analytics);
|
||||||
|
|
||||||
await user.save();
|
let toSave = tasks.map(task => task.save());
|
||||||
|
|
||||||
await Bluebird.all(tasks.map(task => task.save()));
|
toSave.push(user.save());
|
||||||
|
|
||||||
|
await Bluebird.all(toSave);
|
||||||
|
|
||||||
res.respond(200, ...rebirthRes);
|
res.respond(200, ...rebirthRes);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {post} /api/v3/user/block/:uuid Blocks and unblocks a user
|
* @api {post} /api/v3/user/block/:uuid Block and unblock a user
|
||||||
|
* @apiDescription Must be an admin to make this request.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName BlockUser
|
* @apiName BlockUser
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1201,8 +1210,8 @@ api.markPmsRead = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/reroll Rerolls a user.
|
* @api {post} /api/v3/user/reroll Reroll a user using the Fortify Potion
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReroll
|
* @apiName UserReroll
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1220,6 +1229,10 @@ api.userReroll = {
|
|||||||
let query = {
|
let query = {
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
type: {$in: ['daily', 'habit', 'todo']},
|
type: {$in: ['daily', 'habit', 'todo']},
|
||||||
|
$or: [ // exclude challenge tasks
|
||||||
|
{'challenge.id': {$exists: false}},
|
||||||
|
{'challenge.broken': {$exists: true}},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
let tasks = await Tasks.Task.find(query).exec();
|
let tasks = await Tasks.Task.find(query).exec();
|
||||||
let rerollRes = common.ops.reroll(user, tasks, req, res.analytics);
|
let rerollRes = common.ops.reroll(user, tasks, req, res.analytics);
|
||||||
@@ -1233,8 +1246,8 @@ api.userReroll = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/addPushDevice Adds a push device to a user.
|
* @api {post} /api/v3/user/addPushDevice Add a push device to a user
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserAddPushDevice
|
* @apiName UserAddPushDevice
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1259,8 +1272,8 @@ api.userAddPushDevice = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @api {post} /api/v3/user/reset Resets a user.
|
* @api {post} /api/v3/user/reset Reset user
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName UserReset
|
* @apiName UserReset
|
||||||
* @apiGroup User
|
* @apiGroup User
|
||||||
@@ -1276,11 +1289,20 @@ api.userReset = {
|
|||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
let user = res.locals.user;
|
let user = res.locals.user;
|
||||||
|
|
||||||
let tasks = await Tasks.Task.find({userId: user._id}).select('_id type challenge').exec();
|
let tasks = await Tasks.Task.find({
|
||||||
|
userId: user._id,
|
||||||
|
$or: [ // exclude challenge tasks
|
||||||
|
{'challenge.id': {$exists: false}},
|
||||||
|
{'challenge.broken': {$exists: true}},
|
||||||
|
],
|
||||||
|
}).select('_id type challenge').exec();
|
||||||
|
|
||||||
let resetRes = common.ops.reset(user, tasks);
|
let resetRes = common.ops.reset(user, tasks, req);
|
||||||
|
|
||||||
await Bluebird.all([Tasks.Task.remove({_id: {$in: resetRes[0].tasksToRemove}, userId: user._id}), user.save()]);
|
await Bluebird.all([
|
||||||
|
Tasks.Task.remove({_id: {$in: resetRes[0].tasksToRemove}, userId: user._id}),
|
||||||
|
user.save(),
|
||||||
|
]);
|
||||||
|
|
||||||
res.respond(200, ...resetRes);
|
res.respond(200, ...resetRes);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ const BASE_URL = nconf.get('BASE_URL');
|
|||||||
let api = {};
|
let api = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /export/history.csv Export user tasks history in CSV format.
|
* @api {get} /export/history.csv Export user tasks history in CSV format
|
||||||
* @apiDescription History is only available for habits and dailys so todos and rewards won't be included NOTE: Part of the private API that may change at any time.
|
* @apiDescription History is only available for habits and dailys so todos and rewards won't be included. NOTE: Part of the private API that may change at any time.
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName ExportUserHistory
|
* @apiName ExportUserHistory
|
||||||
* @apiGroup DataExport
|
* @apiGroup DataExport
|
||||||
@@ -94,7 +94,7 @@ async function _getUserDataForExport (user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /export/userdata.json Export user data in JSON format.
|
* @api {get} /export/userdata.json Export user data in JSON format
|
||||||
* @apiVersion 3.0.0
|
* @apiVersion 3.0.0
|
||||||
* @apiName ExportUserDataJson
|
* @apiName ExportUserDataJson
|
||||||
* @apiGroup DataExport
|
* @apiGroup DataExport
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export let TaskSchema = new Schema({
|
|||||||
}, discriminatorOptions));
|
}, discriminatorOptions));
|
||||||
|
|
||||||
TaskSchema.plugin(baseModel, {
|
TaskSchema.plugin(baseModel, {
|
||||||
noSet: ['challenge', 'userId', 'completed', 'history', 'streak', 'dateCompleted', 'completed'],
|
noSet: ['challenge', 'userId', 'completed', 'history', 'dateCompleted', 'completed'],
|
||||||
sanitizeTransform (taskObj) {
|
sanitizeTransform (taskObj) {
|
||||||
if (taskObj.type && taskObj.type !== 'reward') { // value should be settable directly only for rewards
|
if (taskObj.type && taskObj.type !== 'reward') { // value should be settable directly only for rewards
|
||||||
delete taskObj.value;
|
delete taskObj.value;
|
||||||
|
|||||||
Reference in New Issue
Block a user