diff --git a/test/common/ops/buy/buyQuest.js b/test/common/ops/buy/buyQuest.js index b75b86e93f..390b65ee01 100644 --- a/test/common/ops/buy/buyQuest.js +++ b/test/common/ops/buy/buyQuest.js @@ -1,7 +1,7 @@ import { generateUser, } from '../../../helpers/common.helper'; -import buyQuest from '../../../../website/common/script/ops/buy/buyQuest'; +import {BuyQuestWithGoldOperation} from '../../../../website/common/script/ops/buy/buyQuest'; import { BadRequest, NotAuthorized, @@ -13,6 +13,12 @@ describe('shared.ops.buyQuest', () => { let user; let analytics = {track () {}}; + function buyQuest (_user, _req, _analytics) { + const buyOp = new BuyQuestWithGoldOperation(_user, _req, _analytics); + + return buyOp.purchase(); + } + beforeEach(() => { user = generateUser(); sinon.stub(analytics, 'track'); diff --git a/website/common/script/ops/buy/abstractBuyOperation.js b/website/common/script/ops/buy/abstractBuyOperation.js index 444ab7ffb8..f325fa7e5b 100644 --- a/website/common/script/ops/buy/abstractBuyOperation.js +++ b/website/common/script/ops/buy/abstractBuyOperation.js @@ -1,6 +1,8 @@ import i18n from '../../i18n'; import { - NotAuthorized, NotImplementedError, + NotAuthorized, + NotImplementedError, + BadRequest, } from '../../libs/errors'; import _merge from 'lodash/merge'; import _get from 'lodash/get'; @@ -16,7 +18,14 @@ export class AbstractBuyOperation { this.req = req || {}; this.analytics = analytics; - this.quantity = _get(req, 'quantity', 1); + this.quantity = 1; + + if (this.multiplePurchaseAllowed()) { + let quantity = _get(req, 'quantity'); + + this.quantity = quantity ? Number(quantity) : 1; + if (isNaN(this.quantity)) throw new BadRequest(this.i18n('invalidQuantity')); + } } /** diff --git a/website/common/script/ops/buy/buy.js b/website/common/script/ops/buy/buy.js index ed7267142b..b8f56aab7b 100644 --- a/website/common/script/ops/buy/buy.js +++ b/website/common/script/ops/buy/buy.js @@ -7,7 +7,7 @@ import {BuyArmoireOperation} from './buyArmoire'; import {BuyHealthPotionOperation} from './buyHealthPotion'; import {BuyMarketGearOperation} from './buyMarketGear'; import buyMysterySet from './buyMysterySet'; -import buyQuest from './buyQuest'; +import {BuyQuestWithGoldOperation} from './buyQuest'; import buySpecialSpell from './buySpecialSpell'; import purchaseOp from './purchase'; import hourglassPurchase from './hourglassPurchase'; @@ -58,9 +58,12 @@ module.exports = function buy (user, req = {}, analytics) { case 'mounts': buyRes = hourglassPurchase(user, req, analytics); break; - case 'quest': - buyRes = buyQuest(user, req, analytics); + case 'quest': { + const buyOp = new BuyQuestWithGoldOperation(user, req, analytics); + + buyRes = buyOp.purchase(); break; + } case 'special': buyRes = buySpecialSpell(user, req, analytics); break; diff --git a/website/common/script/ops/buy/buyQuest.js b/website/common/script/ops/buy/buyQuest.js index 59fd0dcd53..e30513347b 100644 --- a/website/common/script/ops/buy/buyQuest.js +++ b/website/common/script/ops/buy/buyQuest.js @@ -1,56 +1,72 @@ -import i18n from '../../i18n'; -import content from '../../content/index'; import { BadRequest, NotAuthorized, NotFound, } from '../../libs/errors'; +import content from '../../content/index'; import get from 'lodash/get'; -// buy a quest with gold -module.exports = function buyQuest (user, req = {}, analytics) { - let key = get(req, 'params.key'); +import {AbstractGoldItemOperation} from './abstractBuyOperation'; - let quantity = req.quantity ? Number(req.quantity) : 1; - if (isNaN(quantity)) throw new BadRequest(i18n.t('invalidQuantity', req.language)); - - if (!key) throw new BadRequest(i18n.t('missingKeyParam', req.language)); - - let item = content.quests[key]; - if (!item) throw new NotFound(i18n.t('questNotFound', {key}, req.language)); - - if (key === 'lostMasterclasser1' && !(user.achievements.quests.dilatoryDistress3 && user.achievements.quests.mayhemMistiflying3 && user.achievements.quests.stoikalmCalamity3 && user.achievements.quests.taskwoodsTerror3)) { - throw new NotAuthorized(i18n.t('questUnlockLostMasterclasser', req.language)); +export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation { + constructor (user, req, analytics) { + super(user, req, analytics); } - if (!(item.category === 'gold' && item.goldValue)) { - throw new NotAuthorized(i18n.t('questNotGoldPurchasable', {key}, req.language)); - } - if (user.stats.gp < item.goldValue * quantity) { - throw new NotAuthorized(i18n.t('messageNotEnoughGold', req.language)); + multiplePurchaseAllowed () { + return true; } - user.items.quests[item.key] = user.items.quests[item.key] || 0; - user.items.quests[item.key] += quantity; - user.stats.gp -= item.goldValue * quantity; + userAbleToStartMasterClasser (user) { + return user.achievements.quests.dilatoryDistress3 && + user.achievements.quests.mayhemMistiflying3 && + user.achievements.quests.stoikalmCalamity3 && + user.achievements.quests.taskwoodsTerror3; + } - if (analytics) { - analytics.track('acquire item', { - uuid: user._id, - itemKey: item.key, + getItemValue (item) { + return item.goldValue; + } + + extractAndValidateParams (user, req) { + let key = this.key = get(req, 'params.key'); + if (!key) throw new BadRequest(this.i18n('missingKeyParam')); + + if (key === 'lostMasterclasser1' && !this.userAbleToStartMasterClasser(user)) { + throw new NotAuthorized(this.i18n('questUnlockLostMasterclasser')); + } + + let item = content.quests[key]; + + if (!item) throw new NotFound(this.i18n('questNotFound', {key})); + + if (!(item.category === 'gold' && item.goldValue)) { + throw new NotAuthorized(this.i18n('questNotGoldPurchasable', {key})); + } + + this.canUserPurchase(user, item); + } + + executeChanges (user, item, req) { + user.items.quests[item.key] = user.items.quests[item.key] || 0; + user.items.quests[item.key] += this.quantity; + + this.subtractCurrency(user, item, this.quantity); + + return [ + user.items.quests, + this.i18n('messageBought', { + itemText: item.text(req.language), + }), + ]; + } + + analyticsData () { + return { + itemKey: this.key, itemType: 'Market', - goldCost: item.goldValue, - quantityPurchased: quantity, acquireMethod: 'Gold', - category: 'behavior', - headers: req.headers, - }); + goldCost: this.getItemValue(this.item.goldValue), + }; } - - return [ - user.items.quests, - i18n.t('messageBought', { - itemText: item.text(req.language), - }, req.language), - ]; -}; +}