Merge branch 'develop' into phillip/sub_change
This commit is contained in:
@@ -492,7 +492,17 @@ api.updateGroup = {
|
||||
|
||||
if (req.body.leader !== user._id && group.hasNotCancelled()) throw new NotAuthorized(res.t('cannotChangeLeaderWithActiveGroupPlan'));
|
||||
|
||||
_.assign(group, _.merge(group.toObject(), Group.sanitizeUpdate(req.body)));
|
||||
const handleArrays = (currentValue, updatedValue) => {
|
||||
if (!_.isArray(currentValue)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Previously, categories could get duplicated. By making the updated category list unique,
|
||||
// the duplication issue is fixed on every group edit
|
||||
return _.uniqBy(updatedValue, 'slug');
|
||||
};
|
||||
|
||||
_.assign(group, _.mergeWith(group.toObject(), Group.sanitizeUpdate(req.body), handleArrays));
|
||||
|
||||
const savedGroup = await group.save();
|
||||
const response = await Group.toJSONCleanChat(savedGroup, user);
|
||||
|
||||
@@ -273,6 +273,28 @@ api.updateHero = {
|
||||
hero.balance = updateData.balance;
|
||||
}
|
||||
|
||||
if (updateData.purchased && updateData.purchased.plan) {
|
||||
if (updateData.purchased.plan.gemsBought) {
|
||||
hero.purchased.plan.gemsBought = updateData.purchased.plan.gemsBought;
|
||||
}
|
||||
if (updateData.purchased.plan.consecutive) {
|
||||
if (updateData.purchased.plan.consecutive.trinkets) {
|
||||
await hero.updateHourglasses(
|
||||
updateData.purchased.plan.consecutive.trinkets
|
||||
- hero.purchased.plan.consecutive.trinkets,
|
||||
'admin_update_hourglasses', '', 'Updated by Habitica staff',
|
||||
);
|
||||
hero.purchased.plan.consecutive.trinkets = updateData.purchased.plan.consecutive.trinkets;
|
||||
}
|
||||
if (updateData.purchased.plan.consecutive.gemCapExtra) {
|
||||
hero.purchased.plan.consecutive.gemCapExtra = updateData.purchased.plan.consecutive.gemCapExtra; // eslint-disable-line max-len
|
||||
}
|
||||
if (updateData.purchased.plan.consecutive.count) {
|
||||
hero.purchased.plan.consecutive.count = updateData.purchased.plan.consecutive.count; // eslint-disable-line max-len
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// give them gems if they got an higher level
|
||||
// tier = level in this context
|
||||
let newTier = updateData.contributor && updateData.contributor.level;
|
||||
@@ -331,6 +353,13 @@ api.updateHero = {
|
||||
hero.apiToken = common.uuid();
|
||||
}
|
||||
|
||||
if (updateData.resetCron) {
|
||||
// Set last cron to yesterday. Quick approach so we don't need moment() for one line
|
||||
const yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
|
||||
hero.lastCron = yesterday;
|
||||
hero.auth.timestamps.loggedin = yesterday; // so admin panel doesn't gripe about mismatch
|
||||
}
|
||||
|
||||
const savedHero = await hero.save();
|
||||
const heroJSON = savedHero.toJSON();
|
||||
heroJSON.secret = savedHero.getSecretData();
|
||||
|
||||
@@ -978,6 +978,10 @@ api.disableClasses = {
|
||||
,"food","quests","gear"} type Type of item to purchase.
|
||||
* @apiParam (Path) {String} key Item's key (use "gem" for purchasing gems)
|
||||
*
|
||||
* @apiParam (Body) {Integer} [quantity=1] Count of items to buy.
|
||||
* Defaults to 1 and is ignored
|
||||
* for items where quantity is irrelevant.
|
||||
*
|
||||
* @apiSuccess {Object} data.items user.items
|
||||
* @apiSuccess {Number} data.balance user.balance
|
||||
* @apiSuccess {String} message Success message
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { authWithHeaders } from '../../middlewares/auth';
|
||||
import { chatReporterFactory } from '../../libs/chatReporting/chatReporterFactory';
|
||||
import { ensurePermission } from '../../middlewares/ensureAccessRight';
|
||||
import { model as Transaction } from '../../models/transaction';
|
||||
import { TransactionModel as Transaction } from '../../models/transaction';
|
||||
|
||||
const api = {};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { authWithHeaders } from '../../middlewares/auth';
|
||||
import * as userLib from '../../libs/user';
|
||||
import { verifyDisplayName } from '../../libs/user/validation';
|
||||
import common from '../../../common';
|
||||
import { model as Transaction } from '../../models/transaction';
|
||||
import { TransactionModel as Transaction } from '../../models/transaction';
|
||||
|
||||
const api = {};
|
||||
|
||||
|
||||
@@ -161,13 +161,16 @@ async function registerLocal (req, res, { isV3 = false }) {
|
||||
};
|
||||
|
||||
if (existingUser) {
|
||||
const hasSocialAuth = common.constants.SUPPORTED_SOCIAL_NETWORKS.find(network => {
|
||||
const networks = common.constants.SUPPORTED_SOCIAL_NETWORKS;
|
||||
// need to insert FB here to allow users who only have FB auth to connect local auth.
|
||||
networks.push({ key: 'facebook', name: 'Facebook' });
|
||||
const hasSocialAuth = networks.find(network => {
|
||||
if (existingUser.auth.hasOwnProperty(network.key)) { // eslint-disable-line no-prototype-builtins, max-len
|
||||
return existingUser.auth[network.key].id;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!hasSocialAuth) throw new NotAuthorized(res.t('onlySocialAttachLocal'));
|
||||
if (!hasSocialAuth && existingUser.auth.local.hashed_password) throw new NotAuthorized(res.t('onlySocialAttachLocal'));
|
||||
existingUser.auth.local = newUser.auth.local;
|
||||
newUser = existingUser;
|
||||
} else {
|
||||
|
||||
@@ -60,11 +60,6 @@ export async function loginSocial (req, res) { // eslint-disable-line import/pre
|
||||
[`auth.${network}.id`]: profile.id,
|
||||
}, { _id: 1, apiToken: 1, auth: 1 }).exec();
|
||||
|
||||
let email;
|
||||
if (profile.emails && profile.emails[0] && profile.emails[0].value) {
|
||||
email = profile.emails[0].value.toLowerCase();
|
||||
}
|
||||
|
||||
// User already signed up
|
||||
if (user) {
|
||||
if (existingUser) {
|
||||
@@ -79,6 +74,11 @@ export async function loginSocial (req, res) { // eslint-disable-line import/pre
|
||||
return loginRes(user, req, res);
|
||||
}
|
||||
|
||||
let email;
|
||||
if (profile.emails && profile.emails[0] && profile.emails[0].value) {
|
||||
email = profile.emails[0].value.toLowerCase();
|
||||
}
|
||||
|
||||
if (!existingUser && email) {
|
||||
existingUser = await User.findOne({ 'auth.local.email': email }).exec();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import find from 'lodash/find';
|
||||
import { getAnalyticsServiceByEnvironment } from '../analyticsService';
|
||||
import { getCurrentEvent } from '../worldState'; // eslint-disable-line import/no-cycle
|
||||
import { getCurrentEventList } from '../worldState'; // eslint-disable-line import/no-cycle
|
||||
import { // eslint-disable-line import/no-cycle
|
||||
getUserInfo,
|
||||
sendTxn as txnEmail,
|
||||
@@ -86,9 +87,10 @@ function getAmountForGems (data) {
|
||||
|
||||
const { gemsBlock } = data;
|
||||
|
||||
const currentEvent = getCurrentEvent();
|
||||
if (currentEvent && currentEvent.gemsPromo && currentEvent.gemsPromo[gemsBlock.key]) {
|
||||
return currentEvent.gemsPromo[gemsBlock.key] / 4;
|
||||
const currentEventsList = getCurrentEventList();
|
||||
const promoEvent = find(currentEventsList, event => Boolean(event.gemsPromo));
|
||||
if (promoEvent && promoEvent.gemsPromo[gemsBlock.key]) {
|
||||
return promoEvent.gemsPromo[gemsBlock.key] / 4;
|
||||
}
|
||||
|
||||
return gemsBlock.gems / 4;
|
||||
|
||||
@@ -86,6 +86,13 @@ async function createSubscription (data) {
|
||||
user: data.user, groupId: data.groupId, populateLeader: false, groupFields,
|
||||
});
|
||||
|
||||
if (group) {
|
||||
analytics.track(
|
||||
this.groupID,
|
||||
data.demographics,
|
||||
);
|
||||
}
|
||||
|
||||
if (!group) {
|
||||
throw new NotFound(shared.i18n.t('groupNotFound'));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import passport from 'passport';
|
||||
import nconf from 'nconf';
|
||||
import { Strategy as FacebookStrategy } from 'passport-facebook';
|
||||
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
|
||||
|
||||
// Passport session setup.
|
||||
@@ -13,20 +12,6 @@ import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
|
||||
passport.serializeUser((user, done) => done(null, user));
|
||||
passport.deserializeUser((obj, done) => done(null, obj));
|
||||
|
||||
// TODO remove?
|
||||
// This auth strategy is no longer used.
|
||||
// It's just kept around for auth.js#loginFacebook() (passport._strategies.facebook.userProfile)
|
||||
// The proper fix would be to move to a general OAuth module simply to verify accessTokens
|
||||
passport.use(new FacebookStrategy({
|
||||
clientID: nconf.get('FACEBOOK_KEY'),
|
||||
clientSecret: nconf.get('FACEBOOK_SECRET'),
|
||||
profileFields: ['id', 'email', 'displayName'],
|
||||
profileURL: 'https://graph.facebook.com/v2.8/me',
|
||||
authorizationURL: 'https://www.facebook.com/v2.8/dialog/oauth',
|
||||
tokenURL: 'https://graph.facebook.com/v2.8/oauth/access_token',
|
||||
// callbackURL: nconf.get("BASE_URL") + "/auth/facebook/callback"
|
||||
}, (accessToken, refreshToken, profile, done) => done(null, profile)));
|
||||
|
||||
passport.use(new GoogleStrategy({
|
||||
clientID: nconf.get('GOOGLE_CLIENT_ID'),
|
||||
clientSecret: nconf.get('GOOGLE_CLIENT_SECRET'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import validator from 'validator';
|
||||
import baseModel from '../libs/baseModel';
|
||||
import { model as Transaction } from './transaction';
|
||||
import { TransactionModel as Transaction } from './transaction';
|
||||
|
||||
export const schema = new mongoose.Schema({
|
||||
planId: String,
|
||||
|
||||
@@ -5,7 +5,7 @@ import baseModel from '../libs/baseModel';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
export const currencies = ['gems', 'hourglasses'];
|
||||
export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'admin_update_balance'];
|
||||
export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'admin_update_balance', 'admin_update_hourglasses'];
|
||||
|
||||
export const schema = new Schema({
|
||||
currency: { $type: String, enum: currencies, required: true },
|
||||
@@ -17,6 +17,7 @@ export const schema = new Schema({
|
||||
userId: {
|
||||
$type: String, ref: 'User', required: true, validate: [v => validator.isUUID(v), 'Invalid uuid for Transaction.'],
|
||||
},
|
||||
migration: String,
|
||||
}, {
|
||||
strict: true,
|
||||
minimize: false, // So empty objects are returned
|
||||
@@ -34,9 +35,10 @@ schema.plugin(baseModel, {
|
||||
'referenceText',
|
||||
'amount',
|
||||
'currentAmount',
|
||||
'migration',
|
||||
], // Nothing can be set from the client
|
||||
timestamps: true,
|
||||
_id: false, // using custom _id
|
||||
});
|
||||
|
||||
export const model = mongoose.model('Transaction', schema);
|
||||
export const TransactionModel = mongoose.model('Transaction', schema);
|
||||
|
||||
@@ -23,7 +23,7 @@ import amazonPayments from '../../libs/payments/amazon'; // eslint-disable-line
|
||||
import stripePayments from '../../libs/payments/stripe'; // eslint-disable-line import/no-cycle
|
||||
import paypalPayments from '../../libs/payments/paypal'; // eslint-disable-line import/no-cycle
|
||||
import { model as NewsPost } from '../newsPost';
|
||||
import { model as Transaction } from '../transaction';
|
||||
import { TransactionModel as Transaction } from '../transaction';
|
||||
|
||||
const { daysSince } = common;
|
||||
|
||||
@@ -577,3 +577,22 @@ schema.methods.updateBalance = async function updateBalance (amount,
|
||||
currentAmount: this.balance,
|
||||
});
|
||||
};
|
||||
|
||||
schema.methods.updateHourglasses = async function updateHourglasses (
|
||||
amount,
|
||||
transactionType,
|
||||
reference,
|
||||
referenceText,
|
||||
) {
|
||||
this.purchased.plan.consecutive.trinkets += amount;
|
||||
|
||||
await Transaction.create({
|
||||
currency: 'hourglasses',
|
||||
userId: this._id,
|
||||
transactionType,
|
||||
amount,
|
||||
reference,
|
||||
referenceText,
|
||||
currentAmount: this.purchased.plan.consecutive.trinkets,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user