mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
finish porting to async/away syntax
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -27,75 +27,72 @@ 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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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) {
|
||||
throw new NotAuthorized(res.t('onlyGroupLeaderChal'));
|
||||
if (group.leaderOnly && group.leaderOnly.challenges && group.leader !== user._id) {
|
||||
throw new NotAuthorized(res.t('onlyGroupLeaderChal'));
|
||||
}
|
||||
|
||||
if (groupId === 'habitrpg' && prize < 1) {
|
||||
throw new NotAuthorized(res.t('pubChalsMinPrize'));
|
||||
}
|
||||
|
||||
if (prize > 0) {
|
||||
let groupBalance = group.balance && group.leader === user._id ? group.balance : 0;
|
||||
let prizeCost = prize / 4;
|
||||
|
||||
if (prizeCost > user.balance + groupBalance) {
|
||||
throw new NotAuthorized(res.t('cantAfford'));
|
||||
}
|
||||
|
||||
if (groupId === 'habitrpg' && prize < 1) {
|
||||
throw new NotAuthorized(res.t('pubChalsMinPrize'));
|
||||
if (groupBalance >= prizeCost) {
|
||||
// Group pays for all of prize
|
||||
group.balance -= prizeCost;
|
||||
} else if (groupBalance > 0) {
|
||||
// User pays remainder of prize cost after group
|
||||
let remainder = prizeCost - group.balance;
|
||||
group.balance = 0;
|
||||
user.balance -= remainder;
|
||||
} else {
|
||||
// User pays for all of prize
|
||||
user.balance -= prizeCost;
|
||||
}
|
||||
}
|
||||
|
||||
if (prize > 0) {
|
||||
let groupBalance = group.balance && group.leader === user._id ? group.balance : 0;
|
||||
let prizeCost = prize / 4;
|
||||
group.challengeCount += 1;
|
||||
|
||||
if (prizeCost > user.balance + groupBalance) {
|
||||
throw new NotAuthorized(res.t('cantAfford'));
|
||||
}
|
||||
let tasks = req.body.tasks || []; // TODO validate
|
||||
req.body.leader = user._id;
|
||||
req.body.official = user.contributor.admin && req.body.official;
|
||||
let challenge = new Challenge(Challenge.sanitize(req.body));
|
||||
|
||||
if (groupBalance >= prizeCost) {
|
||||
// Group pays for all of prize
|
||||
group.balance -= prizeCost;
|
||||
} else if (groupBalance > 0) {
|
||||
// User pays remainder of prize cost after group
|
||||
let remainder = prizeCost - group.balance;
|
||||
group.balance = 0;
|
||||
user.balance -= remainder;
|
||||
} else {
|
||||
// User pays for all of prize
|
||||
user.balance -= prizeCost;
|
||||
}
|
||||
}
|
||||
let toSave = tasks.map(tasks, taskToCreate => {
|
||||
// TODO validate type
|
||||
let task = new Tasks[taskToCreate.type](Tasks.Task.sanitizeCreate(taskToCreate));
|
||||
task.challenge.id = challenge._id;
|
||||
challenge.tasksOrder[`${task.type}s`].push(task._id);
|
||||
return task.save();
|
||||
});
|
||||
|
||||
group.challengeCount += 1;
|
||||
toSave.unshift(challenge, group);
|
||||
|
||||
let tasks = req.body.tasks || []; // TODO validate
|
||||
req.body.leader = user._id;
|
||||
req.body.official = user.contributor.admin && req.body.official;
|
||||
let challenge = new Challenge(Challenge.sanitize(req.body));
|
||||
let results = await Q.all(toSave);
|
||||
let savedChal = results[0];
|
||||
|
||||
let toSave = tasks.map(tasks, taskToCreate => {
|
||||
// TODO validate type
|
||||
let task = new Tasks[taskToCreate.type](Tasks.Task.sanitizeCreate(taskToCreate));
|
||||
task.challenge.id = challenge._id;
|
||||
challenge.tasksOrder[`${task.type}s`].push(task._id);
|
||||
return task.save();
|
||||
});
|
||||
|
||||
toSave.unshift(challenge, group);
|
||||
return Q.all(toSave);
|
||||
})
|
||||
.then(results => {
|
||||
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 => {
|
||||
res.respond(200, challenges);
|
||||
})
|
||||
.catch(next);
|
||||
.exec();
|
||||
|
||||
res.respond(200, challenges);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 => {
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
|
||||
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);
|
||||
res.respond(200, {});
|
||||
// Close channel in background
|
||||
_closeChal(challenge, {broken: 'CHALLENGE_DELETED'});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 => {
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
|
||||
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;
|
||||
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}));
|
||||
|
||||
return User.findOne({_id: req.params.winnerId}).exec();
|
||||
})
|
||||
.then(winner => {
|
||||
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);
|
||||
res.respond(200, {});
|
||||
// Close channel in background
|
||||
_closeChal(challenge, {broken: 'CHALLENGE_DELETED', winner});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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);
|
||||
res.respond(200, group.chat);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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,34 +65,31 @@ api.postChat = {
|
||||
req.checkBody('message', res.t('messageGroupChatBlankMessage')).notEmpty();
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) return next(validationErrors);
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
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.');
|
||||
}
|
||||
let group = await Group.getGroup(user, groupId);
|
||||
|
||||
let lastClientMsg = req.query.previousMsg;
|
||||
chatUpdated = lastClientMsg && group.chat && group.chat[0] && group.chat[0].id !== lastClientMsg ? true : false;
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.type !== 'party' && user.flags.chatRevoked) {
|
||||
throw new NotFound('Your chat privileges have been revoked.');
|
||||
}
|
||||
|
||||
group.sendChat(req.body.message, user);
|
||||
let lastClientMsg = req.query.previousMsg;
|
||||
chatUpdated = lastClientMsg && group.chat && group.chat[0] && group.chat[0].id !== lastClientMsg ? true : false;
|
||||
|
||||
if (group.type === 'party') {
|
||||
user.party.lastMessageSeen = group.chat[0].id;
|
||||
user.save();
|
||||
}
|
||||
return group.save();
|
||||
})
|
||||
.then((group) => {
|
||||
if (chatUpdated) {
|
||||
res.respond(200, {chat: group.chat});
|
||||
} else {
|
||||
res.respond(200, {message: group.chat[0]});
|
||||
}
|
||||
})
|
||||
.catch(next);
|
||||
group.sendChat(req.body.message, user);
|
||||
|
||||
if (group.type === 'party') {
|
||||
user.party.lastMessageSeen = group.chat[0].id;
|
||||
user.save(); // TODO why this is non-blocking? must catch?
|
||||
}
|
||||
|
||||
let savedGroup = await group.save();
|
||||
if (chatUpdated) {
|
||||
res.respond(200, {chat: savedGroup.chat});
|
||||
} else {
|
||||
res.respond(200, {message: savedGroup.chat[0]});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -114,42 +108,35 @@ 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) => {
|
||||
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 group = await Group.getGroup(user, groupId);
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
if (message.uuid === user._id) throw new NotFound(res.t('messageGroupChatLikeOwnMessage'));
|
||||
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: {}};
|
||||
let update = {$set: {}};
|
||||
|
||||
if (!message.likes) message.likes = {};
|
||||
if (!message.likes) message.likes = {};
|
||||
|
||||
message.likes[user._id] = !message.likes[user._id];
|
||||
update.$set[`chat.$.likes.${user._id}`] = message.likes[user._id];
|
||||
message.likes[user._id] = !message.likes[user._id];
|
||||
update.$set[`chat.$.likes.${user._id}`] = message.likes[user._id];
|
||||
|
||||
return 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);
|
||||
await Group.update(
|
||||
{_id: group._id, 'chat.id': message.id},
|
||||
update
|
||||
);
|
||||
res.respond(200, message);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -168,116 +155,104 @@ 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) throw new NotFound(res.t('messageGroupChatNotFound'));
|
||||
|
||||
if (message.uuid === user._id) throw new NotFound(res.t('messageGroupChatFlagOwnMessage'));
|
||||
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: {}};
|
||||
let update = {$set: {}};
|
||||
|
||||
// Log user ids that have flagged the message
|
||||
if (!message.flags) message.flags = {};
|
||||
if (message.flags[user._id] && !user.contributor.admin) throw new NotFound(res.t('messageGroupChatFlagAlreadyReported'));
|
||||
message.flags[user._id] = true;
|
||||
update.$set[`chat.$.flags.${user._id}`] = true;
|
||||
// Log user ids that have flagged the message
|
||||
if (!message.flags) message.flags = {};
|
||||
if (message.flags[user._id] && !user.contributor.admin) throw new NotFound(res.t('messageGroupChatFlagAlreadyReported'));
|
||||
message.flags[user._id] = true;
|
||||
update.$set[`chat.$.flags.${user._id}`] = true;
|
||||
|
||||
// Log total number of flags (publicly viewable)
|
||||
if (!message.flagCount) message.flagCount = 0;
|
||||
if (user.contributor.admin) {
|
||||
// Arbitraty amount, higher than 2
|
||||
message.flagCount = 5;
|
||||
} else {
|
||||
message.flagCount++;
|
||||
}
|
||||
update.$set['chat.$.flagCount'] = message.flagCount;
|
||||
// Log total number of flags (publicly viewable)
|
||||
if (!message.flagCount) message.flagCount = 0;
|
||||
if (user.contributor.admin) {
|
||||
// Arbitraty amount, higher than 2
|
||||
message.flagCount = 5;
|
||||
} else {
|
||||
message.flagCount++;
|
||||
}
|
||||
update.$set['chat.$.flagCount'] = message.flagCount;
|
||||
|
||||
return Group.update(
|
||||
{_id: group._id, 'chat.id': message.id},
|
||||
update
|
||||
);
|
||||
})
|
||||
.then((group2) => {
|
||||
if (!group2) throw new NotFound(res.t('groupNotFound'));
|
||||
await Group.update(
|
||||
{_id: group._id, 'chat.id': message.id},
|
||||
update
|
||||
);
|
||||
|
||||
let addressesToSendTo = nconf.get('FLAG_REPORT_EMAIL');
|
||||
addressesToSendTo = typeof addressesToSendTo === 'string' ? JSON.parse(addressesToSendTo) : addressesToSendTo;
|
||||
let addressesToSendTo = nconf.get('FLAG_REPORT_EMAIL');
|
||||
addressesToSendTo = typeof addressesToSendTo === 'string' ? JSON.parse(addressesToSendTo) : addressesToSendTo;
|
||||
|
||||
if (Array.isArray(addressesToSendTo)) {
|
||||
addressesToSendTo = addressesToSendTo.map((email) => {
|
||||
return {email, canSend: true};
|
||||
});
|
||||
} else {
|
||||
addressesToSendTo = {email: addressesToSendTo};
|
||||
}
|
||||
if (Array.isArray(addressesToSendTo)) {
|
||||
addressesToSendTo = addressesToSendTo.map((email) => {
|
||||
return {email, canSend: true};
|
||||
});
|
||||
} else {
|
||||
addressesToSendTo = {email: addressesToSendTo};
|
||||
}
|
||||
|
||||
let reporterEmailContent;
|
||||
if (user.auth.local) {
|
||||
reporterEmailContent = user.auth.local.email;
|
||||
} else if (user.auth.facebook && user.auth.facebook.emails && user.auth.facebook.emails[0]) {
|
||||
reporterEmailContent = user.auth.facebook.emails[0].value;
|
||||
}
|
||||
let reporterEmailContent;
|
||||
if (user.auth.local) {
|
||||
reporterEmailContent = user.auth.local.email;
|
||||
} else if (user.auth.facebook && user.auth.facebook.emails && user.auth.facebook.emails[0]) {
|
||||
reporterEmailContent = user.auth.facebook.emails[0].value;
|
||||
}
|
||||
|
||||
let authorEmailContent;
|
||||
if (author.auth.local) {
|
||||
authorEmailContent = author.auth.local.email;
|
||||
} else if (author.auth.facebook && author.auth.facebook.emails && author.auth.facebook.emails[0]) {
|
||||
authorEmailContent = author.auth.facebook.emails[0].value;
|
||||
}
|
||||
let authorEmailContent;
|
||||
if (author.auth.local) {
|
||||
authorEmailContent = author.auth.local.email;
|
||||
} else if (author.auth.facebook && author.auth.facebook.emails && author.auth.facebook.emails[0]) {
|
||||
authorEmailContent = author.auth.facebook.emails[0].value;
|
||||
}
|
||||
|
||||
let groupUrl;
|
||||
if (group._id === 'habitrpg') {
|
||||
groupUrl = '/#/options/groups/tavern';
|
||||
} else if (group.type === 'guild') {
|
||||
groupUrl = `/#/options/groups/guilds/{$group._id}`;
|
||||
} else {
|
||||
groupUrl = 'party';
|
||||
}
|
||||
let groupUrl;
|
||||
if (group._id === 'habitrpg') {
|
||||
groupUrl = '/#/options/groups/tavern';
|
||||
} else if (group.type === 'guild') {
|
||||
groupUrl = `/#/options/groups/guilds/{$group._id}`;
|
||||
} else {
|
||||
groupUrl = 'party';
|
||||
}
|
||||
|
||||
sendTxn(addressesToSendTo, 'flag-report-to-mods', [
|
||||
{name: 'MESSAGE_TIME', content: (new Date(message.timestamp)).toString()},
|
||||
{name: 'MESSAGE_TEXT', content: message.text},
|
||||
sendTxn(addressesToSendTo, 'flag-report-to-mods', [
|
||||
{name: 'MESSAGE_TIME', content: (new Date(message.timestamp)).toString()},
|
||||
{name: 'MESSAGE_TEXT', content: message.text},
|
||||
|
||||
{name: 'REPORTER_USERNAME', content: user.profile.name},
|
||||
{name: 'REPORTER_UUID', content: user._id},
|
||||
{name: 'REPORTER_EMAIL', content: reporterEmailContent},
|
||||
{name: 'REPORTER_MODAL_URL', content: `/static/front/#?memberId={$user._id}`},
|
||||
{name: 'REPORTER_USERNAME', content: user.profile.name},
|
||||
{name: 'REPORTER_UUID', content: user._id},
|
||||
{name: 'REPORTER_EMAIL', content: reporterEmailContent},
|
||||
{name: 'REPORTER_MODAL_URL', content: `/static/front/#?memberId={$user._id}`},
|
||||
|
||||
{name: 'AUTHOR_USERNAME', content: message.user},
|
||||
{name: 'AUTHOR_UUID', content: message.uuid},
|
||||
{name: 'AUTHOR_EMAIL', content: authorEmailContent},
|
||||
{name: 'AUTHOR_MODAL_URL', content: `/static/front/#?memberId={$message.uuid}`},
|
||||
{name: 'AUTHOR_USERNAME', content: message.user},
|
||||
{name: 'AUTHOR_UUID', content: message.uuid},
|
||||
{name: 'AUTHOR_EMAIL', content: authorEmailContent},
|
||||
{name: 'AUTHOR_MODAL_URL', content: `/static/front/#?memberId={$message.uuid}`},
|
||||
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'GROUP_TYPE', content: group.type},
|
||||
{name: 'GROUP_ID', content: group._id},
|
||||
{name: 'GROUP_URL', content: groupUrl},
|
||||
]);
|
||||
res.respond(200, message);
|
||||
})
|
||||
.catch(next);
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'GROUP_TYPE', content: group.type},
|
||||
{name: 'GROUP_ID', content: group._id},
|
||||
{name: 'GROUP_URL', content: groupUrl},
|
||||
]);
|
||||
|
||||
res.respond(200, message);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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 savedGroup = results[1];
|
||||
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);
|
||||
firebase.updateGroupData(savedGroup);
|
||||
firebase.addUserToGroup(savedGroup._id, user._id);
|
||||
return res.respond(201, savedGroup); // TODO populate
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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'));
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
res.respond(200, _.reduce(results, (m, v) => {
|
||||
if (_.isEmpty(v)) return m;
|
||||
return m.concat(Array.isArray(v) ? v : [v]);
|
||||
}, []));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
let group = await Group.getGroup(user, req.params.groupId);
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
res.respond(200, group);
|
||||
})
|
||||
.catch(next);
|
||||
res.respond(200, group);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
|
||||
|
||||
_.assign(group, _.merge(group.toObject(), Group.sanitizeUpdate(req.body)));
|
||||
_.assign(group, _.merge(group.toObject(), Group.sanitizeUpdate(req.body)));
|
||||
|
||||
return group.save();
|
||||
}).then(savedGroup => {
|
||||
res.respond(200, savedGroup);
|
||||
firebase.updateGroupData(savedGroup);
|
||||
})
|
||||
.catch(next);
|
||||
let savedGroup = await group.save();
|
||||
res.respond(200, savedGroup);
|
||||
firebase.updateGroupData(savedGroup);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -213,60 +199,57 @@ 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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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;
|
||||
let isUserInvited = false;
|
||||
|
||||
if (group.type === 'party' && group._id === (user.invitations.party && user.invitations.party.id)) {
|
||||
user.invitations.party = {}; // Clear invite TODO mark modified?
|
||||
if (group.type === 'party' && group._id === (user.invitations.party && user.invitations.party.id)) {
|
||||
user.invitations.party = {}; // Clear invite TODO mark modified?
|
||||
|
||||
// invite new user to pending quest
|
||||
if (group.quest.key && !group.quest.active) {
|
||||
user.party.quest.RSVPNeeded = true;
|
||||
user.party.quest.key = group.quest.key;
|
||||
group.quest.members[user._id] = undefined;
|
||||
group.markModified('quest.members');
|
||||
}
|
||||
|
||||
user.party._id = group._id; // Set group as user's party
|
||||
|
||||
isUserInvited = true;
|
||||
} else if (group.type === 'guild' && user.invitations.guilds) {
|
||||
let i = _.findIndex(user.invitations.guilds, {id: group._id});
|
||||
|
||||
if (i !== -1) {
|
||||
isUserInvited = true;
|
||||
user.invitations.guilds.splice(i, 1); // Remove invitation
|
||||
} else {
|
||||
isUserInvited = group.privacy === 'private' ? false : true;
|
||||
}
|
||||
// invite new user to pending quest
|
||||
if (group.quest.key && !group.quest.active) {
|
||||
user.party.quest.RSVPNeeded = true;
|
||||
user.party.quest.key = group.quest.key;
|
||||
group.quest.members[user._id] = undefined;
|
||||
group.markModified('quest.members');
|
||||
}
|
||||
|
||||
if (isUserInvited && group.type === 'guild') user.guilds.push(group._id); // Add group to user's guilds
|
||||
if (!isUserInvited) throw new NotAuthorized(res.t('messageGroupRequiresInvite'));
|
||||
user.party._id = group._id; // Set group as user's party
|
||||
|
||||
if (group.memberCount === 0) group.leader = user._id; // If new user is only member -> set as leader
|
||||
isUserInvited = true;
|
||||
} else if (group.type === 'guild' && user.invitations.guilds) {
|
||||
let i = _.findIndex(user.invitations.guilds, {id: group._id});
|
||||
|
||||
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);
|
||||
if (i !== -1) {
|
||||
isUserInvited = true;
|
||||
user.invitations.guilds.splice(i, 1); // Remove invitation
|
||||
} else {
|
||||
isUserInvited = group.privacy === 'private' ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isUserInvited && group.type === 'guild') user.guilds.push(group._id); // Add group to user's guilds
|
||||
if (!isUserInvited) throw new NotAuthorized(res.t('messageGroupRequiresInvite'));
|
||||
|
||||
if (group.memberCount === 0) group.leader = user._id; // If new user is only member -> set as leader
|
||||
|
||||
await Q.all([
|
||||
group.save(),
|
||||
user.save(),
|
||||
User.update({_id: user.invitations.party.inviter}, {$inc: {'items.quests.basilist': 1}}).exec(), // Reward inviter
|
||||
]);
|
||||
|
||||
firebase.addUserToGroup(group._id, user._id);
|
||||
res.respond(200, {}); // TODO what to return?
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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,27 +276,24 @@ 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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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
|
||||
if (group.type === 'party') {
|
||||
if (group.quest && group.quest.leader === user._id) {
|
||||
throw new NotAuthorized(res.t('questLeaderCannotLeaveGroup'));
|
||||
}
|
||||
|
||||
if (group.quest && group.quest.active && group.quest.members && group.quest.members[user._id]) {
|
||||
throw new NotAuthorized(res.t('cannotLeaveWhileActiveQuest'));
|
||||
}
|
||||
// During quests, checke wheter user can leave
|
||||
if (group.type === 'party') {
|
||||
if (group.quest && group.quest.leader === user._id) {
|
||||
throw new NotAuthorized(res.t('questLeaderCannotLeaveGroup'));
|
||||
}
|
||||
|
||||
return group.leave(user, req.query.keep);
|
||||
})
|
||||
.then(() => res.respond(200, {}))
|
||||
.catch(next);
|
||||
if (group.quest && group.quest.active && group.quest.members && group.quest.members[user._id]) {
|
||||
throw new NotAuthorized(res.t('cannotLeaveWhileActiveQuest'));
|
||||
}
|
||||
}
|
||||
|
||||
await group.leave(user, req.query.keep);
|
||||
res.respond(200, {});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -345,71 +325,65 @@ 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;
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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;
|
||||
let uuid = req.query.memberId;
|
||||
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyLeaderCanRemoveMember'));
|
||||
if (user._id === uuid) throw new NotAuthorized(res.t('memberCannotRemoveYourself'));
|
||||
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 => {
|
||||
// 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
|
||||
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
|
||||
|
||||
if (isInGroup) {
|
||||
group.memberCount -= 1;
|
||||
if (isInGroup) {
|
||||
group.memberCount -= 1;
|
||||
|
||||
if (group.quest && group.quest.leader === member._id) {
|
||||
group.quest.key = null;
|
||||
group.quest.leader = null; // TODO markmodified?
|
||||
} else if (group.quest && group.quest.members) {
|
||||
// remove member from quest
|
||||
group.quest.members[member._id] = undefined;
|
||||
}
|
||||
|
||||
if (isInGroup === 'guild') _.pull(member.guilds, group._id);
|
||||
if (isInGroup === 'party') member.party._id = undefined; // TODO remove quest information too?
|
||||
|
||||
member.newMessages.group._id = undefined;
|
||||
|
||||
if (group.quest && group.quest.active && group.quest.leader === member._id) {
|
||||
member.items.quests[group.quest.key] += 1; // TODO why this?
|
||||
}
|
||||
} else if (isInvited) {
|
||||
if (isInvited === 'guild') {
|
||||
let i = _.findIndex(member.invitations.guilds, {id: group._id});
|
||||
if (i !== -1) member.invitations.guilds.splice(i, 1);
|
||||
}
|
||||
if (isInvited === 'party') user.invitations.party = {}; // TODO mark modified?
|
||||
} else {
|
||||
throw new NotFound(res.t('groupMemberNotFound'));
|
||||
if (group.quest && group.quest.leader === member._id) {
|
||||
group.quest.key = null;
|
||||
group.quest.leader = null; // TODO markmodified?
|
||||
} else if (group.quest && group.quest.members) {
|
||||
// remove member from quest
|
||||
group.quest.members[member._id] = undefined;
|
||||
}
|
||||
|
||||
let message = req.query.message;
|
||||
if (message) _sendMessageToRemoved(group, member, message);
|
||||
if (isInGroup === 'guild') _.pull(member.guilds, group._id);
|
||||
if (isInGroup === 'party') member.party._id = undefined; // TODO remove quest information too?
|
||||
|
||||
return Q.all([
|
||||
member.save(),
|
||||
group.save(),
|
||||
]);
|
||||
})
|
||||
.then(() => res.respond(200, {}))
|
||||
.catch(next);
|
||||
member.newMessages.group._id = undefined;
|
||||
|
||||
if (group.quest && group.quest.active && group.quest.leader === member._id) {
|
||||
member.items.quests[group.quest.key] += 1; // TODO why this?
|
||||
}
|
||||
} else if (isInvited) {
|
||||
if (isInvited === 'guild') {
|
||||
let i = _.findIndex(member.invitations.guilds, {id: group._id});
|
||||
if (i !== -1) member.invitations.guilds.splice(i, 1);
|
||||
}
|
||||
if (isInvited === 'party') user.invitations.party = {}; // TODO mark modified?
|
||||
} else {
|
||||
throw new NotFound(res.t('groupMemberNotFound'));
|
||||
}
|
||||
|
||||
let message = req.query.message;
|
||||
if (message) _sendMessageToRemoved(group, member, message);
|
||||
|
||||
await Q.all([
|
||||
member.save(),
|
||||
group.save(),
|
||||
]);
|
||||
res.respond(200, {});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -571,32 +545,29 @@ 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 => {
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
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;
|
||||
let emails = req.body.emails;
|
||||
let uuids = req.body.uuids;
|
||||
let emails = req.body.emails;
|
||||
|
||||
if (uuids && emails) { // TODO fix this, low priority, allow for inviting by both at the same time
|
||||
throw new BadRequest(res.t('canOnlyInviteEmailUuid'));
|
||||
} else if (Array.isArray(uuids)) {
|
||||
// return _inviteByUUIDs(uuids, group, user, req, res, next);
|
||||
} else if (Array.isArray(emails)) {
|
||||
// return _inviteByEmails(emails, group, user, req, res, next);
|
||||
} else {
|
||||
throw new BadRequest(res.t('canOnlyInviteEmailUuid'));
|
||||
}
|
||||
})
|
||||
.catch(next);
|
||||
if (uuids && emails) { // TODO fix this, low priority, allow for inviting by both at the same time
|
||||
throw new BadRequest(res.t('canOnlyInviteEmailUuid'));
|
||||
} else if (Array.isArray(uuids)) {
|
||||
// return _inviteByUUIDs(uuids, group, user, req, res, next);
|
||||
} else if (Array.isArray(emails)) {
|
||||
// return _inviteByEmails(emails, group, user, req, res, next);
|
||||
} else {
|
||||
throw new BadRequest(res.t('canOnlyInviteEmailUuid'));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
let l = savedUser.tags.length;
|
||||
let tag = savedUser.tags[l - 1];
|
||||
res.respond(201, tag);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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, {});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
res.respond(200, task);
|
||||
})
|
||||
.catch(next);
|
||||
}).exec();
|
||||
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
res.respond(200, task);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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,37 +162,36 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
}).exec();
|
||||
|
||||
// If checklist is updated -> replace the original one
|
||||
if (req.body.checklist) {
|
||||
task.checklist = req.body.checklist;
|
||||
delete req.body.checklist;
|
||||
}
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
|
||||
// If tags are updated -> replace the original ones
|
||||
if (req.body.tags) {
|
||||
task.tags = req.body.tags;
|
||||
delete req.body.tags;
|
||||
}
|
||||
// If checklist is updated -> replace the original one
|
||||
if (req.body.checklist) {
|
||||
task.checklist = req.body.checklist;
|
||||
delete req.body.checklist;
|
||||
}
|
||||
|
||||
// TODO we have to convert task to an object because otherwise thigns doesn't get merged correctly, very bad for performances
|
||||
// TODO regarding comment above make sure other models with nested fields are using this trick too
|
||||
_.assign(task, _.merge(task.toObject(), Tasks.Task.sanitizeUpdate(req.body)));
|
||||
// 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);
|
||||
// If tags are updated -> replace the original ones
|
||||
if (req.body.tags) {
|
||||
task.tags = req.body.tags;
|
||||
delete req.body.tags;
|
||||
}
|
||||
|
||||
// TODO we have to convert task to an object because otherwise thigns doesn't get merged correctly, very bad for performances
|
||||
// TODO regarding comment above make sure other models with nested fields are using this trick too
|
||||
_.assign(task, _.merge(task.toObject(), Tasks.Task.sanitizeUpdate(req.body)));
|
||||
// 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
|
||||
|
||||
let savedTask = await task.save();
|
||||
res.respond(200, savedTask);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -239,81 +235,82 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
}).exec();
|
||||
|
||||
let wasCompleted = task.completed;
|
||||
if (task.type === 'daily' || task.type === 'todo') {
|
||||
task.completed = direction === 'up'; // TODO move into scoreTask
|
||||
}
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
|
||||
let delta = scoreTask({task, user, direction}, req);
|
||||
// Drop system (don't run on the client, as it would only be discarded since ops are sent to the API, not the results)
|
||||
if (direction === 'up') user.fns.randomDrop({task, delta}, req);
|
||||
let wasCompleted = task.completed;
|
||||
if (task.type === 'daily' || task.type === 'todo') {
|
||||
task.completed = direction === 'up'; // TODO move into scoreTask
|
||||
}
|
||||
|
||||
// If a todo was completed or uncompleted move it in or out of the user.tasksOrder.todos list
|
||||
if (task.type === 'todo') {
|
||||
if (!wasCompleted && task.completed) {
|
||||
let i = user.tasksOrder.todos.indexOf(task._id);
|
||||
if (i !== -1) user.tasksOrder.todos.splice(i, 1);
|
||||
} else if (wasCompleted && !task.completed) {
|
||||
let i = user.tasksOrder.todos.indexOf(task._id);
|
||||
if (i === -1) {
|
||||
user.tasksOrder.todos.push(task._id); // TODO push at the top?
|
||||
} else { // If for some reason it hadn't been removed TODO ok?
|
||||
user.tasksOrder.todos.splice(i, 1);
|
||||
user.tasksOrder.push(task._id);
|
||||
}
|
||||
let delta = scoreTask({task, user, direction}, req);
|
||||
// Drop system (don't run on the client, as it would only be discarded since ops are sent to the API, not the results)
|
||||
if (direction === 'up') user.fns.randomDrop({task, delta}, req);
|
||||
|
||||
// If a todo was completed or uncompleted move it in or out of the user.tasksOrder.todos list
|
||||
if (task.type === 'todo') {
|
||||
if (!wasCompleted && task.completed) {
|
||||
let i = user.tasksOrder.todos.indexOf(task._id);
|
||||
if (i !== -1) user.tasksOrder.todos.splice(i, 1);
|
||||
} else if (wasCompleted && !task.completed) {
|
||||
let i = user.tasksOrder.todos.indexOf(task._id);
|
||||
if (i === -1) {
|
||||
user.tasksOrder.todos.push(task._id); // TODO push at the top?
|
||||
} else { // If for some reason it hadn't been removed TODO ok?
|
||||
user.tasksOrder.todos.splice(i, 1);
|
||||
user.tasksOrder.push(task._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Q.all([
|
||||
user.save(),
|
||||
task.save(),
|
||||
]).then((results) => {
|
||||
let savedUser = results[0];
|
||||
let results = await Q.all([
|
||||
user.save(),
|
||||
task.save(),
|
||||
]);
|
||||
|
||||
let userStats = savedUser.stats.toJSON();
|
||||
let resJsonData = _.extend({delta, _tmp: user._tmp}, userStats);
|
||||
res.respond(200, resJsonData);
|
||||
let savedUser = results[0];
|
||||
|
||||
sendTaskWebhook(user.preferences.webhooks, _generateWebhookTaskData(task, direction, delta, userStats, user));
|
||||
let userStats = savedUser.stats.toJSON();
|
||||
let resJsonData = _.extend({delta, _tmp: user._tmp}, userStats);
|
||||
res.respond(200, resJsonData);
|
||||
|
||||
// TODO test?
|
||||
if (task.challenge.id && task.challenge.taskId && !task.challenge.broken && task.type !== 'reward') {
|
||||
Tasks.Task.findOne({
|
||||
_id: task.challenge.taskId,
|
||||
}).exec()
|
||||
.then(chalTask => {
|
||||
chalTask.value += delta;
|
||||
if (chalTask.type === 'habit' || chalTask.type === 'daily') {
|
||||
chalTask.history.push({value: chalTask.value, date: Number(new Date())});
|
||||
// TODO 1. treat challenges as subscribed users for preening 2. it's expensive to do it at every score - how to have it happen once like for cron?
|
||||
chalTask.history = preenHistory(user, chalTask.history);
|
||||
chalTask.markModified('history');
|
||||
}
|
||||
sendTaskWebhook(user.preferences.webhooks, _generateWebhookTaskData(task, direction, delta, userStats, user));
|
||||
|
||||
return chalTask.save();
|
||||
});
|
||||
// .catch(next) TODO what to do here
|
||||
// TODO test?
|
||||
if (task.challenge.id && task.challenge.taskId && !task.challenge.broken && task.type !== 'reward') {
|
||||
// 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();
|
||||
|
||||
chalTask.value += delta;
|
||||
if (chalTask.type === 'habit' || chalTask.type === 'daily') {
|
||||
chalTask.history.push({value: chalTask.value, date: Number(new Date())});
|
||||
// TODO 1. treat challenges as subscribed users for preening 2. it's expensive to do it at every score - how to have it happen once like for cron?
|
||||
chalTask.history = preenHistory(user, chalTask.history);
|
||||
chalTask.markModified('history');
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(next);
|
||||
|
||||
await chalTask.save();
|
||||
} catch (e) {
|
||||
// TODO handle
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -334,41 +331,39 @@ 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) => {
|
||||
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`];
|
||||
let currentIndex = order.indexOf(task._id);
|
||||
}).exec();
|
||||
|
||||
// If for some reason the task isn't ordered (should never happen)
|
||||
// or if the task is moved to a non existing position
|
||||
// or if the task is moved to postion -1 (push to bottom)
|
||||
// -> push task at end of list
|
||||
if (currentIndex === -1 || !order[to] || to === -1) {
|
||||
order.push(task._id);
|
||||
} else {
|
||||
let taskToMove = order.splice(currentIndex, 1)[0];
|
||||
order.splice(to, 0, taskToMove);
|
||||
}
|
||||
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`];
|
||||
let currentIndex = order.indexOf(task._id);
|
||||
|
||||
return user.save();
|
||||
})
|
||||
.then(() => res.respond(200, {})) // TODO what to return
|
||||
.catch(next);
|
||||
// If for some reason the task isn't ordered (should never happen)
|
||||
// or if the task is moved to a non existing position
|
||||
// or if the task is moved to postion -1 (push to bottom)
|
||||
// -> push task at end of list
|
||||
if (currentIndex === -1 || !order[to] || to === -1) {
|
||||
order.push(task._id);
|
||||
} else {
|
||||
let taskToMove = order.splice(currentIndex, 1)[0];
|
||||
order.splice(to, 0, taskToMove);
|
||||
}
|
||||
|
||||
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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
}).exec();
|
||||
|
||||
task.checklist.push(Tasks.Task.sanitizeChecklist(req.body));
|
||||
return task.save();
|
||||
})
|
||||
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
|
||||
.catch(next);
|
||||
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));
|
||||
let savedTask = await task.save();
|
||||
|
||||
res.respond(200, savedTask); // TODO what to return
|
||||
},
|
||||
};
|
||||
|
||||
@@ -426,31 +420,30 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
}).exec();
|
||||
|
||||
let item = _.find(task.checklist, {_id: req.params.itemId});
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
|
||||
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 item = _.find(task.checklist, {_id: req.params.itemId});
|
||||
|
||||
if (!item) throw new NotFound(res.t('checklistItemNotFound'));
|
||||
item.completed = !item.completed;
|
||||
let savedTask = await task.save();
|
||||
|
||||
res.respond(200, savedTask); // TODO what to return
|
||||
},
|
||||
};
|
||||
|
||||
@@ -469,31 +462,30 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
}).exec();
|
||||
|
||||
let item = _.find(task.checklist, {_id: req.params.itemId});
|
||||
if (!item) throw new NotFound(res.t('checklistItemNotFound'));
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
|
||||
_.merge(item, Tasks.Task.sanitizeChecklist(req.body));
|
||||
return task.save();
|
||||
})
|
||||
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
|
||||
.catch(next);
|
||||
let item = _.find(task.checklist, {_id: req.params.itemId});
|
||||
if (!item) throw new NotFound(res.t('checklistItemNotFound'));
|
||||
|
||||
_.merge(item, Tasks.Task.sanitizeChecklist(req.body));
|
||||
let savedTask = await task.save();
|
||||
|
||||
res.respond(200, savedTask); // TODO what to return
|
||||
},
|
||||
};
|
||||
|
||||
@@ -512,31 +504,30 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
}).exec();
|
||||
|
||||
let itemI = _.findIndex(task.checklist, {_id: req.params.itemId});
|
||||
if (itemI === -1) throw new NotFound(res.t('checklistItemNotFound'));
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.type !== 'daily' && task.type !== 'todo') throw new BadRequest(res.t('checklistOnlyDailyTodo'));
|
||||
|
||||
task.checklist.splice(itemI, 1);
|
||||
return task.save();
|
||||
})
|
||||
.then(() => res.respond(200, {})) // TODO what to return
|
||||
.catch(next);
|
||||
let itemI = _.findIndex(task.checklist, {_id: req.params.itemId});
|
||||
if (itemI === -1) throw new NotFound(res.t('checklistItemNotFound'));
|
||||
|
||||
task.checklist.splice(itemI, 1);
|
||||
|
||||
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,24 +554,23 @@ 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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
let tagId = req.params.tagId;
|
||||
}).exec();
|
||||
|
||||
let alreadyTagged = task.tags.indexOf(tagId) !== -1;
|
||||
if (alreadyTagged) throw new BadRequest(res.t('alreadyTagged'));
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
let tagId = req.params.tagId;
|
||||
|
||||
task.tags.push(tagId);
|
||||
return task.save();
|
||||
})
|
||||
.then((savedTask) => res.respond(200, savedTask)) // TODO what to return
|
||||
.catch(next);
|
||||
let alreadyTagged = task.tags.indexOf(tagId) !== -1;
|
||||
if (alreadyTagged) throw new BadRequest(res.t('alreadyTagged'));
|
||||
|
||||
task.tags.push(tagId);
|
||||
|
||||
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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
}).exec();
|
||||
|
||||
let tagI = task.tags.indexOf(req.params.tagId);
|
||||
if (tagI === -1) throw new NotFound(res.t('tagNotFound'));
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
|
||||
task.tags.splice(tagI, 1);
|
||||
return task.save();
|
||||
})
|
||||
.then(() => res.respond(200, {})) // TODO what to return
|
||||
.catch(next);
|
||||
let tagI = task.tags.indexOf(req.params.tagId);
|
||||
if (tagI === -1) throw new NotFound(res.t('tagNotFound'));
|
||||
|
||||
task.tags.splice(tagI, 1);
|
||||
|
||||
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) => {
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.challenge.id) throw new NotAuthorized(res.t('cantDeleteChallengeTasks'));
|
||||
}).exec();
|
||||
|
||||
_removeTaskTasksOrder(user, req.params.taskId);
|
||||
return Q.all([
|
||||
user.save(),
|
||||
task.remove(),
|
||||
]);
|
||||
})
|
||||
.then(() => res.respond(200, {}))
|
||||
.catch(next);
|
||||
if (!task) throw new NotFound(res.t('taskNotFound'));
|
||||
if (task.challenge.id) throw new NotAuthorized(res.t('cantDeleteChallengeTasks'));
|
||||
|
||||
_removeTaskTasksOrder(user, req.params.taskId);
|
||||
await Q.all([user.save(), task.remove()]);
|
||||
|
||||
res.respond(200, {});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user