WIP: Improve User model performances (#10832)
* wip: define items as mixed objects * add default owned gear * mark modified * more mark modified * more mark modified * more mark modified * more mark modified * fix common tests * fix common tests * update mongoose * add itemsUtils * use new util function in hall controller * add tests for items utils * update website/server to mark all items as modified * start updating common code * update login incentives * update unlock * remove changes to package-lock.json * remove changes to package.json
This commit is contained in:
@@ -204,6 +204,8 @@ api.updateUsername = {
|
||||
} else {
|
||||
user.items.pets['Wolf-Veteran'] = 5;
|
||||
}
|
||||
|
||||
user.markModified('items.pets');
|
||||
}
|
||||
await user.save();
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ api.modifyInventory = {
|
||||
|
||||
if (gear) {
|
||||
user.items.gear.owned = gear;
|
||||
user.markModified('items.gear.owned');
|
||||
}
|
||||
|
||||
[
|
||||
@@ -148,6 +149,7 @@ api.modifyInventory = {
|
||||
].forEach((type) => {
|
||||
if (req.body[type]) {
|
||||
user.items[type] = req.body[type];
|
||||
user.markModified(`items.${type}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -595,6 +595,7 @@ api.joinGroup = {
|
||||
inviter.items.quests.basilist = 0;
|
||||
}
|
||||
inviter.items.quests.basilist++;
|
||||
inviter.markModified('items.quests');
|
||||
}
|
||||
promises.push(inviter.save());
|
||||
}
|
||||
@@ -890,6 +891,7 @@ api.removeGroupMember = {
|
||||
|
||||
if (group.quest && group.quest.active && group.quest.leader === member._id) {
|
||||
member.items.quests[group.quest.key] += 1;
|
||||
member.markModified('items.quests');
|
||||
}
|
||||
} else if (isInvited) {
|
||||
if (isInvited === 'guild') {
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
import _ from 'lodash';
|
||||
import apiError from '../../libs/apiError';
|
||||
import validator from 'validator';
|
||||
import { validateItemPath } from '../../libs/items/utils';
|
||||
|
||||
|
||||
let api = {};
|
||||
|
||||
@@ -264,10 +266,11 @@ api.updateHero = {
|
||||
if (updateData.purchased && updateData.purchased.ads) hero.purchased.ads = updateData.purchased.ads;
|
||||
|
||||
// give them the Dragon Hydra pet if they're above level 6
|
||||
if (hero.contributor.level >= 6) hero.items.pets['Dragon-Hydra'] = 5;
|
||||
if (updateData.itemPath && updateData.itemVal &&
|
||||
updateData.itemPath.indexOf('items.') === 0 &&
|
||||
User.schema.paths[updateData.itemPath]) {
|
||||
if (hero.contributor.level >= 6) {
|
||||
hero.items.pets['Dragon-Hydra'] = 5;
|
||||
hero.markModified('items.pets');
|
||||
}
|
||||
if (updateData.itemPath && updateData.itemVal && validateItemPath(updateData.itemPath)) {
|
||||
_.set(hero, updateData.itemPath, updateData.itemVal); // Sanitization at 5c30944 (deemed unnecessary)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import shared from '../../../common';
|
||||
import { model as User } from '../../models/user';
|
||||
import { last } from 'lodash';
|
||||
|
||||
// Build a list of gear items owned by default
|
||||
const defaultOwnedGear = {};
|
||||
|
||||
Object.keys(shared.content.gear.flat).forEach(key => {
|
||||
const item = shared.content.gear.flat[key];
|
||||
if (item.key.match(/(armor|head|shield)_warrior_0/) || item.gearSet === 'glasses' || item.gearSet === 'headband') {
|
||||
defaultOwnedGear[item.key] = true;
|
||||
}
|
||||
});
|
||||
|
||||
export function getDefaultOwnedGear () {
|
||||
// Clone to avoid modifications to the original object
|
||||
return Object.assign({}, defaultOwnedGear);
|
||||
}
|
||||
|
||||
// When passed a path to an item in the user object it'll return true if
|
||||
// it's valid, false otherwsie
|
||||
// Example of an item path: `items.gear.owned.head_warrior_0`
|
||||
export function validateItemPath (itemPath) {
|
||||
// The item path must start with `items.`
|
||||
if (itemPath.indexOf('items.') !== 0) return false;
|
||||
if (User.schema.paths[itemPath]) return true;
|
||||
|
||||
const key = last(itemPath.split('.'));
|
||||
|
||||
if (itemPath.indexOf('items.gear.owned') === 0) {
|
||||
return Boolean(shared.content.gear.flat[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.pets') === 0) {
|
||||
return Boolean(shared.content.petInfo[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.eggs') === 0) {
|
||||
return Boolean(shared.content.eggs[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.hatchingPotions') === 0) {
|
||||
return Boolean(shared.content.hatchingPotions[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.food') === 0) {
|
||||
return Boolean(shared.content.food[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.mounts') === 0) {
|
||||
return Boolean(shared.content.mountInfo[key]);
|
||||
}
|
||||
|
||||
if (itemPath.indexOf('items.quests') === 0) {
|
||||
return Boolean(shared.content.quests[key]);
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,7 @@ async function addSubToGroupUser (member, group) {
|
||||
|
||||
member.purchased.plan = plan;
|
||||
member.items.mounts['Jackalope-RoyalPurple'] = true;
|
||||
member.markModified('items.mounts');
|
||||
|
||||
data.user = member;
|
||||
await this.createSubscription(data);
|
||||
|
||||
@@ -140,6 +140,7 @@ async function createSubscription (data) {
|
||||
|
||||
if (recipient !== group) {
|
||||
recipient.items.pets['Jackalope-RoyalPurple'] = 5;
|
||||
recipient.markModified('items.pets');
|
||||
revealMysteryItems(recipient);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ schema.statics.apply = async function applyCoupon (user, req, code) {
|
||||
user.items.gear.owned.body_special_wondercon_red = true;
|
||||
user.items.gear.owned.body_special_wondercon_black = true;
|
||||
user.items.gear.owned.body_special_wondercon_gold = true;
|
||||
user.markModified('items.gear.owned');
|
||||
|
||||
user.extra = {signupEvent: 'wondercon'};
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ function _setUpNewUser (user) {
|
||||
let iterableFlags = user.flags.toObject();
|
||||
|
||||
user.items.quests.dustbunnies = 1;
|
||||
user.markModified('items.quests');
|
||||
|
||||
user.purchased.background.violet = true;
|
||||
user.preferences.background = 'violet';
|
||||
|
||||
@@ -217,6 +219,7 @@ schema.pre('save', true, function preSaveUser (next, done) {
|
||||
// automatically granted an item during a certain time period:
|
||||
// if (!this.items.pets['JackOLantern-Base'] && moment().isBefore('2014-11-01'))
|
||||
// this.items.pets['JackOLantern-Base'] = 5;
|
||||
// this.markModified('items.pets');
|
||||
}
|
||||
|
||||
// Filter notifications, remove unvalid and not necessary, handle the ones that have special requirements
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import mongoose from 'mongoose';
|
||||
import shared from '../../../common';
|
||||
import _ from 'lodash';
|
||||
import validator from 'validator';
|
||||
import { schema as TagSchema } from '../tag';
|
||||
import { schema as PushDeviceSchema } from '../pushDevice';
|
||||
@@ -11,6 +10,9 @@ import {
|
||||
import {
|
||||
schema as SubscriptionPlanSchema,
|
||||
} from '../subscriptionPlan';
|
||||
import {
|
||||
getDefaultOwnedGear,
|
||||
} from '../../libs/items/utils';
|
||||
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
@@ -251,12 +253,12 @@ let schema = new Schema({
|
||||
|
||||
items: {
|
||||
gear: {
|
||||
owned: _.transform(shared.content.gear.flat, (m, v) => {
|
||||
m[v.key] = {$type: Boolean};
|
||||
if (v.key.match(/(armor|head|shield)_warrior_0/) || v.gearSet === 'glasses' || v.gearSet === 'headband') {
|
||||
m[v.key].default = true;
|
||||
}
|
||||
}),
|
||||
owned: {
|
||||
$type: Schema.Types.Mixed,
|
||||
default: () => {
|
||||
return getDefaultOwnedGear();
|
||||
},
|
||||
},
|
||||
|
||||
equipped: {
|
||||
weapon: String,
|
||||
@@ -310,55 +312,52 @@ let schema = new Schema({
|
||||
// 'PandaCub-Red': 10, // Number represents "Growth Points"
|
||||
// etc...
|
||||
// }
|
||||
pets: _.defaults(
|
||||
// First transform to a 1D eggs/potions mapping
|
||||
_.transform(shared.content.pets, (m, v, k) => m[k] = Number),
|
||||
// Then add additional pets (quest, backer, contributor, premium)
|
||||
_.transform(shared.content.questPets, (m, v, k) => m[k] = Number),
|
||||
_.transform(shared.content.specialPets, (m, v, k) => m[k] = Number),
|
||||
_.transform(shared.content.premiumPets, (m, v, k) => m[k] = Number)
|
||||
),
|
||||
pets: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
currentPet: String, // Cactus-Desert
|
||||
|
||||
// eggs: {
|
||||
// 'PandaCub': 0, // 0 indicates "doesn't own"
|
||||
// 'Wolf': 5 // Number indicates "stacking"
|
||||
// }
|
||||
eggs: _.transform(shared.content.eggs, (m, v, k) => m[k] = Number),
|
||||
eggs: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
|
||||
// hatchingPotions: {
|
||||
// 'Desert': 0, // 0 indicates "doesn't own"
|
||||
// 'CottonCandyBlue': 5 // Number indicates "stacking"
|
||||
// }
|
||||
hatchingPotions: _.transform(shared.content.hatchingPotions, (m, v, k) => m[k] = Number),
|
||||
hatchingPotions: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
|
||||
// Food: {
|
||||
// 'Watermelon': 0, // 0 indicates "doesn't own"
|
||||
// 'RottenMeat': 5 // Number indicates "stacking"
|
||||
// }
|
||||
food: _.transform(shared.content.food, (m, v, k) => m[k] = Number),
|
||||
food: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
|
||||
// mounts: {
|
||||
// 'Wolf-Desert': true,
|
||||
// 'PandaCub-Red': false,
|
||||
// etc...
|
||||
// }
|
||||
mounts: _.defaults(
|
||||
// First transform to a 1D eggs/potions mapping
|
||||
_.transform(shared.content.pets, (m, v, k) => m[k] = Boolean),
|
||||
// Then add quest and premium pets
|
||||
_.transform(shared.content.questPets, (m, v, k) => m[k] = Boolean),
|
||||
_.transform(shared.content.premiumPets, (m, v, k) => m[k] = Boolean),
|
||||
// Then add additional mounts (backer, contributor)
|
||||
_.transform(shared.content.specialMounts, (m, v, k) => m[k] = Boolean)
|
||||
),
|
||||
mounts: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
currentMount: String,
|
||||
|
||||
// Quests: {
|
||||
// 'boss_0': 0, // 0 indicates "doesn't own"
|
||||
// 'collection_honey': 5 // Number indicates "stacking"
|
||||
// }
|
||||
quests: _.transform(shared.content.quests, (m, v, k) => m[k] = Number),
|
||||
quests: {$type: Schema.Types.Mixed, default: () => {
|
||||
return {};
|
||||
}},
|
||||
|
||||
lastDrop: {
|
||||
date: {$type: Date, default: Date.now},
|
||||
|
||||
Reference in New Issue
Block a user