mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 05:37:22 +01:00
Groups can prevent members from getting gems (#8870)
* add possibility for group to block members from getting gems * fixes * fix tests * adds some tests * unit tests * finish unit tests * remove old code
This commit is contained in:
committed by
Sabe Jones
parent
fe9521a63f
commit
78ba596504
@@ -114,6 +114,26 @@ describe('POST /challenges/:challengeId/winner/:winnerId', () => {
|
||||
await expect(winningUser.sync()).to.eventually.have.property('balance', oldBalance + challenge.prize / 4);
|
||||
});
|
||||
|
||||
it('doesn\'t gives winner gems if group policy prevents it', async () => {
|
||||
let oldBalance = winningUser.balance;
|
||||
let oldLeaderBalance = (await groupLeader.sync()).balance;
|
||||
|
||||
await winningUser.update({
|
||||
'purchased.plan.customerId': 'group-plan',
|
||||
});
|
||||
await group.update({
|
||||
'leaderOnly.getGems': true,
|
||||
'purchased.plan.customerId': 123,
|
||||
});
|
||||
|
||||
await groupLeader.post(`/challenges/${challenge._id}/selectWinner/${winningUser._id}`);
|
||||
|
||||
await sleep(0.5);
|
||||
|
||||
await expect(winningUser.sync()).to.eventually.have.property('balance', oldBalance);
|
||||
await expect(groupLeader.sync()).to.eventually.have.property('balance', oldLeaderBalance + challenge.prize / 4);
|
||||
});
|
||||
|
||||
it('doesn\'t refund gems to group leader', async () => {
|
||||
let oldBalance = (await groupLeader.sync()).balance;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
generateUser,
|
||||
createAndPopulateGroup,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
|
||||
@@ -31,4 +32,70 @@ describe('POST /user/purchase/:type/:key', () => {
|
||||
|
||||
expect(user.items[type][key]).to.equal(1);
|
||||
});
|
||||
|
||||
it('can convert gold to gems if subscribed', async () => {
|
||||
let oldBalance = user.balance;
|
||||
await user.update({
|
||||
'purchased.plan.customerId': 'group-plan',
|
||||
'stats.gp': 1000,
|
||||
});
|
||||
await user.post('/user/purchase/gems/gem');
|
||||
await user.sync();
|
||||
expect(user.balance).to.equal(oldBalance + 0.25);
|
||||
});
|
||||
|
||||
it('leader can convert gold to gems even if the group plan prevents it', async () => {
|
||||
let { group, groupLeader } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
});
|
||||
await group.update({
|
||||
'leaderOnly.getGems': true,
|
||||
'purchased.plan.customerId': 123,
|
||||
});
|
||||
await groupLeader.sync();
|
||||
let oldBalance = groupLeader.balance;
|
||||
|
||||
await groupLeader.update({
|
||||
'purchased.plan.customerId': 'group-plan',
|
||||
'stats.gp': 1000,
|
||||
});
|
||||
await groupLeader.post('/user/purchase/gems/gem');
|
||||
|
||||
await groupLeader.sync();
|
||||
expect(groupLeader.balance).to.equal(oldBalance + 0.25);
|
||||
});
|
||||
|
||||
it('cannot convert gold to gems if the group plan prevents it', async () => {
|
||||
let { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
await group.update({
|
||||
'leaderOnly.getGems': true,
|
||||
'purchased.plan.customerId': 123,
|
||||
});
|
||||
let oldBalance = members[0].balance;
|
||||
|
||||
await members[0].update({
|
||||
'purchased.plan.customerId': 'group-plan',
|
||||
'stats.gp': 1000,
|
||||
});
|
||||
await expect(members[0].post('/user/purchase/gems/gem'))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('groupPolicyCannotGetGems'),
|
||||
});
|
||||
|
||||
await members[0].sync();
|
||||
expect(members[0].balance).to.equal(oldBalance);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -102,6 +102,7 @@ describe('Amazon Payments', () => {
|
||||
});
|
||||
|
||||
it('should purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
await amzLib.checkout({user, orderReferenceId, headers});
|
||||
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
@@ -111,6 +112,8 @@ describe('Amazon Payments', () => {
|
||||
headers,
|
||||
});
|
||||
expectAmazonStubs();
|
||||
expect(user.canGetGems).to.be.calledOnce;
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('should error if gem amount is too low', async () => {
|
||||
@@ -132,20 +135,29 @@ describe('Amazon Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if user cannot get gems gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
await expect(amzLib.checkout({user, orderReferenceId, headers})).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('should gift gems', async () => {
|
||||
let receivingUser = new User();
|
||||
receivingUser.save();
|
||||
await receivingUser.save();
|
||||
let gift = {
|
||||
type: 'gems',
|
||||
uuid: receivingUser._id,
|
||||
gems: {
|
||||
amount: 16,
|
||||
uuid: receivingUser._id,
|
||||
},
|
||||
};
|
||||
amount = 16 / 4;
|
||||
await amzLib.checkout({gift, user, orderReferenceId, headers});
|
||||
|
||||
gift.member = receivingUser;
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||
user,
|
||||
|
||||
@@ -57,7 +57,20 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('errors if the user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
});
|
||||
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('purchases gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
await applePayments.verifyGemPurchase(user, receipt, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
@@ -74,6 +87,8 @@ describe('Apple Payments', () => {
|
||||
amount: 5.25,
|
||||
headers,
|
||||
});
|
||||
expect(user.canGetGems).to.be.calledOnce;
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -63,7 +63,21 @@ describe('Google Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase(user, receipt, signature, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
});
|
||||
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('purchases gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
await googlePayments.verifyGemPurchase(user, receipt, signature, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
@@ -82,6 +96,8 @@ describe('Google Payments', () => {
|
||||
amount: 5.25,
|
||||
headers,
|
||||
});
|
||||
expect(user.canGetGems).to.be.calledOnce;
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ describe('Paypal Payments', () => {
|
||||
});
|
||||
|
||||
it('creates a link for gem purchases', async () => {
|
||||
let link = await paypalPayments.checkout();
|
||||
let link = await paypalPayments.checkout({user: new User()});
|
||||
|
||||
expect(paypalPaymentCreateStub).to.be.calledOnce;
|
||||
expect(paypalPaymentCreateStub).to.be.calledWith(getPaypalCreateOptions('Habitica Gems', 5.00));
|
||||
@@ -87,13 +87,25 @@ describe('Paypal Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if the user cannot get gems', async () => {
|
||||
let user = new User();
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
|
||||
await expect(paypalPayments.checkout({user})).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a link for gifting gems', async () => {
|
||||
let receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
let gift = {
|
||||
type: 'gems',
|
||||
uuid: receivingUser._id,
|
||||
gems: {
|
||||
amount: 16,
|
||||
uuid: receivingUser._id,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -75,8 +75,29 @@ describe('Stripe Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should error if user cannot get gems', async () => {
|
||||
gift = undefined;
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(false);
|
||||
|
||||
await expect(stripePayments.checkout({
|
||||
token,
|
||||
user,
|
||||
gift,
|
||||
groupId,
|
||||
email,
|
||||
headers,
|
||||
coupon,
|
||||
}, stripe)).to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
message: i18n.t('groupPolicyCannotGetGems'),
|
||||
name: 'NotAuthorized',
|
||||
});
|
||||
});
|
||||
|
||||
it('should purchase gems', async () => {
|
||||
gift = undefined;
|
||||
sinon.stub(user, 'canGetGems').returnsPromise().resolves(true);
|
||||
|
||||
await stripePayments.checkout({
|
||||
token,
|
||||
@@ -102,16 +123,18 @@ describe('Stripe Payments', () => {
|
||||
paymentMethod: 'Stripe',
|
||||
gift,
|
||||
});
|
||||
expect(user.canGetGems).to.be.calledOnce;
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('should gift gems', async () => {
|
||||
let receivingUser = new User();
|
||||
receivingUser.save();
|
||||
await receivingUser.save();
|
||||
gift = {
|
||||
type: 'gems',
|
||||
uuid: receivingUser._id,
|
||||
gems: {
|
||||
amount: 16,
|
||||
uuid: receivingUser._id,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -125,7 +148,6 @@ describe('Stripe Payments', () => {
|
||||
coupon,
|
||||
}, stripe);
|
||||
|
||||
gift.member = receivingUser;
|
||||
expect(stripeChargeStub).to.be.calledOnce;
|
||||
expect(stripeChargeStub).to.be.calledWith({
|
||||
amount: '400',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Bluebird from 'bluebird';
|
||||
import moment from 'moment';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
import common from '../../../../../website/common';
|
||||
|
||||
describe('User Model', () => {
|
||||
@@ -179,6 +180,75 @@ describe('User Model', () => {
|
||||
});
|
||||
});
|
||||
|
||||
context('canGetGems', () => {
|
||||
let user;
|
||||
let group;
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
let leader = new User();
|
||||
group = new Group({
|
||||
name: 'test',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
leader: leader._id,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns true if user is not subscribed', async () => {
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if user is not subscribed with a group plan', async () => {
|
||||
user.purchased.plan.customerId = 123;
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if user is subscribed with a group plan', async () => {
|
||||
user.purchased.plan.customerId = 'group-plan';
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if user is part of a group', async () => {
|
||||
user.guilds.push(group._id);
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if user is part of a group with a subscription', async () => {
|
||||
user.guilds.push(group._id);
|
||||
user.purchased.plan.customerId = 'group-plan';
|
||||
group.purchased.plan.customerId = 123;
|
||||
await group.save();
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if leader is part of a group with a subscription and canGetGems: false', async () => {
|
||||
user.guilds.push(group._id);
|
||||
user.purchased.plan.customerId = 'group-plan';
|
||||
group.purchased.plan.customerId = 123;
|
||||
group.leader = user._id;
|
||||
group.leaderOnly.getGems = true;
|
||||
await group.save();
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns true if user is part of a group with no subscription but canGetGems: false', async () => {
|
||||
user.guilds.push(group._id);
|
||||
user.purchased.plan.customerId = 'group-plan';
|
||||
group.leaderOnly.getGems = true;
|
||||
await group.save();
|
||||
expect(await user.canGetGems()).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns false if user is part of a group with a subscription and canGetGems: false', async () => {
|
||||
user.guilds.push(group._id);
|
||||
user.purchased.plan.customerId = 'group-plan';
|
||||
group.purchased.plan.customerId = 123;
|
||||
group.leaderOnly.getGems = true;
|
||||
await group.save();
|
||||
expect(await user.canGetGems()).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('hasNotCancelled', () => {
|
||||
let user;
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -298,5 +298,6 @@
|
||||
"managerMarker": " - Manager",
|
||||
"joinedGuild": "Joined a Guild",
|
||||
"joinedGuildText": "Ventured into the social side of Habitica by joining a Guild!",
|
||||
"badAmountOfGemsToPurchase": "Amount must be at least 1."
|
||||
"badAmountOfGemsToPurchase": "Amount must be at least 1.",
|
||||
"groupPolicyCannotGetGems": "The policy of one group you're part of prevents its members from obtaining gems."
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ module.exports = function purchase (user, req = {}, analytics) {
|
||||
let convCap = planGemLimits.convCap;
|
||||
convCap += user.purchased.plan.consecutive.gemCapExtra;
|
||||
|
||||
// Some groups limit their members ability to obtain gems
|
||||
// The check is async so it's done on the server (in server/controllers/api-v3/user#purchase)
|
||||
// only and not on the client,
|
||||
// resulting in a purchase that will seem successful until the request hit the server.
|
||||
|
||||
if (!user.purchased || !user.purchased.plan || !user.purchased.plan.customerId) {
|
||||
throw new NotAuthorized(i18n.t('mustSubscribeToPurchaseGems', req.language));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
sendTxn as txnEmail,
|
||||
} from '../../libs/email';
|
||||
import nconf from 'nconf';
|
||||
import get from 'lodash/get';
|
||||
|
||||
const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS:TECH_ASSISTANCE_EMAIL');
|
||||
|
||||
@@ -1227,7 +1228,18 @@ api.purchase = {
|
||||
url: '/user/purchase/:type/:key',
|
||||
async handler (req, res) {
|
||||
let user = res.locals.user;
|
||||
let purchaseRes = req.params.type === 'spells' ? common.ops.buySpecialSpell(user, req) : common.ops.purchase(user, req, res.analytics);
|
||||
const type = get(req.params, 'type');
|
||||
const key = get(req.params, 'key');
|
||||
|
||||
// Some groups limit their members ability to obtain gems
|
||||
// The check is async so it's done on the server only and not on the client,
|
||||
// resulting in a purchase that will seem successful until the request hit the server.
|
||||
if (type === 'gems' && key === 'gem') {
|
||||
const canGetGems = await user.canGetGems();
|
||||
if (!canGetGems) throw new NotAuthorized(res.t('groupPolicyCannotGetGems'));
|
||||
}
|
||||
|
||||
let purchaseRes = type === 'spells' ? common.ops.buySpecialSpell(user, req) : common.ops.purchase(user, req, res.analytics);
|
||||
await user.save();
|
||||
res.respond(200, ...purchaseRes);
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ api.checkout = {
|
||||
let gift = req.query.gift ? JSON.parse(req.query.gift) : undefined;
|
||||
req.session.gift = req.query.gift;
|
||||
|
||||
let link = await paypalPayments.checkout({gift});
|
||||
let link = await paypalPayments.checkout({gift, user: res.locals.user});
|
||||
|
||||
if (req.query.noRedirect) {
|
||||
res.respond(200);
|
||||
|
||||
@@ -97,6 +97,8 @@ api.checkout = async function checkout (options = {}) {
|
||||
let amount = 5;
|
||||
|
||||
if (gift) {
|
||||
gift.member = await User.findById(gift.uuid).exec();
|
||||
|
||||
if (gift.type === this.constants.GIFT_TYPE_GEMS) {
|
||||
if (gift.gems.amount <= 0) {
|
||||
throw new BadRequest(i18n.t('badAmountOfGemsToPurchase'));
|
||||
@@ -107,6 +109,12 @@ api.checkout = async function checkout (options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!gift || gift.type === this.constants.GIFT_TYPE_GEMS) {
|
||||
const receiver = gift ? gift.member : user;
|
||||
const receiverCanGetGems = await receiver.canGetGems();
|
||||
if (!receiverCanGetGems) throw new NotAuthorized(i18n.t('groupPolicyCannotGetGems', receiver.preferences.language));
|
||||
}
|
||||
|
||||
await this.setOrderReferenceDetails({
|
||||
AmazonOrderReferenceId: orderReferenceId,
|
||||
OrderReferenceAttributes: {
|
||||
|
||||
@@ -21,6 +21,9 @@ api.constants = {
|
||||
};
|
||||
|
||||
api.verifyGemPurchase = async function verifyGemPurchase (user, receipt, headers) {
|
||||
const userCanGetGems = await user.canGetGems();
|
||||
if (!userCanGetGems) throw new NotAuthorized(shared.i18n.t('groupPolicyCannotGetGems', user.preferences.language));
|
||||
|
||||
await iap.setup();
|
||||
let appleRes = await iap.validate(iap.APPLE, receipt);
|
||||
let isValidated = iap.isValidated(appleRes);
|
||||
|
||||
@@ -20,6 +20,9 @@ api.constants = {
|
||||
};
|
||||
|
||||
api.verifyGemPurchase = async function verifyGemPurchase (user, receipt, signature, headers) {
|
||||
const userCanGetGems = await user.canGetGems();
|
||||
if (!userCanGetGems) throw new NotAuthorized(shared.i18n.t('groupPolicyCannotGetGems', user.preferences.language));
|
||||
|
||||
await iap.setup();
|
||||
|
||||
let testObj = {
|
||||
|
||||
@@ -70,11 +70,15 @@ api.paypalBillingAgreementCancel = Bluebird.promisify(paypal.billingAgreement.ca
|
||||
api.ipnVerifyAsync = Bluebird.promisify(ipn.verify, {context: ipn});
|
||||
|
||||
api.checkout = async function checkout (options = {}) {
|
||||
let {gift} = options;
|
||||
let {gift, user} = options;
|
||||
|
||||
let amount = 5.00;
|
||||
let description = 'Habitica Gems';
|
||||
|
||||
if (gift) {
|
||||
const member = await User.findById(gift.uuid).exec();
|
||||
gift.member = member;
|
||||
|
||||
if (gift.type === 'gems') {
|
||||
if (gift.gems.amount <= 0) {
|
||||
throw new BadRequest(i18n.t('badAmountOfGemsToPurchase'));
|
||||
@@ -87,6 +91,14 @@ api.checkout = async function checkout (options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!gift || gift.type === 'gems') {
|
||||
const receiver = gift ? gift.member : user;
|
||||
const receiverCanGetGems = await receiver.canGetGems();
|
||||
if (!receiverCanGetGems) throw new NotAuthorized(shared.i18n.t('groupPolicyCannotGetGems', receiver.preferences.language));
|
||||
}
|
||||
|
||||
|
||||
let createPayment = {
|
||||
intent: 'sale',
|
||||
payer: { payment_method: this.constants.PAYMENT_METHOD },
|
||||
|
||||
@@ -76,6 +76,11 @@ api.checkout = async function checkout (options, stripeInc) {
|
||||
|
||||
if (!token) throw new BadRequest('Missing req.body.id');
|
||||
|
||||
if (gift) {
|
||||
const member = await User.findById(gift.uuid).exec();
|
||||
gift.member = member;
|
||||
}
|
||||
|
||||
if (sub) {
|
||||
if (sub.discount) {
|
||||
if (!coupon) throw new BadRequest(shared.i18n.t('couponCodeRequired'));
|
||||
@@ -114,6 +119,12 @@ api.checkout = async function checkout (options, stripeInc) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!gift || gift.type === 'gems') {
|
||||
const receiver = gift ? gift.member : user;
|
||||
const receiverCanGetGems = await receiver.canGetGems();
|
||||
if (!receiverCanGetGems) throw new NotAuthorized(shared.i18n.t('groupPolicyCannotGetGems', receiver.preferences.language));
|
||||
}
|
||||
|
||||
response = await stripeApi.charges.create({
|
||||
amount,
|
||||
currency: 'usd',
|
||||
@@ -141,8 +152,6 @@ api.checkout = async function checkout (options, stripeInc) {
|
||||
};
|
||||
|
||||
if (gift) {
|
||||
let member = await User.findById(gift.uuid).exec();
|
||||
gift.member = member;
|
||||
if (gift.type === 'subscription') method = 'createSubscription';
|
||||
data.paymentMethod = 'Gift';
|
||||
}
|
||||
|
||||
@@ -283,7 +283,15 @@ schema.methods.closeChal = async function closeChal (broken = {}) {
|
||||
// Award prize to winner and notify
|
||||
if (winner) {
|
||||
winner.achievements.challenges.push(challenge.name);
|
||||
|
||||
// If the winner cannot get gems (because of a group policy)
|
||||
// reimburse the leader
|
||||
const winnerCanGetGems = await winner.canGetGems();
|
||||
if (!winnerCanGetGems) {
|
||||
await User.update({_id: challenge.leader}, {$inc: {balance: challenge.prize / 4}}).exec();
|
||||
} else {
|
||||
winner.balance += challenge.prize / 4;
|
||||
}
|
||||
|
||||
winner.addNotification('WON_CHALLENGE');
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ export let schema = new Schema({
|
||||
leaderOnly: { // restrict group actions to leader (members can't do them)
|
||||
challenges: {type: Boolean, default: false, required: true},
|
||||
// invites: {type: Boolean, default: false, required: true},
|
||||
// Some group plans prevent members from getting gems
|
||||
getGems: {type: Boolean, default: false},
|
||||
},
|
||||
memberCount: {type: Number, default: 1},
|
||||
challengeCount: {type: Number, default: 0},
|
||||
|
||||
@@ -4,6 +4,7 @@ import Bluebird from 'bluebird';
|
||||
import {
|
||||
chatDefaults,
|
||||
TAVERN_ID,
|
||||
model as Group,
|
||||
} from '../group';
|
||||
import { defaults, map, flatten, flow, compact, uniq, partialRight } from 'lodash';
|
||||
import { model as UserNotification } from '../userNotification';
|
||||
@@ -271,3 +272,28 @@ schema.methods.daysUserHasMissed = function daysUserHasMissed (now, req = {}) {
|
||||
|
||||
return {daysMissed, timezoneOffsetFromUserPrefs};
|
||||
};
|
||||
|
||||
// Determine if the user can get gems: some groups restrict their members ability to obtain them.
|
||||
// User is allowed to buy gems if no group has `leaderOnly.getGems` === true or if
|
||||
// its the group leader
|
||||
schema.methods.canGetGems = async function canObtainGems () {
|
||||
const user = this;
|
||||
const plan = user.purchased.plan;
|
||||
|
||||
if (!user.isSubscribed() || plan.customerId !== payments.constants.GROUP_PLAN_CUSTOMER_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const userGroups = user.getGroups();
|
||||
|
||||
const groups = await Group
|
||||
.find({
|
||||
_id: {$in: userGroups},
|
||||
})
|
||||
.select('leaderOnly leader purchased')
|
||||
.exec();
|
||||
|
||||
return groups.every(g => {
|
||||
return !g.isSubscribed() || g.leader === user._id || g.leaderOnly.getGems !== true;
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user