Merge branch 'develop' into phillip/sub_change

This commit is contained in:
SabreCat
2022-10-25 16:47:51 -05:00
268 changed files with 6840 additions and 3242 deletions
+11 -1
View File
@@ -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);
+29
View File
@@ -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 -1
View File
@@ -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 = {};
+1 -1
View File
@@ -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 = {};
+5 -2
View File
@@ -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 {
+5 -5
View File
@@ -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();
}
+6 -4
View File
@@ -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'));
}
-15
View File
@@ -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 -1
View File
@@ -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,
+4 -2
View File
@@ -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);
+20 -1
View File
@@ -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,
});
};