mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
185 lines
4.3 KiB
JavaScript
185 lines
4.3 KiB
JavaScript
import i18n from '../../i18n';
|
|
import {
|
|
NotAuthorized,
|
|
NotImplementedError,
|
|
BadRequest,
|
|
} from '../../libs/errors';
|
|
import _merge from 'lodash/merge';
|
|
import _get from 'lodash/get';
|
|
|
|
export class AbstractBuyOperation {
|
|
/**
|
|
* @param {User} user - the User-Object
|
|
* @param {Request} req - the Request-Object
|
|
* @param {analytics} analytics
|
|
*/
|
|
constructor (user, req, analytics) {
|
|
this.user = user;
|
|
this.req = req || {};
|
|
this.analytics = analytics;
|
|
|
|
let quantity = _get(req, 'quantity');
|
|
|
|
this.quantity = quantity ? Number(quantity) : 1;
|
|
if (isNaN(this.quantity)) throw new BadRequest(this.i18n('invalidQuantity'));
|
|
}
|
|
|
|
/**
|
|
* Returns the item value
|
|
* @param item
|
|
* @returns {number}
|
|
*/
|
|
getItemValue (item) {
|
|
return item.value;
|
|
}
|
|
|
|
/**
|
|
* Returns the item key
|
|
* @param item
|
|
* @returns {String}
|
|
*/
|
|
getIemKey (item) {
|
|
return item.key;
|
|
}
|
|
|
|
/**
|
|
* Shortcut to get the translated string without passing `req.language`
|
|
* @param {String} key - translation key
|
|
* @param {*=} params
|
|
* @returns {*|string}
|
|
*/
|
|
// eslint-disable-next-line no-unused-vars
|
|
i18n (key, params = {}) {
|
|
return i18n.t.apply(null, [...arguments, this.req.language]);
|
|
}
|
|
|
|
/**
|
|
* If the Operation allows purchasing items by quantity
|
|
* @returns Boolean
|
|
*/
|
|
multiplePurchaseAllowed () {
|
|
throw new NotImplementedError('multiplePurchaseAllowed');
|
|
}
|
|
|
|
/**
|
|
* Method is called to save the params as class-fields in order to access them
|
|
*/
|
|
extractAndValidateParams () {
|
|
throw new NotImplementedError('extractAndValidateParams');
|
|
}
|
|
|
|
executeChanges () {
|
|
throw new NotImplementedError('executeChanges');
|
|
}
|
|
|
|
analyticsData () {
|
|
throw new NotImplementedError('sendToAnalytics');
|
|
}
|
|
|
|
purchase () {
|
|
if (!this.multiplePurchaseAllowed() && this.quantity > 1) {
|
|
throw new NotAuthorized(this.i18n('messageNotAbleToBuyInBulk'));
|
|
}
|
|
|
|
this.extractAndValidateParams(this.user, this.req);
|
|
|
|
let resultObj = this.executeChanges(this.user, this.item, this.req);
|
|
|
|
if (this.analytics) {
|
|
this.sendToAnalytics(this.analyticsData());
|
|
}
|
|
|
|
return resultObj;
|
|
}
|
|
|
|
analyticsLabel () {
|
|
return 'acquire item';
|
|
}
|
|
|
|
sendToAnalytics (additionalData = {}) {
|
|
// spread-operator produces an "unexpected token" error
|
|
let analyticsData = _merge(additionalData, {
|
|
// ...additionalData,
|
|
uuid: this.user._id,
|
|
category: 'behavior',
|
|
headers: this.req.headers,
|
|
});
|
|
|
|
if (this.multiplePurchaseAllowed()) {
|
|
analyticsData.quantityPurchased = this.quantity;
|
|
}
|
|
|
|
this.analytics.track(this.analyticsLabel(), analyticsData);
|
|
}
|
|
}
|
|
|
|
export class AbstractGoldItemOperation extends AbstractBuyOperation {
|
|
constructor (user, req, analytics) {
|
|
super(user, req, analytics);
|
|
}
|
|
|
|
canUserPurchase (user, item) {
|
|
this.item = item;
|
|
let itemValue = this.getItemValue(item);
|
|
|
|
let userGold = user.stats.gp;
|
|
|
|
if (userGold < itemValue * this.quantity) {
|
|
throw new NotAuthorized(this.i18n('messageNotEnoughGold'));
|
|
}
|
|
|
|
if (item && item.canOwn && !item.canOwn(user)) {
|
|
throw new NotAuthorized(this.i18n('cannotBuyItem'));
|
|
}
|
|
}
|
|
|
|
subtractCurrency (user, item) {
|
|
let itemValue = this.getItemValue(item);
|
|
|
|
user.stats.gp -= itemValue * this.quantity;
|
|
}
|
|
|
|
analyticsData () {
|
|
return {
|
|
itemKey: this.getIemKey(this.item),
|
|
itemType: 'Market',
|
|
acquireMethod: 'Gold',
|
|
goldCost: this.getItemValue(this.item),
|
|
};
|
|
}
|
|
}
|
|
|
|
export class AbstractGemItemOperation extends AbstractBuyOperation {
|
|
constructor (user, req, analytics) {
|
|
super(user, req, analytics);
|
|
}
|
|
|
|
canUserPurchase (user, item) {
|
|
this.item = item;
|
|
let itemValue = this.getItemValue(item);
|
|
|
|
if (!item.canBuy(user)) {
|
|
throw new NotAuthorized(this.i18n('messageNotAvailable'));
|
|
}
|
|
|
|
if (!user.balance || user.balance < itemValue * this.quantity) {
|
|
throw new NotAuthorized(this.i18n('notEnoughGems'));
|
|
}
|
|
}
|
|
|
|
subtractCurrency (user, item) {
|
|
let itemValue = this.getItemValue(item);
|
|
|
|
user.balance -= itemValue * this.quantity;
|
|
}
|
|
|
|
analyticsData () {
|
|
return {
|
|
itemKey: this.getIemKey(this.item),
|
|
itemType: 'Market',
|
|
acquireMethod: 'Gems',
|
|
gemCost: this.getItemValue(this.item) * 4,
|
|
};
|
|
}
|
|
}
|