v3: review some more files, add logging for unhandled promises

This commit is contained in:
Matteo Pagliazzi
2016-04-12 20:14:36 +02:00
parent 6458796a36
commit 793ce38f6b
18 changed files with 33 additions and 48 deletions

View File

@@ -62,7 +62,7 @@ describe('Challenge Model', () => {
each(tasksToTest, (taskValue, taskType) => { each(tasksToTest, (taskValue, taskType) => {
context(`${taskType}`, () => { context(`${taskType}`, () => {
beforeEach(async() => { beforeEach(async() => {
task = new Tasks[`${taskType}`](Tasks.Task.sanitizeCreate(taskValue)); task = new Tasks[`${taskType}`](Tasks.Task.sanitize(taskValue));
task.challenge.id = challenge._id; task.challenge.id = challenge._id;
await task.save(); await task.save();
}); });

View File

@@ -54,7 +54,7 @@ describe('Task Model', () => {
each(tasksToTest, (taskValue, taskType) => { each(tasksToTest, (taskValue, taskType) => {
context(`${taskType}`, () => { context(`${taskType}`, () => {
beforeEach(async() => { beforeEach(async() => {
task = new Tasks[`${taskType}`](Tasks.Task.sanitizeCreate(taskValue)); task = new Tasks[`${taskType}`](Tasks.Task.sanitize(taskValue));
task.challenge.id = challenge._id; task.challenge.id = challenge._id;
task.history = generateHistory(396); task.history = generateHistory(396);
await task.save(); await task.save();

View File

@@ -210,7 +210,6 @@ let _sendPurchaseDataToGoogle = (data) => {
}); });
}; };
// TODO log errors...
function track (eventType, data) { function track (eventType, data) {
return Q.all([ return Q.all([
_sendDataToAmplitude(eventType, data), _sendDataToAmplitude(eventType, data),

View File

@@ -4,7 +4,6 @@ import {
} from 'crypto'; } from 'crypto';
import nconf from 'nconf'; import nconf from 'nconf';
// TODO check this is secure
const algorithm = 'aes-256-ctr'; const algorithm = 'aes-256-ctr';
const SESSION_SECRET = nconf.get('SESSION_SECRET'); const SESSION_SECRET = nconf.get('SESSION_SECRET');
@@ -22,4 +21,4 @@ export function decrypt (text) {
dec += decipher.final('utf8'); dec += decipher.final('utf8');
return dec; return dec;
} }

View File

@@ -104,15 +104,3 @@ export let multipleVersionsLanguages = {
'zh-tw': 'zh_TW', 'zh-tw': 'zh_TW',
}, },
}; };
// Export en strings only, temporary solution for mobile
// This is copied from middlewares/locals#t()
// TODO review if this can be removed since the old mobile app is no longer active
// stringName and vars are the allowed parameters
export function enTranslations (...args) {
let language = _.find(availableLanguages, {code: 'en'});
// language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined);
args.push(language.code);
return shared.i18n.t(...args);
}

View File

@@ -20,4 +20,15 @@ if (IS_PROD) {
}); });
} }
// Logs unhandled promises errors
// when no catch is attached to a promise a unhandledRejection event will be triggered
process.on('unhandledRejection', function handlePromiseRejection (reason, promise) {
let stack = reason.stack || reason.message || reason;
logger.error(stack, {
promise,
fullError: reason,
});
});
module.exports = logger; module.exports = logger;

View File

@@ -9,7 +9,8 @@ let gcm = GCM_API_KEY ? pushNotify.gcm({
retries: 3, retries: 3,
}) : undefined; }) : undefined;
// TODO log // TODO review and test this file when push notifications are added back
if (gcm) { if (gcm) {
gcm.on('transmitted', (/* result, message, registrationId */) => { gcm.on('transmitted', (/* result, message, registrationId */) => {
// console.info("transmitted", result, message, registrationId); // console.info("transmitted", result, message, registrationId);
@@ -24,7 +25,6 @@ if (gcm) {
}); });
} }
// TODO test
module.exports = function sendNotification (user, title, message, timeToLive = 15) { module.exports = function sendNotification (user, title, message, timeToLive = 15) {
// TODO need investigation: // TODO need investigation:
// https://github.com/HabitRPG/habitrpg/issues/5252 // https://github.com/HabitRPG/habitrpg/issues/5252
@@ -50,7 +50,6 @@ module.exports = function sendNotification (user, title, message, timeToLive = 1
break; break;
case 'ios': case 'ios':
// TODO implement
break; break;
} }
}); });

View File

@@ -14,7 +14,7 @@ const FacebookStrategy = passportFacebook.Strategy;
passport.serializeUser((user, done) => done(null, user)); passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((obj, done) => done(null, obj)); passport.deserializeUser((obj, done) => done(null, obj));
// TODO // TODO remove?
// This auth strategy is no longer used. It's just kept around for auth.js#loginFacebook() (passport._strategies.facebook.userProfile) // 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 // The proper fix would be to move to a general OAuth module simply to verify accessTokens
passport.use(new FacebookStrategy({ passport.use(new FacebookStrategy({

View File

@@ -40,7 +40,6 @@ export function authWithHeaders (optional = false) {
} }
// Authenticate a request through a valid session // Authenticate a request through a valid session
// TODO should use json web token
export function authWithSession (req, res, next) { export function authWithSession (req, res, next) {
let userId = req.session.userId; let userId = req.session.userId;

View File

@@ -1,6 +1,3 @@
// TODO in api-v2 this module also checked memory usage every x minutes and
// threw an error in case of low memory avalible (possible memory leak)
// it's yet to be decided whether to keep it or not
import domainMiddleware from 'domain-middleware'; import domainMiddleware from 'domain-middleware';
module.exports = function implementDomainMiddleware (server, mongoose) { module.exports = function implementDomainMiddleware (server, mongoose) {

View File

@@ -32,8 +32,6 @@ module.exports = function errorHandler (err, req, res, next) { // eslint-disable
responseErr.message = err.message; responseErr.message = err.message;
} }
// TODO make mongoose and express-validator errors more recognizable
// Handle errors by express-validator // Handle errors by express-validator
if (Array.isArray(err) && err[0].param && err[0].msg) { if (Array.isArray(err) && err[0].param && err[0].msg) {
responseErr = new BadRequest(res.t('invalidReqParams')); responseErr = new BadRequest(res.t('invalidReqParams'));

View File

@@ -49,7 +49,7 @@ module.exports = function attachMiddlewares (app, server) {
extended: true, // Uses 'qs' library as old connect middleware extended: true, // Uses 'qs' library as old connect middleware
})); }));
app.use(bodyParser.json()); app.use(bodyParser.json());
app.use(methodOverride()); // TODO still needed in 2016? app.use(methodOverride());
app.use(cookieSession({ app.use(cookieSession({
name: 'connect:sess', // Used to keep backward compatibility with Express 3 cookies name: 'connect:sess', // Used to keep backward compatibility with Express 3 cookies

View File

@@ -12,7 +12,6 @@ import { mods } from '../../models/user';
// To avoid stringifying more data then we need, // To avoid stringifying more data then we need,
// items from `env` used on the client will have to be specified in this array // items from `env` used on the client will have to be specified in this array
// TODO where is this used?
const CLIENT_VARS = ['language', 'isStaticPage', 'availableLanguages', 'translations', const CLIENT_VARS = ['language', 'isStaticPage', 'availableLanguages', 'translations',
'FACEBOOK_KEY', 'NODE_ENV', 'BASE_URL', 'GA_ID', 'FACEBOOK_KEY', 'NODE_ENV', 'BASE_URL', 'GA_ID',
'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY', 'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY',

View File

@@ -114,7 +114,7 @@ schema.methods.syncToUser = async function syncChallengeToUser (user) {
let matchingTask = _.find(userTasks, userTask => userTask.challenge.taskId === chalTask._id); let matchingTask = _.find(userTasks, userTask => userTask.challenge.taskId === chalTask._id);
if (!matchingTask) { // If the task is new, create it if (!matchingTask) { // If the task is new, create it
matchingTask = new Tasks[chalTask.type](Tasks.Task.sanitizeCreate(_syncableAttrs(chalTask))); matchingTask = new Tasks[chalTask.type](Tasks.Task.sanitize(_syncableAttrs(chalTask)));
matchingTask.challenge = {taskId: chalTask._id, id: challenge._id}; matchingTask.challenge = {taskId: chalTask._id, id: challenge._id};
matchingTask.userId = user._id; matchingTask.userId = user._id;
user.tasksOrder[`${chalTask.type}s`].push(matchingTask._id); user.tasksOrder[`${chalTask.type}s`].push(matchingTask._id);
@@ -152,13 +152,14 @@ schema.methods.addTasks = async function challengeAddTasks (tasks) {
let membersIds = await _fetchMembersIds(challenge._id); let membersIds = await _fetchMembersIds(challenge._id);
// Sync each user sequentially // Sync each user sequentially
// TODO are we sure it's the best solution?
for (let memberId of membersIds) { for (let memberId of membersIds) {
let updateTasksOrderQ = {$push: {}}; let updateTasksOrderQ = {$push: {}};
let toSave = []; let toSave = [];
// TODO eslint complaints about ahving a function inside a loop -> make sure it works // TODO eslint complaints about having a function inside a loop -> make sure it works
tasks.forEach(chalTask => { // eslint-disable-line no-loop-func tasks.forEach(chalTask => { // eslint-disable-line no-loop-func
let userTask = new Tasks[chalTask.type](Tasks.Task.sanitizeCreate(_syncableAttrs(chalTask))); let userTask = new Tasks[chalTask.type](Tasks.Task.sanitize(_syncableAttrs(chalTask)));
userTask.challenge = {taskId: chalTask._id, id: challenge._id}; userTask.challenge = {taskId: chalTask._id, id: challenge._id};
userTask.userId = memberId; userTask.userId = memberId;
@@ -192,7 +193,6 @@ schema.methods.updateTask = async function challengeUpdateTask (task) {
updateCmd.$set[key] = syncableAttrs[key]; updateCmd.$set[key] = syncableAttrs[key];
} }
// TODO reveiw
// Updating instead of loading and saving for performances, risks becoming a problem if we introduce more complexity in tasks // Updating instead of loading and saving for performances, risks becoming a problem if we introduce more complexity in tasks
await Tasks.Task.update({ await Tasks.Task.update({
userId: {$exists: true}, userId: {$exists: true},

View File

@@ -212,13 +212,13 @@ schema.methods.removeGroupInvitations = async function removeGroupInvitations ()
let group = this; let group = this;
let usersToRemoveInvitationsFrom = await User.find({ let usersToRemoveInvitationsFrom = await User.find({
// TODO id -> _id ?
[`invitations.${group.type}${group.type === 'guild' ? 's' : ''}.id`]: group._id, [`invitations.${group.type}${group.type === 'guild' ? 's' : ''}.id`]: group._id,
}).exec(); }).exec();
let userUpdates = usersToRemoveInvitationsFrom.map(user => { let userUpdates = usersToRemoveInvitationsFrom.map(user => {
if (group.type === 'party') { if (group.type === 'party') {
user.invitations.party = {}; // TODO mark modified user.invitations.party = {};
this.markModified('invitations.party');
} else { } else {
removeFromArray(user.invitations.guilds, { id: group._id }); removeFromArray(user.invitations.guilds, { id: group._id });
} }
@@ -395,7 +395,6 @@ function _cleanQuestProgress (merge) {
return clean; return clean;
} }
// TODO move to User.cleanQuestProgress?
schema.statics.cleanQuestProgress = _cleanQuestProgress; schema.statics.cleanQuestProgress = _cleanQuestProgress;
// returns a clean object for group.quest // returns a clean object for group.quest
@@ -619,7 +618,6 @@ schema.statics.tavernBoss = async function tavernBoss (user, progress) {
_.assign(tavernQuest, tavern.quest.toObject()); _.assign(tavernQuest, tavern.quest.toObject());
return tavern.save(); return tavern.save();
} }
// TODO catch
}; };
schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') { schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') {

View File

@@ -5,7 +5,7 @@ let Schema = mongoose.Schema;
export let schema = new Schema({ export let schema = new Schema({
name: {type: String, required: true}, name: {type: String, required: true},
challenge: {type: String}, // TODO validate challenge: {type: String},
}, { }, {
minimize: true, // So empty objects are returned minimize: true, // So empty objects are returned
strict: true, strict: true,

View File

@@ -57,7 +57,7 @@ export let TaskSchema = new Schema({
TaskSchema.plugin(baseModel, { TaskSchema.plugin(baseModel, {
noSet: ['challenge', 'userId', 'completed', 'history', 'streak', 'dateCompleted', 'completed'], noSet: ['challenge', 'userId', 'completed', 'history', 'streak', 'dateCompleted', 'completed'],
sanitizeTransform (taskObj) { sanitizeTransform (taskObj) {
if (taskObj.type !== 'reward') { // value should be settable directly only for rewards if (taskObj.type && taskObj.type !== 'reward') { // value should be settable directly only for rewards
delete taskObj.value; delete taskObj.value;
} }

View File

@@ -49,7 +49,6 @@ export let schema = new Schema({
// We want to know *every* time an object updates. Mongoose uses __v to designate when an object contains arrays which // We want to know *every* time an object updates. Mongoose uses __v to designate when an object contains arrays which
// have been updated (http://goo.gl/gQLz41), but we want *every* update // have been updated (http://goo.gl/gQLz41), but we want *every* update
_v: { type: Number, default: 0 }, _v: { type: Number, default: 0 },
// TODO give all this a default of 0?
achievements: { achievements: {
originalUser: Boolean, originalUser: Boolean,
habitSurveys: Number, habitSurveys: Number,
@@ -99,8 +98,11 @@ export let schema = new Schema({
contributor: { contributor: {
// 1-9, see https://trello.com/c/wkFzONhE/277-contributor-gear https://github.com/HabitRPG/habitrpg/issues/3801 // 1-9, see https://trello.com/c/wkFzONhE/277-contributor-gear https://github.com/HabitRPG/habitrpg/issues/3801
// TODO validate level: {
level: Number, type: Number,
min: 0,
max: 9,
},
admin: Boolean, admin: Boolean,
sudo: Boolean, sudo: Boolean,
// Artisan, Friend, Blacksmith, etc // Artisan, Friend, Blacksmith, etc
@@ -119,7 +121,6 @@ export let schema = new Schema({
purchased: { purchased: {
ads: {type: Boolean, default: false}, ads: {type: Boolean, default: false},
// eg, {skeleton: true, pumpkin: true, eb052b: true} // eg, {skeleton: true, pumpkin: true, eb052b: true}
// TODO dictionary
skin: {type: Schema.Types.Mixed, default: () => { skin: {type: Schema.Types.Mixed, default: () => {
return {}; return {};
}}, }},
@@ -421,7 +422,7 @@ export let schema = new Schema({
displayInviteToPartyWhenPartyIs1: {type: Boolean, default: true}, displayInviteToPartyWhenPartyIs1: {type: Boolean, default: true},
webhooks: {type: Schema.Types.Mixed, default: () => { webhooks: {type: Schema.Types.Mixed, default: () => {
return {}; return {};
}}, // TODO array? and proper controller... unless VersionError becomes problematic }},
// For the following fields make sure to use strict comparison when searching for falsey values (=== false) // For the following fields make sure to use strict comparison when searching for falsey values (=== false)
// As users who didn't login after these were introduced may have them undefined/null // As users who didn't login after these were introduced may have them undefined/null
emailNotifications: { emailNotifications: {
@@ -541,7 +542,6 @@ schema.plugin(baseModel, {
}); });
// A list of publicly accessible fields (not everything from preferences because there are also a lot of settings tha should remain private) // A list of publicly accessible fields (not everything from preferences because there are also a lot of settings tha should remain private)
// TODO is all party data meant to be public?
export let publicFields = `preferences.size preferences.hair preferences.skin preferences.shirt export let publicFields = `preferences.size preferences.hair preferences.skin preferences.shirt
preferences.costume preferences.sleep preferences.background profile stats achievements party preferences.costume preferences.sleep preferences.background profile stats achievements party
backer contributor auth.timestamps items`; backer contributor auth.timestamps items`;
@@ -823,6 +823,4 @@ mongoose.model('User')
.then((foundMods) => { .then((foundMods) => {
// Using push to maintain the reference to mods // Using push to maintain the reference to mods
mods.push(...foundMods); mods.push(...foundMods);
}, (err) => { // TODO replace with .catch which for some reason was throwing an error }); // In case of failure we don't want this to crash the whole server
throw err; // TODO ?
});