From 3364019fcc729aed61b457003f28dc7806d0db3c Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 29 Apr 2016 11:49:12 +0200 Subject: [PATCH] v3 and adapted v2: bugs fixes for groups, challenges and tasks --- common/script/fns/randomDrop.js | 2 +- website/src/controllers/api-v2/challenges.js | 7 ++-- website/src/controllers/api-v2/user.js | 9 ++++- website/src/controllers/api-v3/user.js | 22 ++++++++++-- website/src/models/group.js | 36 ++++++++++---------- 5 files changed, 51 insertions(+), 25 deletions(-) diff --git a/common/script/fns/randomDrop.js b/common/script/fns/randomDrop.js index 3d1114676a..102709da57 100644 --- a/common/script/fns/randomDrop.js +++ b/common/script/fns/randomDrop.js @@ -3,7 +3,7 @@ import content from '../content/index'; import i18n from '../i18n'; import { daysSince } from '../cron'; import { diminishingReturns } from '../statHelpers'; -import { predictableRandom } from './predictableRandom'; +import predictableRandom from './predictableRandom'; import randomVal from './randomVal'; // Clone a drop object maintaining its functions so that we can change it without affecting the original item diff --git a/website/src/controllers/api-v2/challenges.js b/website/src/controllers/api-v2/challenges.js index 605e3424cf..51f57433c7 100644 --- a/website/src/controllers/api-v2/challenges.js +++ b/website/src/controllers/api-v2/challenges.js @@ -52,7 +52,9 @@ api.list = async function(req, res, next) { let obj = challenge.toJSON(); obj._isMember = user.challenges.indexOf(challenge._id) !== -1; + return obj; }); + // TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 await Q.all(resChals.map((chal, index) => { return Q.all([ @@ -195,7 +197,8 @@ api.create = async function(req, res, next){ req.body.rewards = req.body.rewards || []; var chalTasks = req.body.habits.concat(req.body.rewards) - .concat(req.body.dailys).concat(req.body.todos); + .concat(req.body.dailys).concat(req.body.todos) + .map(v2Task => Tasks.Task.fromJSONV2(v2Task)); chalTasks = chalTasks.map(function(task) { var newTask = new Tasks[task.type](Tasks.Task.sanitize(task)); @@ -318,7 +321,7 @@ api.selectWinner = async function(req, res, next) { if (!challenge) return next('Challenge ' + req.params.cid + ' not found'); if (!challenge.canModify(res.locals.user)) return next(shared.i18n.t('noPermissionCloseChallenge')); - let winner = await User.findOne({_id: req.params.uid}).exec(); + let winner = await User.findOne({_id: req.query.uid}).exec(); if (!winner || winner.challenges.indexOf(challenge._id) === -1) return next('Winner ' + req.query.uid + ' not found.'); // Close channel in background, some ops are run in the background without `await`ing diff --git a/website/src/controllers/api-v2/user.js b/website/src/controllers/api-v2/user.js index c11c371c01..d0430c6a80 100644 --- a/website/src/controllers/api-v2/user.js +++ b/website/src/controllers/api-v2/user.js @@ -676,7 +676,14 @@ api.cast = async function(req, res, next) { if (!partyMembers) throw new NotFound(res.t('userWithIDNotFound', {userId: targetId})); spell.cast(user, partyMembers, req); - await partyMembers.save(); + if (partyMembers === user) { + await partyMembers.save(); + } else { + await Q.all([ + await partyMembers.save(), + await user.save(), + ]); + } } if (party && !spell.silent) { diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index f76c785369..a1e34ad435 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -350,7 +350,15 @@ api.castSpell = { if (task.challenge.id) throw new BadRequest(res.t('challengeTasksNoCast')); spell.cast(user, task, req); - await task.save(); + if (user.isModified()) { + await Q.all([ + user.save(), + task.save(), + ]); + } else { + await task.save(); + } + res.respond(200, task); } else if (targetType === 'self') { spell.cast(user, null, req); @@ -370,7 +378,8 @@ api.castSpell = { let toSave = tasks.filter(t => t.isModified()); let isUserModified = user.isModified(); - toSave.unshift(user.save()); + + if (isUserModified) toSave.unshift(user.save()); let saved = await Q.all(toSave); let response = { @@ -403,7 +412,14 @@ api.castSpell = { if (!partyMembers) throw new NotFound(res.t('userWithIDNotFound', {userId: targetId})); spell.cast(user, partyMembers, req); - await partyMembers.save(); + if (user.isModified()) { + await Q.all([ + user.save(), + partyMembers.save(), + ]); + } else { + await partyMembers.save(); + } } res.respond(200, partyMembers); diff --git a/website/src/models/group.js b/website/src/models/group.js index ac9abd13fc..846a018a16 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -631,32 +631,32 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all') { let promises = []; - // If user is the last one in group and group is private, delete it - if (group.memberCount <= 1 && group.privacy === 'private') { - return await group.remove(); - } - - // otherwise just remove a member TODO create User.methods.removeFromGroup? + // remove the group from the user's groups if (group.type === 'guild') { promises.push(User.update({_id: user._id}, {$pull: {guilds: group._id}}).exec()); } else { promises.push(User.update({_id: user._id}, {$set: {party: {}}}).exec()); } - // If the leader is leaving (or if the leader previously left, and this wasn't accounted for) - let update = { - $inc: {memberCount: -1}, - }; + // If user is the last one in group and group is private, delete it + if (group.memberCount <= 1 && group.privacy === 'private') { + return await group.remove(); + } else { // otherwise If the leader is leaving (or if the leader previously left, and this wasn't accounted for) + let update = { + $inc: {memberCount: -1}, + }; - if (group.leader === user._id) { - let query = group.type === 'party' ? {'party._id': group._id} : {guilds: group._id}; - query._id = {$ne: user._id}; - let seniorMember = await User.findOne(query).select('_id').exec(); + if (group.leader === user._id) { + let query = group.type === 'party' ? {'party._id': group._id} : {guilds: group._id}; + query._id = {$ne: user._id}; + let seniorMember = await User.findOne(query).select('_id').exec(); - // could be missing in case of public guild (that can have 0 members) with 1 member who is leaving - if (seniorMember) update.$set = {leader: seniorMember._id}; + // could be missing in case of public guild (that can have 0 members) with 1 member who is leaving + if (seniorMember) update.$set = {leader: seniorMember._id}; + } + promises.push(group.update(update).exec()); } - promises.push(group.update(update).exec()); + firebase.removeUserFromGroup(group._id, user._id); return Q.all(promises); @@ -730,7 +730,7 @@ if (!nconf.get('IS_TEST')) { new model({ // eslint-disable-line babel/new-cap _id: TAVERN_ID, leader: '7bde7864-ebc5-4ee2-a4b7-1070d464cdb0', // Siena Leslie - name: 'HabitRPG', + name: 'Tavern', type: 'guild', privacy: 'public', }).save();