mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
log armoire, quoest response and cron events to history
This commit is contained in:
Submodule habitica-images updated: 98e9a400b8...aa72332019
@@ -19,6 +19,7 @@ import common from '../../../common';
|
|||||||
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
|
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
|
||||||
import { apiError } from '../../libs/apiError';
|
import { apiError } from '../../libs/apiError';
|
||||||
import { questActivityWebhook } from '../../libs/webhook';
|
import { questActivityWebhook } from '../../libs/webhook';
|
||||||
|
import { model as UserHistory } from '../../models/userHistory';
|
||||||
|
|
||||||
const analytics = getAnalyticsServiceByEnvironment();
|
const analytics = getAnalyticsServiceByEnvironment();
|
||||||
|
|
||||||
@@ -227,6 +228,10 @@ api.acceptQuest = {
|
|||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await UserHistory.beginUserHistoryUpdate(user._id)
|
||||||
|
.withQuestInviteResponse(group.quest.key, 'accept')
|
||||||
|
.commit();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -288,6 +293,10 @@ api.rejectQuest = {
|
|||||||
uuid: user._id,
|
uuid: user._id,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await UserHistory.beginUserHistoryUpdate(user._id)
|
||||||
|
.withQuestInviteResponse(group.quest.key, 'reject')
|
||||||
|
.commit();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
} from '../../libs/email';
|
} from '../../libs/email';
|
||||||
import * as inboxLib from '../../libs/inbox';
|
import * as inboxLib from '../../libs/inbox';
|
||||||
import * as userLib from '../../libs/user';
|
import * as userLib from '../../libs/user';
|
||||||
|
import { model as UserHistory } from '../../models/userHistory';
|
||||||
|
|
||||||
const OFFICIAL_PLATFORMS = ['habitica-web', 'habitica-ios', 'habitica-android'];
|
const OFFICIAL_PLATFORMS = ['habitica-web', 'habitica-ios', 'habitica-android'];
|
||||||
const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL');
|
const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL');
|
||||||
@@ -501,6 +502,13 @@ api.buy = {
|
|||||||
const buyRes = await common.ops.buy(user, req, res.analytics);
|
const buyRes = await common.ops.buy(user, req, res.analytics);
|
||||||
|
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
|
if (type === 'armoire') {
|
||||||
|
await UserHistory.beginUserHistoryUpdate(user._id)
|
||||||
|
.withArmoire(buyRes[0].armoire.dropKey || 'experience')
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
res.respond(200, ...buyRes);
|
res.respond(200, ...buyRes);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -593,6 +601,9 @@ api.buyArmoire = {
|
|||||||
}
|
}
|
||||||
const buyArmoireResponse = await common.ops.buy(user, req, res.analytics);
|
const buyArmoireResponse = await common.ops.buy(user, req, res.analytics);
|
||||||
await user.save();
|
await user.save();
|
||||||
|
await UserHistory.beginUserHistoryUpdate(user._id)
|
||||||
|
.withArmoire(buyArmoireResponse[1].data.armoire.dropKey)
|
||||||
|
.commit();
|
||||||
res.respond(200, ...buyArmoireResponse);
|
res.respond(200, ...buyArmoireResponse);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import common from '../../common';
|
|||||||
import { preenUserHistory } from './preening';
|
import { preenUserHistory } from './preening';
|
||||||
import { sleep } from './sleep';
|
import { sleep } from './sleep';
|
||||||
import { revealMysteryItems } from './payments/subscriptions';
|
import { revealMysteryItems } from './payments/subscriptions';
|
||||||
|
import { model as UserHistory } from '../models/userHistory';
|
||||||
|
|
||||||
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
|
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
|
||||||
const CRON_SEMI_SAFE_MODE = nconf.get('CRON_SEMI_SAFE_MODE') === 'true';
|
const CRON_SEMI_SAFE_MODE = nconf.get('CRON_SEMI_SAFE_MODE') === 'true';
|
||||||
@@ -523,5 +524,9 @@ export async function cron (options = {}) {
|
|||||||
user.flags.cronCount += 1;
|
user.flags.cronCount += 1;
|
||||||
trackCronAnalytics(analytics, user, _progress, options);
|
trackCronAnalytics(analytics, user, _progress, options);
|
||||||
|
|
||||||
|
await UserHistory.beginUserHistoryUpdate(user._id)
|
||||||
|
.withCron()
|
||||||
|
.commit();
|
||||||
|
|
||||||
return _progress;
|
return _progress;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
model as NewsPost,
|
model as NewsPost,
|
||||||
} from '../newsPost';
|
} from '../newsPost';
|
||||||
|
import {
|
||||||
|
model as UserHistory,
|
||||||
|
} from '../userHistory';
|
||||||
import { // eslint-disable-line import/no-cycle
|
import { // eslint-disable-line import/no-cycle
|
||||||
userActivityWebhook,
|
userActivityWebhook,
|
||||||
} from '../../libs/webhook';
|
} from '../../libs/webhook';
|
||||||
@@ -237,7 +240,7 @@ schema.pre('validate', function preValidateUser (next) {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
schema.pre('save', true, function preSaveUser (next, done) {
|
schema.pre('save', true, async function preSaveUser (next, done) {
|
||||||
next();
|
next();
|
||||||
|
|
||||||
// VERY IMPORTANT NOTE: when only some fields from an user document are selected
|
// VERY IMPORTANT NOTE: when only some fields from an user document are selected
|
||||||
@@ -360,6 +363,13 @@ schema.pre('save', true, function preSaveUser (next, done) {
|
|||||||
// Unset the field so this is run only once
|
// Unset the field so this is run only once
|
||||||
this.flags.lastWeeklyRecapDiscriminator = undefined;
|
this.flags.lastWeeklyRecapDiscriminator = undefined;
|
||||||
}
|
}
|
||||||
|
if (!this.flags.initializedUserHistory) {
|
||||||
|
this.flags.initializedUserHistory = true;
|
||||||
|
const history = UserHistory();
|
||||||
|
history.userId = this._id;
|
||||||
|
await history.save();
|
||||||
|
console.log('Initialized user history');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce min/max values without displaying schema errors to end user
|
// Enforce min/max values without displaying schema errors to end user
|
||||||
@@ -396,12 +406,9 @@ schema.pre('save', true, function preSaveUser (next, done) {
|
|||||||
|
|
||||||
// Populate new users with default content
|
// Populate new users with default content
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
_setUpNewUser(this)
|
await _setUpNewUser(this);
|
||||||
.then(() => done())
|
|
||||||
.catch(done);
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
}
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
schema.pre('updateOne', function preUpdateUser () {
|
schema.pre('updateOne', function preUpdateUser () {
|
||||||
|
|||||||
@@ -313,6 +313,7 @@ export const UserSchema = new Schema({
|
|||||||
warnedLowHealth: { $type: Boolean, default: false },
|
warnedLowHealth: { $type: Boolean, default: false },
|
||||||
verifiedUsername: { $type: Boolean, default: false },
|
verifiedUsername: { $type: Boolean, default: false },
|
||||||
thirdPartyTools: { $type: Date },
|
thirdPartyTools: { $type: Date },
|
||||||
|
initializedUserHistory: { $type: Boolean, default: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
history: {
|
history: {
|
||||||
|
|||||||
117
website/server/models/userHistory.js
Normal file
117
website/server/models/userHistory.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
import validator from 'validator';
|
||||||
|
import baseModel from '../libs/baseModel';
|
||||||
|
|
||||||
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
|
export const schema = new Schema({
|
||||||
|
userId: {
|
||||||
|
$type: String,
|
||||||
|
ref: 'User',
|
||||||
|
required: true,
|
||||||
|
validate: [v => validator.isUUID(v), 'Invalid uuid for userhistory.'],
|
||||||
|
index: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
armoire: [
|
||||||
|
{
|
||||||
|
_id: false,
|
||||||
|
timestamp: { $type: Date, required: true },
|
||||||
|
reward: { $type: String, required: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
questInviteResponses: [
|
||||||
|
{
|
||||||
|
_id: false,
|
||||||
|
timestamp: { $type: Date, required: true },
|
||||||
|
quest: { $type: String, required: true },
|
||||||
|
response: { $type: String, required: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
cron: [
|
||||||
|
{
|
||||||
|
_id: false,
|
||||||
|
timestamp: { $type: Date, required: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
strict: true,
|
||||||
|
minimize: false, // So empty objects are returned
|
||||||
|
typeKey: '$type', // So that we can use fields named `type`
|
||||||
|
});
|
||||||
|
|
||||||
|
schema.plugin(baseModel, {
|
||||||
|
noSet: ['id', '_id', 'userId'],
|
||||||
|
timestamps: true,
|
||||||
|
_id: false, // using custom _id
|
||||||
|
});
|
||||||
|
|
||||||
|
export const model = mongoose.model('UserHistory', schema);
|
||||||
|
|
||||||
|
const commitUserHistoryUpdate = function commitUserHistoryUpdate (update) {
|
||||||
|
const data = {
|
||||||
|
$push: {
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (update.data.armoire.length) {
|
||||||
|
data.$push.armoire = {
|
||||||
|
$each: update.data.armoire,
|
||||||
|
$sort: { timestamp: -1 },
|
||||||
|
$slice: 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (update.data.questInviteResponses.length) {
|
||||||
|
data.$push.questInviteResponses = {
|
||||||
|
$each: update.data.questInviteResponses,
|
||||||
|
$sort: { timestamp: -1 },
|
||||||
|
$slice: 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (update.data.cron.length > 0) {
|
||||||
|
data.$push.cron = {
|
||||||
|
$each: update.data.cron,
|
||||||
|
$sort: { timestamp: -1 },
|
||||||
|
$slice: 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return model.updateOne(
|
||||||
|
{ userId: update.userId },
|
||||||
|
data,
|
||||||
|
).exec();
|
||||||
|
};
|
||||||
|
|
||||||
|
model.beginUserHistoryUpdate = function beginUserHistoryUpdate (userID) {
|
||||||
|
return {
|
||||||
|
userId: userID,
|
||||||
|
data: {
|
||||||
|
armoire: [],
|
||||||
|
questInviteResponses: [],
|
||||||
|
cron: [],
|
||||||
|
},
|
||||||
|
withArmoire: function withArmoire (reward) {
|
||||||
|
this.data.armoire.push({
|
||||||
|
timestamp: new Date(),
|
||||||
|
reward,
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
withQuestInviteResponse: function withQuestInviteResponse (quest, response) {
|
||||||
|
this.data.questInviteResponses.push({
|
||||||
|
timestamp: new Date(),
|
||||||
|
quest,
|
||||||
|
response,
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
withCron: function withCron () {
|
||||||
|
this.data.cron.push({
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
commit: function commit () {
|
||||||
|
commitUserHistoryUpdate(this);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user