diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js index 175a8ca88d..b5aa5ccbb0 100644 --- a/website/server/controllers/api-v3/auth.js +++ b/website/server/controllers/api-v3/auth.js @@ -525,7 +525,7 @@ api.resetPassword = { let newPassword = passwordUtils.makeSalt(); // use a salt as the new password too (they'll change it later) let hashedPassword = passwordUtils.encrypt(newPassword, salt); - let user = await User.findOne({ 'auth.local.email': email }); + let user = await User.findOne({ 'auth.local.email': email }).exec(); if (user) { user.auth.local.salt = salt; @@ -578,7 +578,10 @@ api.updateEmail = { let validationErrors = req.validationErrors(); if (validationErrors) throw validationErrors; - let emailAlreadyInUse = await User.findOne({'auth.local.email': req.body.newEmail}).select({_id: 1}).lean().exec(); + let emailAlreadyInUse = await User.findOne({ + 'auth.local.email': req.body.newEmail, + }).select({_id: 1}).lean().exec(); + if (emailAlreadyInUse) throw new NotAuthorized(res.t('cannotFulfillReq')); let candidatePassword = passwordUtils.encrypt(req.body.password, user.auth.local.salt); diff --git a/website/server/controllers/api-v3/challenges.js b/website/server/controllers/api-v3/challenges.js index cf7e50cd35..f948e49b39 100644 --- a/website/server/controllers/api-v3/challenges.js +++ b/website/server/controllers/api-v3/challenges.js @@ -138,7 +138,7 @@ api.joinChallenge = { let validationErrors = req.validationErrors(); if (validationErrors) throw validationErrors; - let challenge = await Challenge.findOne({ _id: req.params.challengeId }); + let challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); if (challenge.isMember(user)) throw new NotAuthorized(res.t('userAlreadyInChallenge')); @@ -187,7 +187,7 @@ api.leaveChallenge = { let validationErrors = req.validationErrors(); if (validationErrors) throw validationErrors; - let challenge = await Challenge.findOne({ _id: req.params.challengeId }); + let challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); let group = await Group.getGroup({user, groupId: challenge.group, fields: '_id type privacy'}); @@ -282,9 +282,13 @@ api.getGroupChallenges = { let resChals = challenges.map(challenge => challenge.toJSON()); // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 await Bluebird.all(resChals.map((chal, index) => { - return User.findById(chal.leader).select(nameFields).exec().then(populatedLeader => { - resChals[index].leader = populatedLeader ? populatedLeader.toJSON({minimize: true}) : null; - }); + return User + .findById(chal.leader) + .select(nameFields) + .exec() + .then(populatedLeader => { + resChals[index].leader = populatedLeader ? populatedLeader.toJSON({minimize: true}) : null; + }); })); res.respond(200, resChals); @@ -315,10 +319,10 @@ api.getChallenge = { let user = res.locals.user; let challengeId = req.params.challengeId; - let challenge = await Challenge.findById(challengeId) - // Don't populate the group as we'll fetch it manually later - // .populate('leader', nameFields) - .exec(); + // Don't populate the group as we'll fetch it manually later + // .populate('leader', nameFields) + let challenge = await Challenge.findById(challengeId).exec(); + if (!challenge) throw new NotFound(res.t('challengeNotFound')); // Fetching basic group data @@ -374,8 +378,12 @@ api.exportChallengeCsv = { .lean() // so we don't involve mongoose .exec(), - Tasks.Task.find({'challenge.id': challengeId, userId: {$exists: true}}) - .sort({userId: 1, text: 1}).select('userId type text value notes').lean().exec(), + Tasks.Task.find({ + 'challenge.id': challengeId, + userId: {$exists: true}, + }).sort({userId: 1, text: 1}) + .select('userId type text value notes') + .lean().exec(), ]); let resArray = members.map(member => [member._id, member.profile.name]); diff --git a/website/server/controllers/api-v3/chat.js b/website/server/controllers/api-v3/chat.js index 48d58a2b15..fd3b26815f 100644 --- a/website/server/controllers/api-v3/chat.js +++ b/website/server/controllers/api-v3/chat.js @@ -31,7 +31,7 @@ async function getAuthorEmailFromMessage (message) { return 'system'; } - let author = await User.findOne({_id: authorId}, {auth: 1}); + let author = await User.findOne({_id: authorId}, {auth: 1}).exec(); if (author) { return getUserInfo(author, ['email']).email; @@ -182,7 +182,7 @@ api.likeChat = { await Group.update( {_id: group._id, 'chat.id': message.id}, update - ); + ).exec(); res.respond(200, message); // TODO what if the message is flagged and shouldn't be returned? }, }; @@ -257,7 +257,7 @@ api.flagChat = { await Group.update( {_id: group._id, 'chat.id': message.id}, update - ); + ).exec(); let reporterEmailContent = getUserInfo(user, ['email']).email; let authorEmail = await getAuthorEmailFromMessage(message); @@ -344,7 +344,7 @@ api.clearChatFlags = { await Group.update( {_id: group._id, 'chat.id': message.id}, {$set: {'chat.$.flagCount': message.flagCount}} - ); + ).exec(); let adminEmailContent = getUserInfo(user, ['email']).email; let authorEmail = getAuthorEmailFromMessage(message); @@ -454,7 +454,7 @@ api.deleteChat = { await Group.update( {_id: group._id}, {$pull: {chat: {id: chatId}}} - ); + ).exec(); if (chatUpdated) { let chatRes = Group.toJSONCleanChat(group, user).chat; diff --git a/website/server/controllers/api-v3/groups.js b/website/server/controllers/api-v3/groups.js index dd6f2de1e9..8705a321d2 100644 --- a/website/server/controllers/api-v3/groups.js +++ b/website/server/controllers/api-v3/groups.js @@ -308,7 +308,8 @@ api.updateGroup = { let response = Group.toJSONCleanChat(savedGroup, user); // If the leader changed fetch new data, otherwise use authenticated user if (response.leader !== user._id) { - response.leader = (await User.findById(response.leader).select(nameFields).exec()).toJSON({minimize: true}); + let rawLeader = await User.findById(response.leader).select(nameFields).exec(); + response.leader = rawLeader.toJSON({minimize: true}); } else { response.leader = { _id: user._id, @@ -423,10 +424,16 @@ api.joinGroup = { if (group.type === 'party' && inviter) { if (group.memberCount > 1) { - promises.push(User.update({$or: [{'party._id': group._id}, {_id: user._id}], 'achievements.partyUp': {$ne: true}}, {$set: {'achievements.partyUp': true}}, {multi: true}).exec()); + promises.push(User.update({ + $or: [{'party._id': group._id}, {_id: user._id}], + 'achievements.partyUp': {$ne: true}, + }, {$set: {'achievements.partyUp': true}}, {multi: true}).exec()); } if (group.memberCount > 3) { - promises.push(User.update({$or: [{'party._id': group._id}, {_id: user._id}], 'achievements.partyOn': {$ne: true}}, {$set: {'achievements.partyOn': true}}, {multi: true}).exec()); + promises.push(User.update({ + $or: [{'party._id': group._id}, {_id: user._id}], + 'achievements.partyOn': {$ne: true}, + }, {$set: {'achievements.partyOn': true}}, {multi: true}).exec()); } } diff --git a/website/server/controllers/api-v3/quests.js b/website/server/controllers/api-v3/quests.js index 2502e4bf07..edb3bf2f74 100644 --- a/website/server/controllers/api-v3/quests.js +++ b/website/server/controllers/api-v3/quests.js @@ -77,7 +77,8 @@ api.inviteToQuest = { let members = await User.find({ 'party._id': group._id, _id: {$ne: user._id}, - }).select('auth.facebook auth.local preferences.emailNotifications profile.name pushDevices') + }) + .select('auth.facebook auth.local preferences.emailNotifications profile.name pushDevices') .exec(); group.markModified('quest'); @@ -376,7 +377,7 @@ api.cancelQuest = { {'party._id': groupId}, {$set: {'party.quest': Group.cleanQuestProgress()}}, {multi: true} - ), + ).exec(), ]); res.respond(200, savedGroup.quest); diff --git a/website/server/controllers/api-v3/tasks.js b/website/server/controllers/api-v3/tasks.js index ca358aff87..557243793e 100644 --- a/website/server/controllers/api-v3/tasks.js +++ b/website/server/controllers/api-v3/tasks.js @@ -157,9 +157,17 @@ api.getChallengeTasks = { let user = res.locals.user; let challengeId = req.params.challengeId; - let challenge = await Challenge.findOne({_id: challengeId}).select('group leader tasksOrder').exec(); + let challenge = await Challenge.findOne({ + _id: challengeId, + }).select('group leader tasksOrder').exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); - let group = await Group.getGroup({user, groupId: challenge.group, fields: '_id type privacy', optionalMembership: true}); + + let group = await Group.getGroup({ + user, + groupId: challenge.group, + fields: '_id type privacy', + optionalMembership: true, + }); if (!group || !challenge.canView(user, group)) throw new NotFound(res.t('challengeNotFound')); let tasks = await getTasks(req, res, {user, challenge}); @@ -339,7 +347,8 @@ api.scoreTask = { task.group.approval.requestedDate = new Date(); let group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields}); - let groupLeader = await User.findById(group.leader); // Use this method so we can get access to notifications + let groupLeader = await User.findById(group.leader).exec(); // Use this method so we can get access to notifications + groupLeader.addNotification('GROUP_TASK_APPROVAL', { message: res.t('userHasRequestedTaskApproval', { user: user.profile.name, diff --git a/website/server/controllers/api-v3/tasks/groups.js b/website/server/controllers/api-v3/tasks/groups.js index b1f5af3628..7ed0045b16 100644 --- a/website/server/controllers/api-v3/tasks/groups.js +++ b/website/server/controllers/api-v3/tasks/groups.js @@ -104,7 +104,7 @@ api.assignTask = { let user = res.locals.user; let assignedUserId = req.params.assignedUserId; - let assignedUser = await User.findById(assignedUserId); + let assignedUser = await User.findById(assignedUserId).exec(); let taskId = req.params.taskId; let task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -162,7 +162,7 @@ api.unassignTask = { let user = res.locals.user; let assignedUserId = req.params.assignedUserId; - let assignedUser = await User.findById(assignedUserId); + let assignedUser = await User.findById(assignedUserId).exec(); let taskId = req.params.taskId; let task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -211,13 +211,13 @@ api.approveTask = { let user = res.locals.user; let assignedUserId = req.params.userId; - let assignedUser = await User.findById(assignedUserId); + let assignedUser = await User.findById(assignedUserId).exec(); let taskId = req.params.taskId; let task = await Tasks.Task.findOne({ 'group.taskId': taskId, userId: assignedUserId, - }); + }).exec(); if (!task) { throw new NotFound(res.t('taskNotFound')); diff --git a/website/server/controllers/top-level/email.js b/website/server/controllers/top-level/email.js index f5dde08d90..c769fe6ccb 100644 --- a/website/server/controllers/top-level/email.js +++ b/website/server/controllers/top-level/email.js @@ -39,15 +39,16 @@ api.unsubscribe = { let userUpdated = await User.update( {_id: data._id}, { $set: {'preferences.emailNotifications.unsubscribeFromAll': true}} - ); + ).exec(); if (userUpdated.nModified !== 1) throw new NotFound(res.t('userNotFound')); res.send(`

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextUsers')}`); } else { - let unsubscribedEmail = await EmailUnsubscription.findOne({email: data.email.toLowerCase()}); - let okResponse = `

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextOthers')}`; + let unsubscribedEmail = await EmailUnsubscription.findOne({email: data.email.toLowerCase()}).exec(); if (!unsubscribedEmail) await EmailUnsubscription.create({email: data.email.toLowerCase()}); + + let okResponse = `

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextOthers')}`; res.send(okResponse); } }, diff --git a/website/server/controllers/top-level/payments/amazon.js b/website/server/controllers/top-level/payments/amazon.js index 0a74b37084..5da9ae1330 100644 --- a/website/server/controllers/top-level/payments/amazon.js +++ b/website/server/controllers/top-level/payments/amazon.js @@ -144,7 +144,7 @@ api.checkout = { if (gift) { if (gift.type === 'subscription') method = 'createSubscription'; - gift.member = await User.findById(gift ? gift.uuid : undefined); + gift.member = await User.findById(gift ? gift.uuid : undefined).exec(); data.gift = gift; data.paymentMethod = 'Amazon Payments (Gift)'; } @@ -184,7 +184,7 @@ api.subscribe = { if (sub.discount) { // apply discount if (!coupon) throw new BadRequest(res.t('couponCodeRequired')); - let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key}); + let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key}).exec(); if (!result) throw new NotAuthorized(res.t('invalidCoupon')); } diff --git a/website/server/controllers/top-level/payments/paypal.js b/website/server/controllers/top-level/payments/paypal.js index 763b79ea5e..908ac1791e 100644 --- a/website/server/controllers/top-level/payments/paypal.js +++ b/website/server/controllers/top-level/payments/paypal.js @@ -134,7 +134,7 @@ api.checkoutSuccess = { delete req.session.gift; if (gift) { - gift.member = await User.findById(gift.uuid); + gift.member = await User.findById(gift.uuid).exec(); if (gift.type === 'subscription') { method = 'createSubscription'; } @@ -168,7 +168,7 @@ api.subscribe = { if (sub.discount) { if (!req.query.coupon) throw new BadRequest(res.t('couponCodeRequired')); - let coupon = await Coupon.findOne({_id: cc.validate(req.query.coupon), event: sub.key}); + let coupon = await Coupon.findOne({_id: cc.validate(req.query.coupon), event: sub.key}).exec(); if (!coupon) throw new NotAuthorized(res.t('invalidCoupon')); } @@ -295,14 +295,18 @@ api.ipn = { await ipnVerifyAsync(req.body); if (req.body.txn_type === 'recurring_payment_profile_cancel' || req.body.txn_type === 'subscr_cancel') { - let user = await User.findOne({ 'purchased.plan.customerId': req.body.recurring_payment_id }); + let user = await User.findOne({ 'purchased.plan.customerId': req.body.recurring_payment_id }).exec(); if (user) { await payments.cancelSubscription({ user, paymentMethod: 'Paypal' }); return; } let groupFields = basicGroupFields.concat(' purchased'); - let group = await Group.findOne({ 'purchased.plan.customerId': req.body.recurring_payment_id }).select(groupFields).exec(); + let group = await Group + .findOne({ 'purchased.plan.customerId': req.body.recurring_payment_id }) + .select(groupFields) + .exec(); + if (group) { await payments.cancelSubscription({ groupId: group._id, paymentMethod: 'Paypal' }); } diff --git a/website/server/controllers/top-level/payments/stripe.js b/website/server/controllers/top-level/payments/stripe.js index c0ba36cd60..50af49ca11 100644 --- a/website/server/controllers/top-level/payments/stripe.js +++ b/website/server/controllers/top-level/payments/stripe.js @@ -58,7 +58,7 @@ api.checkout = { if (sub) { if (sub.discount) { if (!req.query.coupon) throw new BadRequest(res.t('couponCodeRequired')); - coupon = await Coupon.findOne({_id: cc.validate(req.query.coupon), event: sub.key}); + coupon = await Coupon.findOne({_id: cc.validate(req.query.coupon), event: sub.key}).exec(); if (!coupon) throw new BadRequest(res.t('invalidCoupon')); } @@ -114,7 +114,7 @@ api.checkout = { }; if (gift) { - let member = await User.findById(gift.uuid); + let member = await User.findById(gift.uuid).exec(); gift.member = member; if (gift.type === 'subscription') method = 'createSubscription'; data.paymentMethod = 'Stripe (Gift)'; diff --git a/website/server/libs/taskManager.js b/website/server/libs/taskManager.js index 0fbd9f2bfc..ab28509c03 100644 --- a/website/server/libs/taskManager.js +++ b/website/server/libs/taskManager.js @@ -107,6 +107,8 @@ export async function getTasks (req, res, options = {}) { } = options; let query = {userId: user._id}; + let limit; + let sort; let owner = group || challenge || user; if (challenge) { @@ -122,18 +124,21 @@ export async function getTasks (req, res, options = {}) { query.completed = false; // Exclude completed todos query.type = 'todo'; } else if (type === 'completedTodos' || type === '_allCompletedTodos') { // _allCompletedTodos is currently in BETA and is likely to be removed in future - let limit = 30; + limit = 30; if (type === '_allCompletedTodos') { limit = 0; // no limit } - query = Tasks.Task.find({ + + query = { userId: user._id, type: 'todo', completed: true, - }).limit(limit).sort({ + }; + + sort = { dateCompleted: -1, - }); + }; } else { query.type = type.slice(0, -1); // removing the final "s" } @@ -144,7 +149,11 @@ export async function getTasks (req, res, options = {}) { ]; } - let tasks = await Tasks.Task.find(query).exec(); + let mQuery = Tasks.Task.find(query); + if (limit) mQuery.limit(limit); + if (sort) mQuery.sort(sort); + + let tasks = await mQuery.exec(); // Order tasks based on tasksOrder if (type && type !== 'completedTodos' && type !== '_allCompletedTodos') { diff --git a/website/server/models/group.js b/website/server/models/group.js index 88fe3a598f..b41c9deac1 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -461,7 +461,7 @@ schema.methods.startQuest = async function startQuest (user) { let partyId = this._id; let questMembers = this.quest.members; await Bluebird.map(Object.keys(this.quest.members), async (memberId) => { - let member = await User.findOne({_id: memberId, 'party._id': partyId}).select('_id').lean(); + let member = await User.findOne({_id: memberId, 'party._id': partyId}).select('_id').lean().exec(); if (!member) { delete questMembers[memberId]; @@ -553,7 +553,7 @@ schema.methods.sendGroupChatReceivedWebhooks = function sendGroupChatReceivedWeb query.guilds = this._id; } - User.find(query).select({webhooks: 1}).lean().then((users) => { + User.find(query).select({webhooks: 1}).lean().exec().then((users) => { users.forEach((user) => { let { webhooks } = user; groupChatReceivedWebhook.send(webhooks, { @@ -797,7 +797,7 @@ schema.statics.processQuestProgress = async function processQuestProgress (user, }); }; -// to set a boss: `db.groups.update({_id:TAVERN_ID},{$set:{quest:{key:'dilatory',active:true,progress:{hp:1000,rage:1500}}}})` +// to set a boss: `db.groups.update({_id:TAVERN_ID},{$set:{quest:{key:'dilatory',active:true,progress:{hp:1000,rage:1500}}}}).exec()` // we export an empty object that is then populated with the query-returned data export let tavernQuest = {}; let tavernQ = {_id: TAVERN_ID, 'quest.key': {$ne: null}}; @@ -891,7 +891,7 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') { let challenges = await Challenge.find({ _id: {$in: user.challenges}, group: group._id, - }); + }).exec(); let challengesToRemoveUserFrom = challenges.map(chal => { return chal.unlinkTasks(user, keep); @@ -903,7 +903,7 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') { 'group.id': group._id, userId: {$exists: false}, 'group.assignedUsers': user._id, - }); + }).exec(); let assignedTasksToRemoveUserFrom = assignedTasks.map(task => { return this.unlinkTask(task, user, keep); });