Merge remote-tracking branch 'upstream/develop' into quest-refactors
This commit is contained in:
@@ -7,6 +7,8 @@ import {
|
||||
NotImplementedError,
|
||||
BadRequest,
|
||||
} from '../../libs/errors';
|
||||
import updateUserBalance from '../updateUserBalance';
|
||||
import updateUserHourglasses from '../updateUserHourglasses';
|
||||
|
||||
export class AbstractBuyOperation {
|
||||
/**
|
||||
@@ -89,7 +91,7 @@ export class AbstractBuyOperation {
|
||||
throw new NotImplementedError('extractAndValidateParams');
|
||||
}
|
||||
|
||||
executeChanges () { // eslint-disable-line class-methods-use-this
|
||||
async executeChanges () { // eslint-disable-line class-methods-use-this
|
||||
throw new NotImplementedError('executeChanges');
|
||||
}
|
||||
|
||||
@@ -97,14 +99,14 @@ export class AbstractBuyOperation {
|
||||
throw new NotImplementedError('sendToAnalytics');
|
||||
}
|
||||
|
||||
purchase () {
|
||||
async purchase () {
|
||||
if (!this.multiplePurchaseAllowed() && this.quantity > 1) {
|
||||
throw new NotAuthorized(this.i18n('messageNotAbleToBuyInBulk'));
|
||||
}
|
||||
|
||||
this.extractAndValidateParams(this.user, this.req);
|
||||
|
||||
const resultObj = this.executeChanges(this.user, this.item, this.req, this.analytics);
|
||||
const resultObj = await this.executeChanges(this.user, this.item, this.req, this.analytics);
|
||||
|
||||
if (this.analytics) {
|
||||
this.sendToAnalytics(this.analyticsData());
|
||||
@@ -154,7 +156,7 @@ export class AbstractGoldItemOperation extends AbstractBuyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
subtractCurrency (user, item) {
|
||||
async subtractCurrency (user, item) {
|
||||
const itemValue = this.getItemValue(item);
|
||||
|
||||
user.stats.gp -= itemValue * this.quantity;
|
||||
@@ -188,10 +190,10 @@ export class AbstractGemItemOperation extends AbstractBuyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
subtractCurrency (user, item) {
|
||||
async subtractCurrency (user, item) {
|
||||
const itemValue = this.getItemValue(item);
|
||||
|
||||
user.balance -= itemValue * this.quantity;
|
||||
await updateUserBalance(user, -(itemValue * this.quantity), 'spend', item.key, item.text());
|
||||
}
|
||||
|
||||
analyticsData () {
|
||||
@@ -213,8 +215,8 @@ export class AbstractHourglassItemOperation extends AbstractBuyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
subtractCurrency (user) { // eslint-disable-line class-methods-use-this
|
||||
user.purchased.plan.consecutive.trinkets -= 1;
|
||||
async subtractCurrency (user, item) { // eslint-disable-line class-methods-use-this
|
||||
await updateUserHourglasses(user, -1, 'spend', item.key);
|
||||
}
|
||||
|
||||
analyticsData () {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { BuyHourglassMountOperation } from './buyMount';
|
||||
|
||||
// @TODO: when we are sure buy is the only function used, let's move the buy files to a folder
|
||||
|
||||
export default function buy (
|
||||
export default async function buy (
|
||||
user, req = {}, analytics, options = { quantity: 1, hourglass: false },
|
||||
) {
|
||||
const key = get(req, 'params.key');
|
||||
@@ -40,35 +40,35 @@ export default function buy (
|
||||
case 'armoire': {
|
||||
const buyOp = new BuyArmoireOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
case 'backgrounds':
|
||||
if (!hourglass) throw new BadRequest(errorMessage('useUnlockForCosmetics'));
|
||||
buyRes = hourglassPurchase(user, req, analytics);
|
||||
buyRes = await hourglassPurchase(user, req, analytics);
|
||||
break;
|
||||
case 'mystery':
|
||||
buyRes = buyMysterySet(user, req, analytics);
|
||||
buyRes = await buyMysterySet(user, req, analytics);
|
||||
break;
|
||||
case 'potion': {
|
||||
const buyOp = new BuyHealthPotionOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
case 'gems': {
|
||||
const buyOp = new BuyGemOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
case 'quests': {
|
||||
if (hourglass) {
|
||||
buyRes = hourglassPurchase(user, req, analytics, quantity);
|
||||
buyRes = await hourglassPurchase(user, req, analytics, quantity);
|
||||
} else {
|
||||
const buyOp = new BuyQuestWithGemOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -77,12 +77,12 @@ export default function buy (
|
||||
case 'food':
|
||||
case 'gear':
|
||||
case 'bundles':
|
||||
buyRes = purchaseOp(user, req, analytics);
|
||||
buyRes = await purchaseOp(user, req, analytics);
|
||||
break;
|
||||
case 'mounts': {
|
||||
const buyOp = new BuyHourglassMountOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
case 'pets':
|
||||
@@ -91,19 +91,19 @@ export default function buy (
|
||||
case 'quest': {
|
||||
const buyOp = new BuyQuestWithGoldOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
case 'special': {
|
||||
const buyOp = new BuySpellOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const buyOp = new BuyMarketGearOperation(user, req, analytics);
|
||||
|
||||
buyRes = buyOp.purchase();
|
||||
buyRes = await buyOp.purchase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '../../libs/errors';
|
||||
import { AbstractGoldItemOperation } from './abstractBuyOperation';
|
||||
import planGemLimits from '../../libs/planGemLimits';
|
||||
import updateUserBalance from '../updateUserBalance';
|
||||
|
||||
export class BuyGemOperation extends AbstractGoldItemOperation { // eslint-disable-line import/prefer-default-export, max-len
|
||||
multiplePurchaseAllowed () { // eslint-disable-line class-methods-use-this
|
||||
@@ -59,7 +60,7 @@ export class BuyGemOperation extends AbstractGoldItemOperation { // eslint-disab
|
||||
}
|
||||
|
||||
executeChanges (user, item) {
|
||||
user.balance += 0.25 * this.quantity;
|
||||
updateUserBalance(user, 0.25 * this.quantity, 'buy_gold');
|
||||
user.purchased.plan.gemsBought += this.quantity;
|
||||
|
||||
this.subtractCurrency(user, item);
|
||||
|
||||
@@ -32,7 +32,7 @@ export class BuyHourglassMountOperation extends AbstractHourglassItemOperation {
|
||||
});
|
||||
}
|
||||
|
||||
executeChanges (user) {
|
||||
async executeChanges (user, item) {
|
||||
user.items.mounts = {
|
||||
...user.items.mounts,
|
||||
[this.key]: true,
|
||||
@@ -40,7 +40,7 @@ export class BuyHourglassMountOperation extends AbstractHourglassItemOperation {
|
||||
|
||||
if (user.markModified) user.markModified('items.mounts');
|
||||
|
||||
this.subtractCurrency(user);
|
||||
await this.subtractCurrency(user, item);
|
||||
|
||||
const message = this.i18n('hourglassPurchase');
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ import {
|
||||
NotFound,
|
||||
} from '../../libs/errors';
|
||||
import errorMessage from '../../libs/errorMessage';
|
||||
import updateUserHourglasses from '../updateUserHourglasses';
|
||||
import { removeItemByPath } from '../pinnedGearUtils';
|
||||
import getItemInfo from '../../libs/getItemInfo';
|
||||
|
||||
export default function buyMysterySet (user, req = {}, analytics) {
|
||||
export default async function buyMysterySet (user, req = {}, analytics) {
|
||||
const key = get(req, 'params.key');
|
||||
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
|
||||
|
||||
@@ -51,7 +52,7 @@ export default function buyMysterySet (user, req = {}, analytics) {
|
||||
|
||||
if (user.markModified) user.markModified('items.gear.owned');
|
||||
|
||||
user.purchased.plan.consecutive.trinkets -= 1;
|
||||
await updateUserHourglasses(user, -1, 'spend', mysterySet.text());
|
||||
|
||||
return [
|
||||
{ items: user.items, purchasedPlanConsecutive: user.purchased.plan.consecutive },
|
||||
|
||||
@@ -52,7 +52,7 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation { // esli
|
||||
this.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
executeChanges (user, item, req) {
|
||||
async executeChanges (user, item, req) {
|
||||
if (
|
||||
!user.items.quests[item.key]
|
||||
|| user.items.quests[item.key] < 0
|
||||
@@ -63,7 +63,7 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation { // esli
|
||||
};
|
||||
if (user.markModified) user.markModified('items.quests');
|
||||
|
||||
this.subtractCurrency(user, item, this.quantity);
|
||||
await this.subtractCurrency(user, item, this.quantity);
|
||||
|
||||
return [
|
||||
user.items.quests,
|
||||
|
||||
@@ -10,8 +10,9 @@ import {
|
||||
import errorMessage from '../../libs/errorMessage';
|
||||
import getItemInfo from '../../libs/getItemInfo';
|
||||
import { removeItemByPath } from '../pinnedGearUtils';
|
||||
import updateUserHourglasses from '../updateUserHourglasses';
|
||||
|
||||
export default function purchaseHourglass (user, req = {}, analytics, quantity = 1) {
|
||||
export default async function purchaseHourglass (user, req = {}, analytics, quantity = 1) {
|
||||
const key = get(req, 'params.key');
|
||||
if (!key) throw new BadRequest(errorMessage('missingKeyParam'));
|
||||
|
||||
@@ -30,7 +31,7 @@ export default function purchaseHourglass (user, req = {}, analytics, quantity =
|
||||
}
|
||||
|
||||
user.purchased.background[key] = true;
|
||||
user.purchased.plan.consecutive.trinkets -= 1;
|
||||
await updateUserHourglasses(user, -1, 'spend', key);
|
||||
const itemInfo = getItemInfo(user, 'background', content.backgroundsFlat[key]);
|
||||
removeItemByPath(user, itemInfo.path);
|
||||
|
||||
@@ -43,7 +44,7 @@ export default function purchaseHourglass (user, req = {}, analytics, quantity =
|
||||
|
||||
if (!user.items.quests[key] || user.items.quests[key] < 0) user.items.quests[key] = 0;
|
||||
user.items.quests[key] += quantity;
|
||||
user.purchased.plan.consecutive.trinkets -= quantity;
|
||||
await updateUserHourglasses(user, -quantity, 'spend', key);
|
||||
|
||||
if (user.markModified) user.markModified('items.quests');
|
||||
} else {
|
||||
@@ -63,7 +64,7 @@ export default function purchaseHourglass (user, req = {}, analytics, quantity =
|
||||
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
|
||||
}
|
||||
|
||||
user.purchased.plan.consecutive.trinkets -= 1;
|
||||
await updateUserHourglasses(user, -1, 'spend', key);
|
||||
|
||||
if (type === 'pets') {
|
||||
user.items.pets = {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
import { removeItemByPath } from '../pinnedGearUtils';
|
||||
import getItemInfo from '../../libs/getItemInfo';
|
||||
import updateUserBalance from '../updateUserBalance';
|
||||
|
||||
function getItemAndPrice (user, type, key, req) {
|
||||
let item;
|
||||
@@ -42,8 +43,8 @@ function getItemAndPrice (user, type, key, req) {
|
||||
return { item, price };
|
||||
}
|
||||
|
||||
function purchaseItem (user, item, price, type, key) {
|
||||
user.balance -= price;
|
||||
async function purchaseItem (user, item, price, type, key) {
|
||||
await updateUserBalance(user, -price, 'spend', item.key, `${item.text()} ${type}`);
|
||||
|
||||
if (type === 'gear') {
|
||||
user.items.gear.owned = {
|
||||
@@ -74,7 +75,7 @@ function purchaseItem (user, item, price, type, key) {
|
||||
|
||||
const acceptedTypes = ['eggs', 'hatchingPotions', 'food', 'gear', 'bundles'];
|
||||
const singlePurchaseTypes = ['gear'];
|
||||
export default function purchase (user, req = {}, analytics) {
|
||||
export default async function purchase (user, req = {}, analytics) {
|
||||
const type = get(req.params, 'type');
|
||||
const key = get(req.params, 'key');
|
||||
|
||||
@@ -108,10 +109,11 @@ export default function purchase (user, req = {}, analytics) {
|
||||
removeItemByPath(user, itemInfo.path);
|
||||
}
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let i = 0; i < quantity; i += 1) {
|
||||
purchaseItem(user, item, price, type, key);
|
||||
await purchaseItem(user, item, price, type, key);
|
||||
}
|
||||
|
||||
/* eslint-enable no-await-in-loop */
|
||||
if (analytics) {
|
||||
analytics.track('buy', {
|
||||
uuid: user._id,
|
||||
|
||||
@@ -8,8 +8,9 @@ import {
|
||||
BadRequest,
|
||||
} from '../libs/errors';
|
||||
import { removePinnedGearByClass, removePinnedItemsByOwnedGear, addPinnedGearByClass } from './pinnedGearUtils';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
function resetClass (user, req = {}) {
|
||||
async function resetClass (user, req = {}) {
|
||||
removePinnedGearByClass(user);
|
||||
|
||||
let balanceRemoved = 0;
|
||||
@@ -19,7 +20,7 @@ function resetClass (user, req = {}) {
|
||||
user.preferences.autoAllocate = false;
|
||||
} else {
|
||||
if (user.balance < 0.75) throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
|
||||
user.balance -= 0.75;
|
||||
await updateUserBalance(user, -0.75, 'change_class');
|
||||
balanceRemoved = 0.75;
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ function resetClass (user, req = {}) {
|
||||
return balanceRemoved;
|
||||
}
|
||||
|
||||
export default function changeClass (user, req = {}, analytics) {
|
||||
export default async function changeClass (user, req = {}, analytics) {
|
||||
const klass = get(req, 'query.class');
|
||||
let balanceRemoved = 0;
|
||||
// user.flags.classSelected is set to false after the user paid the 3 gems
|
||||
@@ -42,10 +43,10 @@ export default function changeClass (user, req = {}, analytics) {
|
||||
} else if (!klass) {
|
||||
// if no class is specified, reset points and set user.flags.classSelected to false.
|
||||
// User will have paid 3 gems and will be prompted to select class.
|
||||
balanceRemoved = resetClass(user, req);
|
||||
balanceRemoved = await resetClass(user, req);
|
||||
} else if (klass === 'warrior' || klass === 'rogue' || klass === 'wizard' || klass === 'healer') {
|
||||
if (user.flags.classSelected) {
|
||||
balanceRemoved = resetClass(user, req);
|
||||
balanceRemoved = await resetClass(user, req);
|
||||
}
|
||||
|
||||
user.stats.class = klass;
|
||||
|
||||
@@ -9,10 +9,11 @@ import equip from './equip';
|
||||
import { removePinnedGearByClass } from './pinnedGearUtils';
|
||||
import isFreeRebirth from '../libs/isFreeRebirth';
|
||||
import setDebuffPotionItems from '../libs/setDebuffPotionItems';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
const USERSTATSLIST = ['per', 'int', 'con', 'str', 'points', 'gp', 'exp', 'mp'];
|
||||
|
||||
export default function rebirth (user, tasks = [], req = {}, analytics) {
|
||||
export default async function rebirth (user, tasks = [], req = {}, analytics) {
|
||||
const notFree = !isFreeRebirth(user);
|
||||
|
||||
if (user.balance < 1.5 && notFree) {
|
||||
@@ -25,7 +26,7 @@ export default function rebirth (user, tasks = [], req = {}, analytics) {
|
||||
};
|
||||
|
||||
if (notFree) {
|
||||
user.balance -= 1.5;
|
||||
await updateUserBalance(user, -1.5, 'rebirth');
|
||||
analyticsData.currency = 'Gems';
|
||||
analyticsData.gemCost = 6;
|
||||
} else {
|
||||
@@ -42,7 +43,7 @@ export default function rebirth (user, tasks = [], req = {}, analytics) {
|
||||
|
||||
each(tasks, task => {
|
||||
if (!task.challenge || !task.challenge.id || task.challenge.broken) {
|
||||
if (task.type !== 'reward') {
|
||||
if (task.type !== 'reward' && task.type !== 'todo') {
|
||||
task.value = 0;
|
||||
}
|
||||
if (task.type === 'daily') {
|
||||
@@ -52,6 +53,9 @@ export default function rebirth (user, tasks = [], req = {}, analytics) {
|
||||
task.counterDown = 0;
|
||||
task.counterUp = 0;
|
||||
}
|
||||
if (task.type === 'todo' && task.completed !== true) {
|
||||
task.value = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ import i18n from '../i18n';
|
||||
import {
|
||||
NotAuthorized,
|
||||
} from '../libs/errors';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
export default function releaseMounts (user, req = {}, analytics) {
|
||||
export default async function releaseMounts (user, req = {}, analytics) {
|
||||
if (user.balance < 1) {
|
||||
throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
|
||||
}
|
||||
@@ -14,7 +15,7 @@ export default function releaseMounts (user, req = {}, analytics) {
|
||||
throw new NotAuthorized(i18n.t('notEnoughMounts', req.language));
|
||||
}
|
||||
|
||||
user.balance -= 1;
|
||||
await updateUserBalance(user, -1, 'release_mounts');
|
||||
|
||||
let giveMountMasterAchievement = true;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import i18n from '../i18n';
|
||||
import {
|
||||
NotAuthorized,
|
||||
} from '../libs/errors';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
export default function releasePets (user, req = {}, analytics) {
|
||||
if (user.balance < 1) {
|
||||
@@ -14,7 +15,7 @@ export default function releasePets (user, req = {}, analytics) {
|
||||
throw new NotAuthorized(i18n.t('notEnoughPets', req.language));
|
||||
}
|
||||
|
||||
user.balance -= 1;
|
||||
updateUserBalance(user, -1, 'release_pets');
|
||||
|
||||
let giveBeastMasterAchievement = true;
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ import i18n from '../i18n';
|
||||
import {
|
||||
NotAuthorized,
|
||||
} from '../libs/errors';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
export default function reroll (user, tasks = [], req = {}, analytics) {
|
||||
export default async function reroll (user, tasks = [], req = {}, analytics) {
|
||||
if (user.balance < 1) {
|
||||
throw new NotAuthorized(i18n.t('notEnoughGems', req.language));
|
||||
}
|
||||
|
||||
user.balance -= 1;
|
||||
await updateUserBalance(user, -1, 'reroll');
|
||||
user.stats.hp = 50;
|
||||
|
||||
each(tasks, task => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { NotAuthorized, BadRequest } from '../libs/errors';
|
||||
import { removeItemByPath } from './pinnedGearUtils';
|
||||
import getItemInfo from '../libs/getItemInfo';
|
||||
import content from '../content/index';
|
||||
import updateUserBalance from './updateUserBalance';
|
||||
|
||||
const incentiveBackgrounds = ['blue', 'green', 'red', 'purple', 'yellow'];
|
||||
|
||||
@@ -204,7 +205,7 @@ function buildResponse ({ purchased, preference, items }, ownsAlready, language)
|
||||
// If item is already purchased -> equip it
|
||||
// Otherwise unlock it
|
||||
// @TODO refactor and take as parameter the set name, for single items use the buy ops
|
||||
export default function unlock (user, req = {}, analytics) {
|
||||
export default async function unlock (user, req = {}, analytics) {
|
||||
const path = get(req.query, 'path');
|
||||
|
||||
if (!path) {
|
||||
@@ -302,7 +303,7 @@ export default function unlock (user, req = {}, analytics) {
|
||||
}
|
||||
|
||||
if (!unlockedAlready) {
|
||||
user.balance -= cost;
|
||||
await updateUserBalance(user, -cost, 'spend', path);
|
||||
|
||||
if (analytics) {
|
||||
analytics.track('buy', {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export default async function updateUserBalance (user,
|
||||
amount,
|
||||
transactionType,
|
||||
reference,
|
||||
referenceText) {
|
||||
if (user.constructor.name === 'model') {
|
||||
await user.updateBalance(amount, transactionType, reference, referenceText);
|
||||
} else {
|
||||
user.balance += amount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export default async function updateUserHourglasses (user,
|
||||
amount,
|
||||
transactionType,
|
||||
reference,
|
||||
referenceText) {
|
||||
if (user.constructor.name === 'model') {
|
||||
await user.purchased.plan.updateHourglasses(user._id,
|
||||
amount,
|
||||
transactionType,
|
||||
reference,
|
||||
referenceText);
|
||||
} else {
|
||||
user.purchased.plan.consecutive.trinkets += amount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user