finish porting to async/away syntax

This commit is contained in:
Matteo Pagliazzi
2015-12-31 11:46:21 +01:00
parent f76c9d025f
commit aebe2fa400
7 changed files with 560 additions and 652 deletions

View File

@@ -56,7 +56,7 @@ api.registerLocal = {
let lowerCaseUsername = username.toLowerCase();
// Search for duplicates using lowercase version of username
let user = User.findOne({$or: [
let user = await User.findOne({$or: [
{'auth.local.email': email},
{'auth.local.lowerCaseUsername': lowerCaseUsername},
]}, {'auth.local': 1}).exec();

View File

@@ -27,19 +27,18 @@ api.createChallenge = {
method: 'POST',
url: '/challenges',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkBody('group', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let groupId = req.body.group;
let prize = req.body.prize;
Group.getGroup(user, groupId, '-chat')
.then(group => {
let group = await Group.getGroup(user, groupId, '-chat');
if (!group) throw new NotFound(res.t('groupNotFound'));
if (group.leaderOnly && group.leaderOnly.challenges && group.leader !== user._id) {
@@ -88,14 +87,12 @@ api.createChallenge = {
});
toSave.unshift(challenge, group);
return Q.all(toSave);
})
.then(results => {
let results = await Q.all(toSave);
let savedChal = results[0];
return savedChal.syncToUser(user) // (it also saves the user)
.then(() => res.respond(201, savedChal));
})
.catch(next);
await savedChal.syncToUser(user); // (it also saves the user)
res.respond(201, savedChal);
},
};
@@ -111,14 +108,14 @@ api.getChallenges = {
method: 'GET',
url: '/challenges',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let groups = user.guilds || [];
if (user.party._id) groups.push(user.party._id);
groups.push('habitrpg'); // Public challenges
Challenge.find({
let challenges = await Challenge.find({
$or: [
{_id: {$in: user.challenges}}, // Challenges where the user is participating
{group: {$in: groups}}, // Challenges in groups where I'm a member
@@ -130,11 +127,9 @@ api.getChallenges = {
// TODO populate
// .populate('group', '_id name type')
// .populate('leader', 'profile.name')
.exec()
.then(challenges => {
.exec();
res.respond(200, challenges);
})
.catch(next);
},
};
@@ -190,7 +185,7 @@ function _closeChal (challenge, broken = {}) {
}));
}
return Q.allSettled(tasks); // TODO look if allSettle could be useful somewhere else
return Q.allSettled(tasks); // TODO look if allSettled could be useful somewhere else
// TODO catch and handle
}
@@ -206,25 +201,21 @@ api.deleteChallenge = {
method: 'DELETE',
url: '/challenges/:challengeId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('challenge', res.t('challengeIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Challenge.findOne({_id: req.params.challengeId})
.exec()
.then(challenge => {
let challenge = await Challenge.findOne({_id: req.params.challengeId}).exec();
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
res.respond(200, {});
// Close channel in background
_closeChal(challenge, {broken: 'CHALLENGE_DELETED'});
})
.catch(next);
},
};
@@ -240,34 +231,25 @@ api.selectChallengeWinner = {
method: 'POST',
url: '/challenges/:challengeId/selectWinner/:winnerId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let challenge;
req.checkParams('challenge', res.t('challengeIdRequired')).notEmpty().isUUID();
req.checkParams('winnerId', res.t('winnerIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Challenge.findOne({_id: req.params.challengeId})
.exec()
.then(challengeFound => {
let challenge = await Challenge.findOne({_id: req.params.challengeId}).exec();
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
challenge = challengeFound;
return User.findOne({_id: req.params.winnerId}).exec();
})
.then(winner => {
let winner = await User.findOne({_id: req.params.winnerId}).exec();
if (!winner || winner.challenges.indexOf(challenge._id) === -1) throw new NotFound(res.t('winnerNotFound', {userId: req.parama.winnerId}));
res.respond(200, {});
// Close channel in background
_closeChal(challenge, {broken: 'CHALLENGE_DELETED', winner});
})
.catch(next);
},
};

View File

@@ -25,21 +25,18 @@ api.getChat = {
method: 'GET',
url: '/groups/:groupId/chat',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId, 'chat')
.then(group => {
let group = await Group.getGroup(user, req.params.groupId, 'chat');
if (!group) throw new NotFound(res.t('groupNotFound'));
res.respond(200, group.chat);
})
.catch(next);
},
};
@@ -59,7 +56,7 @@ api.postChat = {
method: 'POST',
url: '/groups/:groupId/chat',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
let chatUpdated;
@@ -68,10 +65,10 @@ api.postChat = {
req.checkBody('message', res.t('messageGroupChatBlankMessage')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let group = await Group.getGroup(user, groupId);
Group.getGroup(user, groupId)
.then((group) => {
if (!group) throw new NotFound(res.t('groupNotFound'));
if (group.type !== 'party' && user.flags.chatRevoked) {
throw new NotFound('Your chat privileges have been revoked.');
@@ -84,18 +81,15 @@ api.postChat = {
if (group.type === 'party') {
user.party.lastMessageSeen = group.chat[0].id;
user.save();
user.save(); // TODO why this is non-blocking? must catch?
}
return group.save();
})
.then((group) => {
let savedGroup = await group.save();
if (chatUpdated) {
res.respond(200, {chat: group.chat});
res.respond(200, {chat: savedGroup.chat});
} else {
res.respond(200, {message: group.chat[0]});
res.respond(200, {message: savedGroup.chat[0]});
}
})
.catch(next);
},
};
@@ -114,23 +108,21 @@ api.likeChat = {
method: 'Post',
url: '/groups/:groupId/chat/:chatId/like',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
let message;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
req.checkParams('chatId', res.t('chatIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, groupId)
.then((group) => {
let group = await Group.getGroup(user, groupId);
if (!group) throw new NotFound(res.t('groupNotFound'));
message = _.find(group.chat, {id: req.params.chatId});
if (!message) throw new NotFound(res.t('messageGroupChatNotFound'));
let message = _.find(group.chat, {id: req.params.chatId});
if (!message) throw new NotFound(res.t('messageGroupChatNotFound'));
if (message.uuid === user._id) throw new NotFound(res.t('messageGroupChatLikeOwnMessage'));
let update = {$set: {}};
@@ -140,16 +132,11 @@ api.likeChat = {
message.likes[user._id] = !message.likes[user._id];
update.$set[`chat.$.likes.${user._id}`] = message.likes[user._id];
return Group.update(
await Group.update(
{_id: group._id, 'chat.id': message.id},
update
);
})
.then((groupSaved) => {
if (!groupSaved) throw new NotFound(res.t('groupNotFound'));
res.respond(200, message);
})
.catch(next);
},
};
@@ -168,33 +155,25 @@ api.flagChat = {
method: 'Post',
url: '/groups/:groupId/chat/:chatId/flag',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
let message;
let group;
let author;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
req.checkParams('chatId', res.t('chatIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, groupId)
.then((groupFound) => {
if (!groupFound) throw new NotFound(res.t('groupNotFound'));
group = groupFound;
message = _.find(group.chat, {id: req.params.chatId});
let group = await Group.getGroup(user, groupId);
if (!group) throw new NotFound(res.t('groupNotFound'));
let message = _.find(group.chat, {id: req.params.chatId});
if (!message) throw new NotFound(res.t('messageGroupChatNotFound'));
if (message.uuid === user._id) throw new NotFound(res.t('messageGroupChatFlagOwnMessage'));
return User.findOne({_id: message.uuid}, {auth: 1});
})
.then((foundAuthor) => {
author = foundAuthor;
let author = await User.findOne({_id: message.uuid}, {auth: 1});
let update = {$set: {}};
@@ -214,13 +193,10 @@ api.flagChat = {
}
update.$set['chat.$.flagCount'] = message.flagCount;
return Group.update(
await Group.update(
{_id: group._id, 'chat.id': message.id},
update
);
})
.then((group2) => {
if (!group2) throw new NotFound(res.t('groupNotFound'));
let addressesToSendTo = nconf.get('FLAG_REPORT_EMAIL');
addressesToSendTo = typeof addressesToSendTo === 'string' ? JSON.parse(addressesToSendTo) : addressesToSendTo;
@@ -275,9 +251,8 @@ api.flagChat = {
{name: 'GROUP_ID', content: group._id},
{name: 'GROUP_URL', content: groupUrl},
]);
res.respond(200, message);
})
.catch(next);
},
};

View File

@@ -29,36 +29,31 @@ api.createGroup = {
method: 'POST',
url: '/groups',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let group = new Group(Group.sanitize(req.body)); // TODO validate empty req.body
group.leader = user._id;
if (group.type === 'guild') {
if (user.balance < 1) return next(new NotAuthorized(res.t('messageInsufficientGems')));
if (user.balance < 1) throw new NotAuthorized(res.t('messageInsufficientGems'));
group.balance = 1;
user.balance--;
user.guilds.push(group._id);
} else {
if (user.party._id) return next(new NotAuthorized(res.t('messageGroupAlreadyInParty')));
if (user.party._id) throw new NotAuthorized(res.t('messageGroupAlreadyInParty'));
user.party._id = group._id;
}
Q.all([
user.save(),
group.save(),
]).then(results => {
let results = await Q.all([user.save(), group.save()]);
let savedGroup = results[1];
firebase.updateGroupData(savedGroup);
firebase.addUserToGroup(savedGroup._id, user._id);
return res.respond(201, savedGroup); // TODO populate
})
.catch(next);
},
};
@@ -76,13 +71,13 @@ api.getGroups = {
method: 'GET',
url: '/groups',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkQuery('type', res.t('groupTypesRequired')).notEmpty(); // TODO better validation
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
// TODO validate types are acceptable? probably not necessary
let types = req.query.type.split(',');
@@ -115,16 +110,14 @@ api.getGroups = {
});
// If no valid value for type was supplied, return an error
if (queries.length === 0) return next(new BadRequest(res.t('groupTypesRequired')));
if (queries.length === 0) throw new BadRequest(res.t('groupTypesRequired'));
let results = await Q.all(queries); // TODO we would like not to return a single big array but Q doesn't support the funtionality https://github.com/kriskowal/q/issues/328
Q.all(queries) // TODO we would like not to return a single big array but Q doesn't support the funtionality https://github.com/kriskowal/q/issues/328
.then(results => {
res.respond(200, _.reduce(results, (m, v) => {
if (_.isEmpty(v)) return m;
return m.concat(Array.isArray(v) ? v : [v]);
}, []));
})
.catch(next);
},
};
@@ -142,21 +135,18 @@ api.getGroup = {
method: 'GET',
url: '/groups/:groupId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId)
.then(group => {
let group = await Group.getGroup(user, req.params.groupId);
if (!group) throw new NotFound(res.t('groupNotFound'));
res.respond(200, group);
})
.catch(next);
},
};
@@ -174,28 +164,24 @@ api.updateGroup = {
method: 'PUT',
url: '/groups/:groupId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId)
.then(group => {
let group = await Group.getGroup(user, req.params.groupId);
if (!group) throw new NotFound(res.t('groupNotFound'));
if (group.leader !== user._id) throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
_.assign(group, _.merge(group.toObject(), Group.sanitizeUpdate(req.body)));
return group.save();
}).then(savedGroup => {
let savedGroup = await group.save();
res.respond(200, savedGroup);
firebase.updateGroupData(savedGroup);
})
.catch(next);
},
};
@@ -213,16 +199,15 @@ api.joinGroup = {
method: 'POST',
url: '/groups/:groupId/join',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId, '-chat', true) // Do not fetch chat and work even if the user is not yet a member of the group
.then(group => {
let group = await Group.getGroup(user, req.params.groupId, '-chat', true); // Do not fetch chat and work even if the user is not yet a member of the group
if (!group) throw new NotFound(res.t('groupNotFound'));
let isUserInvited = false;
@@ -257,16 +242,14 @@ api.joinGroup = {
if (group.memberCount === 0) group.leader = user._id; // If new user is only member -> set as leader
Q.all([
await Q.all([
group.save(),
user.save(),
User.update({_id: user.invitations.party.inviter}, {$inc: {'items.quests.basilist': 1}}).exec(), // Reward inviter
]).then(() => {
]);
firebase.addUserToGroup(group._id, user._id);
res.respond(200, {}); // TODO what to return?
});
})
.catch(next);
},
};
@@ -285,7 +268,7 @@ api.leaveGroup = {
method: 'POST',
url: '/groups/:groupId/leave',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
@@ -293,10 +276,9 @@ api.leaveGroup = {
req.checkQuery('keep', res.t('keepOrRemoveAll')).optional().isIn(['keep-all', 'remove-all']);
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId, '-chat') // Do not fetch chat
.then(group => {
let group = await Group.getGroup(user, req.params.groupId, '-chat'); // Do not fetch chat
if (!group) throw new NotFound(res.t('groupNotFound'));
// During quests, checke wheter user can leave
@@ -310,10 +292,8 @@ api.leaveGroup = {
}
}
return group.leave(user, req.query.keep);
})
.then(() => res.respond(200, {}))
.catch(next);
await group.leave(user, req.query.keep);
res.respond(200, {});
},
};
@@ -345,19 +325,16 @@ api.removeGroupMember = {
method: 'POST',
url: '/groups/:groupId/removeMember/:memberId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
let group;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
req.checkParams('memberId', res.t('userIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId, '-chat') // Do not fetch chat
.then(foundGroup => {
group = foundGroup;
let group = await Group.getGroup(user, req.params.groupId, '-chat'); // Do not fetch chat
if (!group) throw new NotFound(res.t('groupNotFound'));
let uuid = req.query.memberId;
@@ -365,8 +342,7 @@ api.removeGroupMember = {
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyLeaderCanRemoveMember'));
if (user._id === uuid) throw new NotAuthorized(res.t('memberCannotRemoveYourself'));
return User.findOne({_id: uuid}).select('party guilds invitations newMessages').exec();
}).then(member => {
let member = await User.findOne({_id: uuid}).select('party guilds invitations newMessages').exec();
// We're removing the user from a guild or a party? is the user invited only?
let isInGroup = member.party._id === group._id ? 'party' : member.guilds.indexOf(group._id) !== 1 ? 'guild' : undefined; // eslint-disable-line no-nested-ternary
let isInvited = member.invitations.party.id === group._id ? 'party' : _.findIndex(member.invitations.guilds, {id: group._id}) !== 1 ? 'guild' : undefined; // eslint-disable-line no-nested-ternary
@@ -403,13 +379,11 @@ api.removeGroupMember = {
let message = req.query.message;
if (message) _sendMessageToRemoved(group, member, message);
return Q.all([
await Q.all([
member.save(),
group.save(),
]);
})
.then(() => res.respond(200, {}))
.catch(next);
res.respond(200, {});
},
};
@@ -571,16 +545,15 @@ api.inviteToGroup = {
method: 'POST',
url: '/groups/:groupId/invite',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Group.getGroup(user, req.params.groupId, '-chat') // Do not fetch chat TODO other fields too?
.then(group => {
let group = await Group.getGroup(user, req.params.groupId, '-chat'); // Do not fetch chat TODO other fields too?
if (!group) throw new NotFound(res.t('groupNotFound'));
let uuids = req.body.uuids;
@@ -595,8 +568,6 @@ api.inviteToGroup = {
} else {
throw new BadRequest(res.t('canOnlyInviteEmailUuid'));
}
})
.catch(next);
},
};

View File

@@ -20,18 +20,15 @@ api.createTag = {
method: 'POST',
url: '/tags',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
user.tags.push(Tag.sanitize(req.body));
let savedUser = await user.save();
user.save()
.then((savedUser) => {
let l = savedUser.tags.length;
let tag = savedUser.tags[l - 1];
res.respond(201, tag);
})
.catch(next);
},
};
@@ -47,7 +44,7 @@ api.getTags = {
method: 'GET',
url: '/tags',
middlewares: [authWithHeaders(), cron],
handler (req, res) {
async handler (req, res) {
let user = res.locals.user;
res.respond(200, user.tags);
},
@@ -67,16 +64,16 @@ api.getTag = {
method: 'GET',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let tag = user.tags.id(req.params.tagId);
if (!tag) return next(new NotFound(res.t('tagNotFound')));
if (!tag) throw new NotFound(res.t('tagNotFound'));
res.respond(200, tag);
},
};
@@ -95,7 +92,7 @@ api.updateTag = {
method: 'PUT',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID();
@@ -104,16 +101,15 @@ api.updateTag = {
let tagId = req.params.tagId;
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let tag = user.tags.id(tagId);
if (!tag) return next(new NotFound(res.t('tagNotFound')));
if (!tag) throw new NotFound(res.t('tagNotFound'));
_.merge(tag, Tag.sanitize(req.body));
user.save()
.then((savedUser) => res.respond(200, savedUser.tags.id(tagId)))
.catch(next);
let savedUser = await user.save();
res.respond(200, savedUser.tags.id(tagId));
},
};
@@ -131,21 +127,20 @@ api.deleteTag = {
method: 'DELETE',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let tag = user.tags.id(req.params.tagId);
if (!tag) return next(new NotFound(res.t('tagNotFound')));
if (!tag) throw new NotFound(res.t('tagNotFound'));
tag.remove();
user.save()
.then(() => res.respond(200, {}))
.catch(next);
await user.save();
res.respond(200, {});
},
};

View File

@@ -29,11 +29,11 @@ api.createTask = {
method: 'POST',
url: '/tasks',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
req.checkBody('type', res.t('invalidTaskType')).notEmpty().isIn(Tasks.tasksTypes);
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let user = res.locals.user;
let taskType = req.body.type;
@@ -43,12 +43,12 @@ api.createTask = {
user.tasksOrder[`${taskType}s`].unshift(newTask._id);
Q.all([
let results = await Q.all([
newTask.save(),
user.save(),
])
.then((results) => res.respond(201, results[0]))
.catch(next);
]);
res.respond(201, results[0]);
},
};
@@ -67,11 +67,11 @@ api.getTasks = {
method: 'GET',
url: '/tasks',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
req.checkQuery('type', res.t('invalidTaskType')).optional().isIn(Tasks.tasksTypes);
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let user = res.locals.user;
let query = {userId: user._id};
@@ -95,16 +95,15 @@ api.getTasks = {
dateCompleted: 1,
});
Q.all([
let results = await Q.all([
queryCompleted.exec(),
Tasks.Task.find(query).exec(),
])
.then((results) => res.respond(200, results[1].concat(results[0])))
.catch(next);
]);
res.respond(200, results[1].concat(results[0]));
} else {
Tasks.Task.find(query).exec()
.then((tasks) => res.respond(200, tasks))
.catch(next);
let tasks = await Tasks.Task.find(query).exec();
res.respond(200, tasks);
}
},
};
@@ -123,23 +122,21 @@ api.getTask = {
method: 'GET',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
res.respond(200, task);
})
.catch(next);
},
};
@@ -157,7 +154,7 @@ api.updateTask = {
method: 'PUT',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
@@ -165,13 +162,13 @@ api.updateTask = {
// TODO make sure tags are updated correctly (they aren't set as modified!) maybe use specific routes
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
// If checklist is updated -> replace the original one
@@ -192,10 +189,9 @@ api.updateTask = {
// TODO console.log(task.modifiedPaths(), task.toObject().repeat === tep)
// repeat is always among modifiedPaths because mongoose changes the other of the keys when using .toObject()
// see https://github.com/Automattic/mongoose/issues/2749
return task.save();
})
.then((savedTask) => res.respond(200, savedTask))
.catch(next);
let savedTask = await task.save();
res.respond(200, savedTask);
},
};
@@ -239,21 +235,21 @@ api.scoreTask = {
method: 'POST',
url: '/tasks/:taskId/score/:direction',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('direction', res.t('directionUpDown')).notEmpty().isIn(['up', 'down']); // TODO what about rewards? maybe separate route?
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let user = res.locals.user;
let direction = req.params.direction;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
let wasCompleted = task.completed;
@@ -281,10 +277,11 @@ api.scoreTask = {
}
}
return Q.all([
let results = await Q.all([
user.save(),
task.save(),
]).then((results) => {
]);
let savedUser = results[0];
let userStats = savedUser.stats.toJSON();
@@ -295,10 +292,12 @@ api.scoreTask = {
// TODO test?
if (task.challenge.id && task.challenge.taskId && !task.challenge.broken && task.type !== 'reward') {
Tasks.Task.findOne({
// Wrapping everything in a try/catch block because if an error occurs using `await` it MUST NOT bubble up because the request has already been handled
try {
let chalTask = await Tasks.Task.findOne({
_id: task.challenge.taskId,
}).exec()
.then(chalTask => {
}).exec();
chalTask.value += delta;
if (chalTask.type === 'habit' || chalTask.type === 'daily') {
chalTask.history.push({value: chalTask.value, date: Number(new Date())});
@@ -307,13 +306,11 @@ api.scoreTask = {
chalTask.markModified('history');
}
return chalTask.save();
});
// .catch(next) TODO what to do here
await chalTask.save();
} catch (e) {
// TODO handle
}
}
});
})
.catch(next);
},
};
@@ -334,21 +331,21 @@ api.moveTask = {
method: 'POST',
url: '/tasks/move/:taskId/to/:position',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('position', res.t('positionRequired')).notEmpty().isNumeric();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
let user = res.locals.user;
let to = Number(req.params.position);
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.type === 'todo' && task.completed) throw new NotFound(res.t('cantMoveCompletedTodo'));
let order = user.tasksOrder[`${task.type}s`];
@@ -365,10 +362,8 @@ api.moveTask = {
order.splice(to, 0, taskToMove);
}
return user.save();
})
.then(() => res.respond(200, {})) // TODO what to return
.catch(next);
await user.save();
res.respond(200, {}); // TODO what to return
},
};
@@ -386,28 +381,27 @@ api.addChecklistItem = {
method: 'POST',
url: '/tasks/:taskId/checklist',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
// TODO check that req.body isn't empty and is an array
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
task.checklist.push(Tasks.Task.sanitizeChecklist(req.body));
return task.save();
})
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
.catch(next);
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
},
};
@@ -426,20 +420,20 @@ api.scoreCheckListItem = {
method: 'POST',
url: '/tasks/:taskId/checklist/:itemId/score',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
@@ -447,10 +441,9 @@ api.scoreCheckListItem = {
if (!item) throw new NotFound(res.t('checklistItemNotFound'));
item.completed = !item.completed;
return task.save();
})
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
.catch(next);
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
},
};
@@ -469,20 +462,20 @@ api.updateChecklistItem = {
method: 'PUT',
url: '/tasks/:taskId/checklist/:itemId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
@@ -490,10 +483,9 @@ api.updateChecklistItem = {
if (!item) throw new NotFound(res.t('checklistItemNotFound'));
_.merge(item, Tasks.Task.sanitizeChecklist(req.body));
return task.save();
})
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
.catch(next);
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
},
};
@@ -512,20 +504,20 @@ api.removeChecklistItem = {
method: 'DELETE',
url: '/tasks/:taskId/checklist/:itemId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
@@ -533,10 +525,9 @@ api.removeChecklistItem = {
if (itemI === -1) throw new NotFound(res.t('checklistItemNotFound'));
task.checklist.splice(itemI, 1);
return task.save();
})
.then(() => res.respond(200, {})) // TODO what to return
.catch(next);
await task.save();
res.respond(200, {}); // TODO what to return
},
};
@@ -555,7 +546,7 @@ api.addTagToTask = {
method: 'POST',
url: '/tasks/:taskId/tags/:tagId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
@@ -563,13 +554,13 @@ api.addTagToTask = {
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID().isIn(userTags);
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
let tagId = req.params.tagId;
@@ -577,10 +568,9 @@ api.addTagToTask = {
if (alreadyTagged) throw new BadRequest(res.t('alreadyTagged'));
task.tags.push(tagId);
return task.save();
})
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
.catch(next);
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
},
};
@@ -599,30 +589,29 @@ api.removeTagFromTask = {
method: 'DELETE',
url: '/tasks/:taskId/tags/:tagId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
let tagI = task.tags.indexOf(req.params.tagId);
if (tagI === -1) throw new NotFound(res.t('tagNotFound'));
task.tags.splice(tagI, 1);
return task.save();
})
.then(() => res.respond(200, {})) // TODO what to return
.catch(next);
await task.save();
res.respond(200, {}); // TODO what to return
},
};
@@ -656,30 +645,26 @@ api.deleteTask = {
method: 'DELETE',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
handler (req, res, next) {
async handler (req, res) {
let user = res.locals.user;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
let validationErrors = req.validationErrors();
if (validationErrors) return next(validationErrors);
if (validationErrors) throw validationErrors;
Tasks.Task.findOne({
let task = await Tasks.Task.findOne({
_id: req.params.taskId,
userId: user._id,
}).exec()
.then((task) => {
}).exec();
if (!task) throw new NotFound(res.t('taskNotFound'));
if (task.challenge.id) throw new NotAuthorized(res.t('cantDeleteChallengeTasks'));
_removeTaskTasksOrder(user, req.params.taskId);
return Q.all([
user.save(),
task.remove(),
]);
})
.then(() => res.respond(200, {}))
.catch(next);
await Q.all([user.save(), task.remove()]);
res.respond(200, {});
},
};

View File

@@ -16,7 +16,7 @@ api.getUser = {
method: 'GET',
middlewares: [authWithHeaders(), cron],
url: '/user',
handler (req, res) {
async handler (req, res) {
let user = res.locals.user.toJSON();
// Remove apiToken from resonse TODO make it priavte at the user level? returned in signup/login