v3: general cleanup

This commit is contained in:
Matteo Pagliazzi
2016-04-17 01:17:22 +02:00
parent c2b8cad886
commit b271520c53
22 changed files with 213 additions and 193 deletions

View File

@@ -1,9 +1,9 @@
import { import {
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
describe('GET /meta/models/:model/paths', () => { describe('GET /models/:model/paths', () => {
let user; let user;
before(async () => { before(async () => {
@@ -11,7 +11,7 @@ describe('GET /meta/models/:model/paths', () => {
}); });
it('returns an error when model is not accessible or doesn\'t exists', async () => { it('returns an error when model is not accessible or doesn\'t exists', async () => {
await expect(user.get('/meta/models/1234/paths')).to.eventually.be.rejected.and.eql({ await expect(user.get('/models/1234/paths')).to.eventually.be.rejected.and.eql({
code: 400, code: 400,
error: 'BadRequest', error: 'BadRequest',
message: t('invalidReqParams'), message: t('invalidReqParams'),
@@ -21,7 +21,7 @@ describe('GET /meta/models/:model/paths', () => {
let models = ['habit', 'daily', 'todo', 'reward', 'user', 'tag', 'challenge', 'group']; let models = ['habit', 'daily', 'todo', 'reward', 'user', 'tag', 'challenge', 'group'];
models.forEach(model => { models.forEach(model => {
it(`returns the model paths for ${model}`, async () => { it(`returns the model paths for ${model}`, async () => {
let res = await user.get(`/meta/models/${model}/paths`); let res = await user.get(`/models/${model}/paths`);
expect(res._id).to.equal('String'); expect(res._id).to.equal('String');
expect(res).to.not.have.keys('__v'); expect(res).to.not.have.keys('__v');

View File

@@ -62,7 +62,7 @@ async function _handleGroupInvitation (user, invite) {
* @apiParam {String} password Body parameter - Password for the new user * @apiParam {String} password Body parameter - Password for the new user
* @apiParam {String} confirmPassword Body parameter - Password confirmation * @apiParam {String} confirmPassword Body parameter - Password confirmation
* *
* @apiSuccess {Object} user The user object, if local auth was just attached to a social user then only user.auth.local * @apiSuccess {Object} data The user object, if local auth was just attached to a social user then only user.auth.local
*/ */
api.registerLocal = { api.registerLocal = {
method: 'POST', method: 'POST',
@@ -174,8 +174,8 @@ function _loginRes (user, req, res) {
* @apiParam {String} username Body parameter - Username or email of the user * @apiParam {String} username Body parameter - Username or email of the user
* @apiParam {String} password Body parameter - The user's password * @apiParam {String} password Body parameter - The user's password
* *
* @apiSuccess {String} _id The user's unique identifier * @apiSuccess {String} data._id The user's unique identifier
* @apiSuccess {String} apiToken The user's api token that must be used to authenticate requests. * @apiSuccess {String} data.apiToken The user's api token that must be used to authenticate requests.
*/ */
api.loginLocal = { api.loginLocal = {
method: 'POST', method: 'POST',
@@ -229,6 +229,7 @@ function _passportFbProfile (accessToken) {
} }
// Called as a callback by Facebook (or other social providers). Internal route // Called as a callback by Facebook (or other social providers). Internal route
// TODO move to top-level/auth?
api.loginSocial = { api.loginSocial = {
method: 'POST', method: 'POST',
url: '/user/auth/social', // this isn't the most appropriate url but must be the same as v2 url: '/user/auth/social', // this isn't the most appropriate url but must be the same as v2
@@ -290,7 +291,7 @@ api.loginSocial = {
* @apiParam {string} password Body parameter - The current user password * @apiParam {string} password Body parameter - The current user password
* @apiParam {string} username Body parameter - The new username * @apiParam {string} username Body parameter - The new username
* @apiSuccess {String} username The new username * @apiSuccess {String} data.username The new username
**/ **/
api.updateUsername = { api.updateUsername = {
method: 'PUT', method: 'PUT',
@@ -339,7 +340,7 @@ api.updateUsername = {
* @apiParam {string} newPassword Body parameter - The new password * @apiParam {string} newPassword Body parameter - The new password
* @apiParam {string} confirmPassword Body parameter - New password confirmation * @apiParam {string} confirmPassword Body parameter - New password confirmation
* *
* @apiSuccess {Object} emoty An empty object * @apiSuccess {Object} data An empty object
**/ **/
api.updatePassword = { api.updatePassword = {
method: 'PUT', method: 'PUT',
@@ -379,7 +380,7 @@ api.updatePassword = {
* *
* @apiParam {string} email Body parameter - The email address of the user * @apiParam {string} email Body parameter - The email address of the user
* *
* @apiSuccess {string} message The localized success message * @apiSuccess {string} data.message The localized success message
**/ **/
api.resetPassword = { api.resetPassword = {
method: 'POST', method: 'POST',
@@ -433,7 +434,7 @@ api.resetPassword = {
* @apiParam {string} Body parameter - newEmail The new email address. * @apiParam {string} Body parameter - newEmail The new email address.
* @apiParam {string} Body parameter - password The user password. * @apiParam {string} Body parameter - password The user password.
* *
* @apiSuccess {string} email The updated email address * @apiSuccess {string} data.email The updated email address
*/ */
api.updateEmail = { api.updateEmail = {
method: 'PUT', method: 'PUT',
@@ -488,7 +489,7 @@ api.getFirebaseToken = {
* @apiName UserDeleteSocial * @apiName UserDeleteSocial
* @apiGroup User * @apiGroup User
* *
* @apiSuccess {Object} empty Empty object * @apiSuccess {Object} data Empty object
*/ */
api.deleteSocial = { api.deleteSocial = {
method: 'DELETE', method: 'DELETE',

View File

@@ -29,7 +29,7 @@ let api = {};
* @apiName CreateChallenge * @apiName CreateChallenge
* @apiGroup Challenge * @apiGroup Challenge
* *
* @apiSuccess {object} challenge The newly created challenge * @apiSuccess {object} data The newly created challenge
*/ */
api.createChallenge = { api.createChallenge = {
method: 'POST', method: 'POST',
@@ -119,7 +119,7 @@ api.createChallenge = {
* @apiGroup Challenge * @apiGroup Challenge
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* *
* @apiSuccess {object} challenge The challenge the user joined * @apiSuccess {object} data The challenge the user joined
*/ */
api.joinChallenge = { api.joinChallenge = {
method: 'POST', method: 'POST',
@@ -165,7 +165,7 @@ api.joinChallenge = {
* @apiGroup Challenge * @apiGroup Challenge
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data An empty object
*/ */
api.leaveChallenge = { api.leaveChallenge = {
method: 'POST', method: 'POST',
@@ -202,7 +202,7 @@ api.leaveChallenge = {
* @apiName GetUserChallenges * @apiName GetUserChallenges
* @apiGroup Challenge * @apiGroup Challenge
* *
* @apiSuccess {Array} challenges An array of challenges * @apiSuccess {Array} data An array of challenges
*/ */
api.getUserChallenges = { api.getUserChallenges = {
method: 'GET', method: 'GET',
@@ -220,12 +220,13 @@ api.getUserChallenges = {
_id: {$ne: '95533e05-1ff9-4e46-970b-d77219f199e9'}, // remove the Spread the Word Challenge for now, will revisit when we fix the closing-challenge bug TODO revisit _id: {$ne: '95533e05-1ff9-4e46-970b-d77219f199e9'}, // remove the Spread the Word Challenge for now, will revisit when we fix the closing-challenge bug TODO revisit
}) })
.sort('-official -timestamp') .sort('-official -timestamp')
// see below why we're not using populate
// .populate('group', basicGroupFields) // .populate('group', basicGroupFields)
// .populate('leader', nameFields) // .populate('leader', nameFields)
.exec(); .exec();
let resChals = challenges.map(challenge => challenge.toJSON()); let resChals = challenges.map(challenge => challenge.toJSON());
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
await Q.all(resChals.map((chal, index) => { await Q.all(resChals.map((chal, index) => {
return Q.all([ return Q.all([
User.findById(chal.leader).select(nameFields).exec(), User.findById(chal.leader).select(nameFields).exec(),
@@ -242,13 +243,14 @@ api.getUserChallenges = {
/** /**
* @api {get} /api/v3/challenges/group/group:Id Get challenges for a group * @api {get} /api/v3/challenges/group/group:Id Get challenges for a group
* @apiDescription Get challenges that the user is a member, public challenges and the ones from the user's groups.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetGroupChallenges * @apiName GetGroupChallenges
* @apiGroup Challenge * @apiGroup Challenge
* *
* @apiParam {groupId} groupId The group _id * @apiParam {groupId} groupId The group _id
* *
* @apiSuccess {Array} challenges An array of challenges * @apiSuccess {Array} data An array of challenges
*/ */
api.getGroupChallenges = { api.getGroupChallenges = {
method: 'GET', method: 'GET',
@@ -272,7 +274,7 @@ api.getGroupChallenges = {
.exec(); .exec();
let resChals = challenges.map(challenge => challenge.toJSON()); let resChals = challenges.map(challenge => challenge.toJSON());
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
await Q.all(resChals.map((chal, index) => { await Q.all(resChals.map((chal, index) => {
return User.findById(chal.leader).select(nameFields).exec().then(populatedLeader => { return User.findById(chal.leader).select(nameFields).exec().then(populatedLeader => {
resChals[index].leader = populatedLeader.toJSON({minimize: true}); resChals[index].leader = populatedLeader.toJSON({minimize: true});
@@ -291,7 +293,7 @@ api.getGroupChallenges = {
* *
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* *
* @apiSuccess {object} challenge The challenge object * @apiSuccess {object} data The challenge object
*/ */
api.getChallenge = { api.getChallenge = {
method: 'GET', method: 'GET',
@@ -318,7 +320,7 @@ api.getChallenge = {
let chalRes = challenge.toJSON(); let chalRes = challenge.toJSON();
chalRes.group = group.toJSON({minimize: true}); chalRes.group = group.toJSON({minimize: true});
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
chalRes.leader = (await User.findById(chalRes.leader).select(nameFields).exec()).toJSON({minimize: true}); chalRes.leader = (await User.findById(chalRes.leader).select(nameFields).exec()).toJSON({minimize: true});
res.respond(200, chalRes); res.respond(200, chalRes);
@@ -333,7 +335,7 @@ api.getChallenge = {
* *
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* *
* @apiSuccess {object} challenge The challenge object * @apiSuccess {string} challenge A csv file
*/ */
api.exportChallengeCsv = { api.exportChallengeCsv = {
method: 'GET', method: 'GET',
@@ -406,7 +408,7 @@ api.exportChallengeCsv = {
* *
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* *
* @apiSuccess {object} challenge The updated challenge object * @apiSuccess {object} data The updated challenge
*/ */
api.updateChallenge = { api.updateChallenge = {
method: 'PUT', method: 'PUT',
@@ -507,7 +509,9 @@ export async function _closeChal (challenge, broken = {}) {
* @apiName DeleteChallenge * @apiName DeleteChallenge
* @apiGroup Challenge * @apiGroup Challenge
* *
* @apiSuccess {object} empty An empty object * challengeId {UUID} The _id for the challenge to delete
*
* @apiSuccess {object} data An empty object
*/ */
api.deleteChallenge = { api.deleteChallenge = {
method: 'DELETE', method: 'DELETE',
@@ -537,7 +541,10 @@ api.deleteChallenge = {
* @apiName SelectChallengeWinner * @apiName SelectChallengeWinner
* @apiGroup Challenge * @apiGroup Challenge
* *
* @apiSuccess {object} empty An empty object * challengeId {UUID} The _id for the challenge to close with a winner
* winnerId {UUID} The _id of the winning user
*
* @apiSuccess {object} data An empty object
*/ */
api.selectChallengeWinner = { api.selectChallengeWinner = {
method: 'POST', method: 'POST',

View File

@@ -27,7 +27,7 @@ let api = {};
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiSuccess {Array} chat An array of chat messages * @apiSuccess {Array} data An array of chat messages
*/ */
api.getChat = { api.getChat = {
method: 'GET', method: 'GET',
@@ -54,11 +54,11 @@ api.getChat = {
* @apiName PostCat * @apiName PostCat
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {UUID} groupId The group _id * @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {message} message The chat's message * @apiParam {message} Body parameter - message The message to post
* @apiParam {previousMsg} previousMsg The previous chat message which will force a return of the full group chat * @apiParam {previousMsg} previousMsg Query parameter - The previous chat message which will force a return of the full group chat
* *
* @apiSuccess {Array} chat An array of chat messages * @apiSuccess data An array of chat messages if a new message was posted after previousMsg, otherwise the posted message
*/ */
api.postChat = { api.postChat = {
method: 'POST', method: 'POST',
@@ -107,10 +107,10 @@ api.postChat = {
* @apiName LikeChat * @apiName LikeChat
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {groupId} groupId The group _id * @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message _id * @apiParam {chatId} chatId The chat message _id
* *
* @apiSuccess {Array} chat An array of chat messages * @apiSuccess {Object} data The liked chat message
*/ */
api.likeChat = { api.likeChat = {
method: 'POST', method: 'POST',
@@ -154,10 +154,10 @@ api.likeChat = {
* @apiName LikeChat * @apiName LikeChat
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {groupId} groupId The group _id * @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message _id * @apiParam {chatId} chatId The chat message id
* *
* @apiSuccess {Array} chat An array of chat messages * @apiSuccess {object} data The flagged chat message
*/ */
api.flagChat = { api.flagChat = {
method: 'POST', method: 'POST',
@@ -255,14 +255,15 @@ api.flagChat = {
/** /**
* @api {post} /api/v3/groups/:groupId/chat/:chatId/clear-flags Clear a group chat message's flags * @api {post} /api/v3/groups/:groupId/chat/:chatId/clear-flags Clear a group chat message's flags
* @apiDescription Admin-only
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName ClearFlags * @apiName ClearFlags
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {groupId} groupId The group _id * @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message _id * @apiParam {chatId} chatId The chat message id
* *
* @apiSuccess {Object} An empty object * @apiSuccess {Object} data An empty object
*/ */
api.clearChatFlags = { api.clearChatFlags = {
method: 'Post', method: 'Post',
@@ -306,7 +307,9 @@ api.clearChatFlags = {
* @apiName SeenChat * @apiName SeenChat
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {groupId} groupId The group _id * @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
*
* @apiSuccess {Object} data An empty object
*/ */
api.seenChat = { api.seenChat = {
method: 'POST', method: 'POST',
@@ -328,7 +331,7 @@ api.seenChat = {
update.$unset[`newMessages.${groupId}`] = true; update.$unset[`newMessages.${groupId}`] = true;
await User.update({_id: user._id}, update).exec(); await User.update({_id: user._id}, update).exec();
res.respond(200); res.respond(200, {});
}, },
}; };
@@ -338,11 +341,12 @@ api.seenChat = {
* @apiName DeleteChat * @apiName DeleteChat
* @apiGroup Chat * @apiGroup Chat
* *
* @apiParam {string} previousMsg Query parameter - The last message fetched by the client so that the whole chat will be returned only if new messages have been posted in the meantime
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {string} chatId The chat _id * @apiParam {string} chatId The chat message id
* *
* @apiSuccess {Array} The update chat array * @apiSuccess data The updated chat array or an empty object if no message was posted after previousMsg
* @apiSuccess {Object} An empty object when the previous message was deleted * @apiSuccess {Object} data An empty object when the previous message was deleted
*/ */
api.deleteChat = { api.deleteChat = {
method: 'DELETE', method: 'DELETE',

View File

@@ -61,14 +61,15 @@ async function saveContentToDisk (language, content) {
} }
/** /**
* @api {get} /api/v3/content Get all available content objects. Does not require authentication. * @api {get} /api/v3/content Get all available content objects.
* @apiDescription Does not require authentication.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName ContentGet * @apiName ContentGet
* @apiGroup Content * @apiGroup Content
* *
* @apiParam {string} language Optional query parameter, the language code used for the items' strings. Defaulting to english * @apiParam {string} language Query parameter, the language code used for the items' strings. Defaulting to english
* *
* @apiSuccess {Object} content All the content available on Habitica * @apiSuccess {Object} data All the content available on Habitica
*/ */
api.getContent = { api.getContent = {
method: 'GET', method: 'GET',
@@ -95,7 +96,7 @@ api.getContent = {
res.set({ res.set({
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}); });
res.status(200).send(content); res.status(200).send(content); // TODO how to use res.respond here?
// save the file in background unless it's already cached or being written right now // save the file in background unless it's already cached or being written right now
if (cachedContentResponses[language] !== true && cacheBeingWritten[language] !== true) { if (cachedContentResponses[language] !== true && cacheBeingWritten[language] !== true) {

View File

@@ -11,12 +11,13 @@ import couponCode from 'coupon-code';
let api = {}; let api = {};
/** /**
* @api {get} /api/v3/coupons Get coupons (sudo users only) * @api {get} /api/v3/coupons Get coupons
* @apiDescription Sudo users only
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetCoupons * @apiName GetCoupons
* @apiGroup Coupon * @apiGroup Coupon
* *
* @apiSuccess string Coupons in CSV format * @apiSuccess {string} Coupons in CSV format
*/ */
api.getCoupons = { api.getCoupons = {
method: 'GET', method: 'GET',
@@ -39,7 +40,8 @@ api.getCoupons = {
}; };
/** /**
* @api {post} /api/v3/coupons/generate/:event Generate coupons for an event (sudo users only) * @api {post} /api/v3/coupons/generate/:event Generate coupons for an event
* @apiDescription Sudo users only
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GenerateCoupons * @apiName GenerateCoupons
* @apiGroup Coupon * @apiGroup Coupon
@@ -47,7 +49,7 @@ api.getCoupons = {
* @apiParam {string} event The event for which the coupon should be generated * @apiParam {string} event The event for which the coupon should be generated
* @apiParam {number} count Query parameter to specify the number of coupon codes to generate * @apiParam {number} count Query parameter to specify the number of coupon codes to generate
* *
* @apiSuccess array Generated coupons * @apiSuccess {array} data Generated coupons
*/ */
api.generateCoupons = { api.generateCoupons = {
method: 'POST', method: 'POST',
@@ -73,7 +75,7 @@ api.generateCoupons = {
* *
* @apiParam {string} code The coupon code to apply * @apiParam {string} code The coupon code to apply
* *
* @apiSuccess object User object * @apiSuccess {object} data User object
*/ */
api.enterCouponCode = { api.enterCouponCode = {
method: 'POST', method: 'POST',
@@ -98,7 +100,7 @@ api.enterCouponCode = {
* @apiName ValidateCoupon * @apiName ValidateCoupon
* @apiGroup Coupon * @apiGroup Coupon
* *
* @apiSuccess valid {boolean} true or false * @apiSuccess {boolean} data.valid True or false
*/ */
api.validateCoupon = { api.validateCoupon = {
method: 'POST', method: 'POST',

View File

@@ -4,12 +4,13 @@ import ensureDevelpmentMode from '../../middlewares/api-v3/ensureDevelpmentMode'
let api = {}; let api = {};
/** /**
* @api {post} /api/v3/debug/add-ten-gems Add ten gems to the current user * @api {post} /api/v3/debug/add-ten-gems Add ten gems to the current user.
* @apiDescription Only available in development mode.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName AddTenGems * @apiName AddTenGems
* @apiGroup Development * @apiGroup Development
* *
* @apiSuccess {Object} empty An empty Object * @apiSuccess {Object} data An empty Object
*/ */
api.addTenGems = { api.addTenGems = {
method: 'POST', method: 'POST',
@@ -27,12 +28,13 @@ api.addTenGems = {
}; };
/** /**
* @api {post} /api/v3/debug/add-hourglass Add Hourglass to the current user * @api {post} /api/v3/debug/add-hourglass Add Hourglass to the current user.
* @apiDescription Only available in development mode.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName AddHourglass * @apiName AddHourglass
* @apiGroup Development * @apiGroup Development
* *
* @apiSuccess {Object} empty An empty Object * @apiSuccess {Object} data An empty Object
*/ */
api.addHourglass = { api.addHourglass = {
method: 'POST', method: 'POST',

View File

@@ -7,21 +7,22 @@ import {
let api = {}; let api = {};
// TODO move to top-level controllers?
/** /**
* @api {get} /api/v3/email/unsubscribe Unsubscribe an email or user from email notifications * @api {get} /api/v3/email/unsubscribe Unsubscribe an email or user from email notifications
* @apiDescription Does not require authentication
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName UnsubscribeEmail * @apiName UnsubscribeEmail
* @apiGroup Unsubscribe * @apiGroup Unsubscribe
* @apiDescription This is a GET method so that you can put the unsubscribe link in emails. * @apiDescription This is a GET method so that you can put the unsubscribe link in emails.
* *
* @apiParam {String} code An unsubscription code * @apiParam {String} code Query parameter - An unsubscription code
* *
* @apiSuccess {String} okRes An message stating the user/email unsubscribed successfully * @apiSuccess {String} An html success message
*/ */
api.unsubscribe = { api.unsubscribe = {
method: 'GET', method: 'GET',
url: '/email/unsubscribe', url: '/email/unsubscribe',
middlewares: [],
async handler (req, res) { async handler (req, res) {
req.checkQuery({ req.checkQuery({
code: { code: {

View File

@@ -24,15 +24,13 @@ import common from '../../../../common';
import sendPushNotification from '../../libs/api-v3/pushNotifications'; import sendPushNotification from '../../libs/api-v3/pushNotifications';
let api = {}; let api = {};
// TODO shall we accept party as groupId in all routes?
/** /**
* @api {post} /api/v3/groups Create group * @api {post} /api/v3/groups Create group
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName CreateGroup * @apiName CreateGroup
* @apiGroup Group * @apiGroup Group
* *
* @apiSuccess {Object} group The group object * @apiSuccess {Object} data The create group
*/ */
api.createGroup = { api.createGroup = {
method: 'POST', method: 'POST',
@@ -40,7 +38,7 @@ api.createGroup = {
middlewares: [authWithHeaders()], middlewares: [authWithHeaders()],
async handler (req, res) { async handler (req, res) {
let user = res.locals.user; let user = res.locals.user;
let group = new Group(Group.sanitize(req.body)); // TODO validate empty req.body let group = new Group(Group.sanitize(req.body));
group.leader = user._id; group.leader = user._id;
if (group.type === 'guild') { if (group.type === 'guild') {
@@ -60,7 +58,7 @@ api.createGroup = {
let results = await Q.all([user.save(), group.save()]); let results = await Q.all([user.save(), group.save()]);
let savedGroup = results[1]; let savedGroup = results[1];
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
// await Q.ninvoke(savedGroup, 'populate', ['leader', nameFields]); // doc.populate doesn't return a promise // await Q.ninvoke(savedGroup, 'populate', ['leader', nameFields]); // doc.populate doesn't return a promise
let response = savedGroup.toJSON(); let response = savedGroup.toJSON();
// the leader is the authenticated user // the leader is the authenticated user
@@ -76,14 +74,14 @@ api.createGroup = {
}; };
/** /**
* @api {get} /api/v3/groups Get groups * @api {get} /api/v3/groups Get groups for a user
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetGroups * @apiName GetGroups
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {string} type The type of groups to retrieve. Must be a query string representing a list of values like 'tavern,party'. Possible values are party, privateGuilds, publicGuilds, tavern * @apiParam {string} type The type of groups to retrieve. Must be a query string representing a list of values like 'tavern,party'. Possible values are party, privateGuilds, publicGuilds, tavern
* *
* @apiSuccess {Array} groups An array of the requested groups * @apiSuccess {Array} data An array of the requested groups
*/ */
api.getGroups = { api.getGroups = {
method: 'GET', method: 'GET',
@@ -92,7 +90,7 @@ api.getGroups = {
async handler (req, res) { async handler (req, res) {
let user = res.locals.user; let user = res.locals.user;
req.checkQuery('type', res.t('groupTypesRequired')).notEmpty(); // TODO better validation req.checkQuery('type', res.t('groupTypesRequired')).notEmpty();
let validationErrors = req.validationErrors(); let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;
@@ -119,7 +117,7 @@ api.getGroups = {
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiSuccess {Object} group The group object * @apiSuccess {Object} data The group object
*/ */
api.getGroup = { api.getGroup = {
method: 'GET', method: 'GET',
@@ -137,7 +135,7 @@ api.getGroup = {
if (!group) throw new NotFound(res.t('groupNotFound')); if (!group) throw new NotFound(res.t('groupNotFound'));
group = Group.toJSONCleanChat(group, user); group = Group.toJSONCleanChat(group, user);
// TODO Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833 // Instead of populate we make a find call manually because of https://github.com/Automattic/mongoose/issues/3833
let leader = await User.findById(group.leader).select(nameFields).exec(); let leader = await User.findById(group.leader).select(nameFields).exec();
if (leader) group.leader = leader.toJSON({minimize: true}); if (leader) group.leader = leader.toJSON({minimize: true});
@@ -153,7 +151,7 @@ api.getGroup = {
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiSuccess {Object} group The updated group object * @apiSuccess {Object} data The updated group
*/ */
api.updateGroup = { api.updateGroup = {
method: 'PUT', method: 'PUT',
@@ -197,9 +195,9 @@ api.updateGroup = {
* @apiName JoinGroup * @apiName JoinGroup
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {UUID} groupId The group _id * @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiSuccess {Object} group The group * @apiSuccess {Object} data The joined group
*/ */
api.joinGroup = { api.joinGroup = {
method: 'POST', method: 'POST',
@@ -288,9 +286,9 @@ api.joinGroup = {
* @apiName RejectGroupInvite * @apiName RejectGroupInvite
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {UUID} groupId The group _id * @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiSuccess {Object} group The group * @apiSuccess {Object} data An empty object
*/ */
api.rejectGroupInvite = { api.rejectGroupInvite = {
method: 'POST', method: 'POST',
@@ -334,9 +332,9 @@ api.rejectGroupInvite = {
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {string="remove-all","keep-all"} keep Wheter to keep or not challenges' tasks, as an optional query string * @apiParam {string="remove-all","keep-all"} keep Query parameter - Whether to keep or not challenges' tasks. Defaults to keep-all
* *
* @apiSuccess {Object} empty An empty object * @apiSuccess {Object} data An empty object
*/ */
api.leaveGroup = { api.leaveGroup = {
method: 'POST', method: 'POST',
@@ -391,9 +389,9 @@ function _sendMessageToRemoved (group, removedUser, message) {
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} memberId The _id of the member to remove * @apiParam {UUID} memberId The _id of the member to remove
* @apiParam {string} message The message to send to the removed members, as a query string // TODO in req.body? * @apiParam {string} message Query parameter - The message to send to the removed members
* *
* @apiSuccess {Object} empty An empty object * @apiSuccess {Object} data An empty object
*/ */
api.removeGroupMember = { api.removeGroupMember = {
method: 'POST', method: 'POST',
@@ -448,7 +446,7 @@ api.removeGroupMember = {
if (isInGroup === 'guild') { if (isInGroup === 'guild') {
removeFromArray(member.guilds, group._id); removeFromArray(member.guilds, group._id);
} }
if (isInGroup === 'party') member.party._id = undefined; // TODO remove quest information too? if (isInGroup === 'party') member.party._id = undefined; // TODO remove quest information too? Use group.leave()?
if (member.newMessages[group._id]) { if (member.newMessages[group._id]) {
member.newMessages[group._id] = undefined; member.newMessages[group._id] = undefined;
@@ -456,13 +454,16 @@ api.removeGroupMember = {
} }
if (group.quest && group.quest.active && group.quest.leader === member._id) { if (group.quest && group.quest.active && group.quest.leader === member._id) {
member.items.quests[group.quest.key] += 1; // TODO why this? member.items.quests[group.quest.key] += 1;
} }
} else if (isInvited) { } else if (isInvited) {
if (isInvited === 'guild') { if (isInvited === 'guild') {
removeFromArray(member.invitations.guilds, { id: group._id }); removeFromArray(member.invitations.guilds, { id: group._id });
} }
if (isInvited === 'party') user.invitations.party = {}; // TODO mark modified? if (isInvited === 'party') {
user.invitations.party = {};
user.markModified('invitations.party');
}
} else { } else {
throw new NotFound(res.t('groupMemberNotFound')); throw new NotFound(res.t('groupMemberNotFound'));
} }
@@ -592,11 +593,11 @@ async function _inviteByEmail (invite, group, inviter, req, res) {
* *
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted) * @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* *
* @apiParam {array} emails An array of emails addresses to invite (optional) (inside body) * @apiParam {array} emails Body parameter - An array of emails addresses to invite (optional)
* @apiParam {array} uuids An array of uuids to invite (optional) (inside body) * @apiParam {array} uuids Body parameter - An array of uuids to invite (optional)
* @apiParam {string} inviter The inviters' name (optional) (inside body) * @apiParam {string} inviter Body parameter - The inviters' name (optional)
* *
* @apiSuccess {Object} empty An empty object * @apiSuccess {array} data The invites
*/ */
api.inviteToGroup = { api.inviteToGroup = {
method: 'POST', method: 'POST',

View File

@@ -9,14 +9,15 @@ import _ from 'lodash';
let api = {}; let api = {};
/** /**
* @api {get} /api/v3/hall/patrons Get all Patrons. Only the first 50 patrons are returned. More can be accessed passing ?page=n. * @api {get} /api/v3/hall/patrons Get all Patrons.
* @apiDescription Only the first 50 patrons are returned. More can be accessed passing ?page=n.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetPatrons * @apiName GetPatrons
* @apiGroup Hall * @apiGroup Hall
* *
* @apiParam {Number} page The result page. Default is 0 * @apiParam {Number} page Query Parameter - The result page. Default is 0
* *
* @apiSuccess {Array} patron An array of patrons * @apiSuccess {Array} data An array of patrons
*/ */
api.getPatrons = { api.getPatrons = {
method: 'GET', method: 'GET',
@@ -52,7 +53,7 @@ api.getPatrons = {
* @apiName GetHeroes * @apiName GetHeroes
* @apiGroup Hall * @apiGroup Hall
* *
* @apiSuccess {Array} hero An array of heroes * @apiSuccess {Array} data An array of heroes
*/ */
api.getHeroes = { api.getHeroes = {
method: 'GET', method: 'GET',
@@ -74,17 +75,17 @@ api.getHeroes = {
// Note, while the following routes are called getHero / updateHero // Note, while the following routes are called getHero / updateHero
// they can be used by admins to get/update any user // they can be used by admins to get/update any user
// TODO rename?
const heroAdminFields = 'contributor balance profile.name purchased items auth'; const heroAdminFields = 'contributor balance profile.name purchased items auth';
/** /**
* @api {get} /api/v3/hall/heroes/:heroId Get an hero given his _id. Must be an admin to make this request * @api {get} /api/v3/hall/heroes/:heroId Get an hero given his _id.
* @apiDescription Must be an admin to make this request
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetHero * @apiName GetHero
* @apiGroup Hall * @apiGroup Hall
* *
* @apiSuccess {Object} hero The hero object * @apiSuccess {Object} data The hero object
*/ */
api.getHero = { api.getHero = {
method: 'GET', method: 'GET',
@@ -116,12 +117,13 @@ api.getHero = {
const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0}; const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
/** /**
* @api {put} /api/v3/hall/heroes/:heroId Update an hero. Must be an admin to make this request * @api {put} /api/v3/hall/heroes/:heroId Update an hero.
* @apiDescription Must be an admin to make this request
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName UpdateHero * @apiName UpdateHero
* @apiGroup Hall * @apiGroup Hall
* *
* @apiSuccess {Object} hero The updated hero object * @apiSuccess {Object} data The updated hero object
*/ */
api.updateHero = { api.updateHero = {
method: 'PUT', method: 'PUT',
@@ -162,7 +164,7 @@ api.updateHero = {
if (updateData.itemPath && updateData.itemVal && if (updateData.itemPath && updateData.itemVal &&
updateData.itemPath.indexOf('items.') === 0 && updateData.itemPath.indexOf('items.') === 0 &&
User.schema.paths[updateData.itemPath]) { User.schema.paths[updateData.itemPath]) {
_.set(hero, updateData.itemPath, updateData.itemVal); // Sanitization at 5c30944 (deemed unnecessary) TODO review _.set(hero, updateData.itemPath, updateData.itemVal); // Sanitization at 5c30944 (deemed unnecessary)
} }
if (updateData.auth && _.isBoolean(updateData.auth.blocked)) hero.auth.blocked = updateData.auth.blocked; if (updateData.auth && _.isBoolean(updateData.auth.blocked)) hero.auth.blocked = updateData.auth.blocked;

View File

@@ -27,7 +27,7 @@ let api = {};
* *
* @apiParam {UUID} memberId The member's id * @apiParam {UUID} memberId The member's id
* *
* @apiSuccess {object} member The member object * @apiSuccess {object} data The member object
*/ */
api.getMember = { api.getMember = {
method: 'GET', method: 'GET',
@@ -129,7 +129,8 @@ function _getMembersForItem (type) {
} }
/** /**
* @api {get} /api/v3/groups/:groupId/members Get members for a group with a limit of 30 member per request. To get all members run requests against this routes (updating the lastId query parameter) until you get less than 30 results. * @api {get} /api/v3/groups/:groupId/members Get members for a group
* @apiDescription With a limit of 30 member per request. To get all members run requests against this routes (updating the lastId query parameter) until you get less than 30 results.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetMembersForGroup * @apiName GetMembersForGroup
* @apiGroup Member * @apiGroup Member
@@ -138,7 +139,7 @@ function _getMembersForItem (type) {
* @apiParam {UUID} lastId Query parameter to specify the last member returned in a previous request to this route and get the next batch of results * @apiParam {UUID} lastId Query parameter to specify the last member returned in a previous request to this route and get the next batch of results
* @apiParam {boolean} includeAllPublicFields Query parameter available only when fetching a party. If === `true` then all public fields for members will be returned (liek when making a request for a single member) * @apiParam {boolean} includeAllPublicFields Query parameter available only when fetching a party. If === `true` then all public fields for members will be returned (liek when making a request for a single member)
* *
* @apiSuccess {array} members An array of members, sorted by _id * @apiSuccess {array} data An array of members, sorted by _id
*/ */
api.getMembersForGroup = { api.getMembersForGroup = {
method: 'GET', method: 'GET',
@@ -148,7 +149,8 @@ api.getMembersForGroup = {
}; };
/** /**
* @api {get} /api/v3/groups/:groupId/invites Get invites for a group with a limit of 30 member per request. To get all invites run requests against this routes (updating the lastId query parameter) until you get less than 30 results. * @api {get} /api/v3/groups/:groupId/invites Get invites for a group
* @apiDescription With a limit of 30 member per request. To get all invites run requests against this routes (updating the lastId query parameter) until you get less than 30 results.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetInvitesForGroup * @apiName GetInvitesForGroup
* @apiGroup Member * @apiGroup Member
@@ -156,7 +158,7 @@ api.getMembersForGroup = {
* @apiParam {UUID} groupId The group id * @apiParam {UUID} groupId The group id
* @apiParam {UUID} lastId Query parameter to specify the last invite returned in a previous request to this route and get the next batch of results * @apiParam {UUID} lastId Query parameter to specify the last invite returned in a previous request to this route and get the next batch of results
* *
* @apiSuccess {array} invites An array of invites, sorted by _id * @apiSuccess {array} data An array of invites, sorted by _id
*/ */
api.getInvitesForGroup = { api.getInvitesForGroup = {
method: 'GET', method: 'GET',
@@ -166,7 +168,8 @@ api.getInvitesForGroup = {
}; };
/** /**
* @api {get} /api/v3/challenges/:challengeId/members Get members for a challenge with a limit of 30 member per request. To get all members run requests against this routes (updating the lastId query parameter) until you get less than 30 results. * @api {get} /api/v3/challenges/:challengeId/members Get members for a challenge
* @apiDescription With a limit of 30 member per request. To get all members run requests against this routes (updating the lastId query parameter) until you get less than 30 results.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetMembersForChallenge * @apiName GetMembersForChallenge
* @apiGroup Member * @apiGroup Member
@@ -174,7 +177,7 @@ api.getInvitesForGroup = {
* @apiParam {UUID} challengeId The challenge id * @apiParam {UUID} challengeId The challenge id
* @apiParam {UUID} lastId Query parameter to specify the last member returned in a previous request to this route and get the next batch of results * @apiParam {UUID} lastId Query parameter to specify the last member returned in a previous request to this route and get the next batch of results
* *
* @apiSuccess {array} members An array of members, sorted by _id * @apiSuccess {array} data An array of members, sorted by _id
*/ */
api.getMembersForChallenge = { api.getMembersForChallenge = {
method: 'GET', method: 'GET',
@@ -192,7 +195,7 @@ api.getMembersForChallenge = {
* @apiParam {UUID} challengeId The challenge _id * @apiParam {UUID} challengeId The challenge _id
* @apiParam {UUID} member The member _id * @apiParam {UUID} member The member _id
* *
* @apiSuccess {object} member Return an object with member _id, profile.name and a tasks object with the challenge tasks for the member * @apiSuccess {object} data Return an object with member _id, profile.name and a tasks object with the challenge tasks for the member
*/ */
api.getChallengeMemberProgress = { api.getChallengeMemberProgress = {
method: 'GET', method: 'GET',
@@ -242,10 +245,10 @@ api.getChallengeMemberProgress = {
* @apiName SendPrivateMessage * @apiName SendPrivateMessage
* @apiGroup Members * @apiGroup Members
* *
* @apiParam {String} message The message * @apiParam {String} message Body parameter - The message
* @apiParam {UUID} toUserId The toUser _id * @apiParam {UUID} toUserId Body parameter - The user to contact
* *
* @apiSuccess {Object} empty An empty Object * @apiSuccess {Object} data An empty Object
*/ */
api.sendPrivateMessage = { api.sendPrivateMessage = {
method: 'POST', method: 'POST',
@@ -291,10 +294,10 @@ api.sendPrivateMessage = {
* @apiName TransferGems * @apiName TransferGems
* @apiGroup Members * @apiGroup Members
* *
* @apiParam {String} message The message * @apiParam {String} message Body parameter The message
* @apiParam {UUID} toUserId The toUser _id * @apiParam {UUID} toUserId Body parameter The toUser _id
* *
* @apiSuccess {Object} empty An empty Object * @apiSuccess {Object} data An empty Object
*/ */
api.transferGems = { api.transferGems = {
method: 'POST', method: 'POST',
@@ -346,7 +349,7 @@ api.transferGems = {
]); ]);
} }
// @TODO: Add push notifications // TODO: Add push notifications
// pushNotify.sendNotify(sender, res.t('giftedGems'), res.t('giftedGemsInfo', { amount: gemAmount, name: byUsername })); // pushNotify.sendNotify(sender, res.t('giftedGems'), res.t('giftedGemsInfo', { amount: gemAmount, name: byUsername }));
res.respond(200, {}); res.respond(200, {});

View File

@@ -6,18 +6,19 @@ let tasksModels = ['habit', 'daily', 'todo', 'reward'];
let allModels = ['user', 'tag', 'challenge', 'group'].concat(tasksModels); let allModels = ['user', 'tag', 'challenge', 'group'].concat(tasksModels);
/** /**
* @api {get} /api/v3/meta/models/:model/paths Get all paths for the specified model. Doesn't require authentication * @api {get} /api/v3s/models/:model/paths Get all paths for the specified model.
* @apiDescription Doesn't require authentication
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetUserModelPaths * @apiName GetUserModelPaths
* @apiGroup Meta * @apiGroup Meta
* *
* @apiParam {string="user","group","challenge","tag","habit","daily","todo","reward"} model The name of the model * @apiParam {string="user","group","challenge","tag","habit","daily","todo","reward"} model The name of the model
* *
* @apiSuccess {object} paths A key-value object made of fieldPath: fieldType (like {'field.nested': Boolean}) * @apiSuccess {object} data A key-value object made of fieldPath: fieldType (like {'field.nested': Boolean})
*/ */
api.getModelPaths = { api.getModelPaths = {
method: 'GET', method: 'GET',
url: '/meta/models/:model/paths', url: '/models/:model/paths',
async handler (req, res) { async handler (req, res) {
req.checkParams('model', res.t('modelNotFound')).notEmpty().isIn(allModels); req.checkParams('model', res.t('modelNotFound')).notEmpty().isIn(allModels);

View File

@@ -35,8 +35,9 @@ let api = {};
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* @apiParam {string} questKey
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest object
*/ */
api.inviteToQuest = { api.inviteToQuest = {
method: 'POST', method: 'POST',
@@ -139,7 +140,7 @@ api.inviteToQuest = {
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.acceptQuest = { api.acceptQuest = {
method: 'POST', method: 'POST',
@@ -196,7 +197,7 @@ api.acceptQuest = {
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.rejectQuest = { api.rejectQuest = {
method: 'POST', method: 'POST',
@@ -250,12 +251,12 @@ api.rejectQuest = {
/** /**
* @api {post} /api/v3/groups/:groupId/quests/force-start Accept a pending quest * @api {post} /api/v3/groups/:groupId/quests/force-start Accept a pending quest
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName forceStart * @apiName ForceQuestStart
* @apiGroup Group * @apiGroup Group
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.forceStart = { api.forceStart = {
method: 'POST', method: 'POST',
@@ -307,7 +308,7 @@ api.forceStart = {
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.cancelQuest = { api.cancelQuest = {
method: 'POST', method: 'POST',
@@ -356,7 +357,7 @@ api.cancelQuest = {
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.abortQuest = { api.abortQuest = {
method: 'POST', method: 'POST',
@@ -410,7 +411,7 @@ api.abortQuest = {
* *
* @apiParam {string} groupId The group _id (or 'party') * @apiParam {string} groupId The group _id (or 'party')
* *
* @apiSuccess {Object} quest Quest Object * @apiSuccess {Object} data Quest Object
*/ */
api.leaveQuest = { api.leaveQuest = {
method: 'POST', method: 'POST',

View File

@@ -6,7 +6,7 @@ let api = {};
* @apiName GetStatus * @apiName GetStatus
* @apiGroup Status * @apiGroup Status
* *
* @apiSuccess {status} string 'up' if everything is ok * @apiSuccess {status} data.status 'up' if everything is ok
*/ */
api.getStatus = { api.getStatus = {
method: 'GET', method: 'GET',

View File

@@ -14,7 +14,7 @@ let api = {};
* @apiName CreateTag * @apiName CreateTag
* @apiGroup Tag * @apiGroup Tag
* *
* @apiSuccess {Object} tag The newly created tag * @apiSuccess {Object} data The newly created tag
*/ */
api.createTag = { api.createTag = {
method: 'POST', method: 'POST',
@@ -38,7 +38,7 @@ api.createTag = {
* @apiName GetTags * @apiName GetTags
* @apiGroup Tag * @apiGroup Tag
* *
* @apiSuccess {Array} tags An array of tag objects * @apiSuccess {Array} data An array of tags
*/ */
api.getTags = { api.getTags = {
method: 'GET', method: 'GET',
@@ -58,7 +58,7 @@ api.getTags = {
* *
* @apiParam {UUID} tagId The tag _id * @apiParam {UUID} tagId The tag _id
* *
* @apiSuccess {object} tag The tag object * @apiSuccess {object} data The tag object
*/ */
api.getTag = { api.getTag = {
method: 'GET', method: 'GET',
@@ -86,7 +86,7 @@ api.getTag = {
* *
* @apiParam {UUID} tagId The tag _id * @apiParam {UUID} tagId The tag _id
* *
* @apiSuccess {object} tag The updated tag * @apiSuccess {object} data The updated tag
*/ */
api.updateTag = { api.updateTag = {
method: 'PUT', method: 'PUT',
@@ -120,7 +120,7 @@ api.updateTag = {
* *
* @apiParam {UUID} tagId The tag _id * @apiParam {UUID} tagId The tag _id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data An empty object
*/ */
api.deleteTag = { api.deleteTag = {
method: 'DELETE', method: 'DELETE',

View File

@@ -54,13 +54,13 @@ async function _createTasks (req, res, user, challenge) {
} }
/** /**
* @api {post} /api/v3/tasks/user Create a new task belonging to the autheticated user. Can be passed an object to create a single task or an array of objects to create multiple tasks. * @api {post} /api/v3/tasks/user Create a new task the user.
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName CreateUserTasks * @apiName CreateUserTasks
* @apiGroup Task * @apiGroup Task
* *
* @apiSuccess {Object} task The newly created task * @apiSuccess data An object if a single task was created, otherwise an array of tasks
* @apiSuccess {Object[]} tasks The newly created tasks (if more than one was created)
*/ */
api.createUserTasks = { api.createUserTasks = {
method: 'POST', method: 'POST',
@@ -73,15 +73,15 @@ api.createUserTasks = {
}; };
/** /**
* @api {post} /api/v3/tasks/challenge/:challengeId Create a new task belonging to the challenge. Can be passed an object to create a single task or an array of objects to create multiple tasks. * @api {post} /api/v3/tasks/challenge/:challengeId Create a new task belonging to a challenge.
* @apiDescription Can be passed an object to create a single task or an array of objects to create multiple tasks.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName CreateChallengeTasks * @apiName CreateChallengeTasks
* @apiGroup Task * @apiGroup Task
* *
* @apiParam {UUID} challengeId The id of the challenge the new task(s) will belong to. * @apiParam {UUID} challengeId The id of the challenge the new task(s) will belong to.
* *
* @apiSuccess {Object} task The newly created task * @apiSuccess data An object if a single task was created, otherwise an array of tasks
* @apiSuccess {Object[]} tasks The newly created tasks (if more than one was created)
*/ */
api.createChallengeTasks = { api.createChallengeTasks = {
method: 'POST', method: 'POST',
@@ -171,7 +171,7 @@ async function _getTasks (req, res, user, challenge) {
* *
* @apiParam {string="habits","dailys","todos","rewards","completedTodos"} type Optional query parameter to return just a type of tasks. By default all types will be returned except completed todos that requested separately. * @apiParam {string="habits","dailys","todos","rewards","completedTodos"} type Optional query parameter to return just a type of tasks. By default all types will be returned except completed todos that requested separately.
* *
* @apiSuccess {Array} tasks An array of task objects * @apiSuccess {Array} data An array of tasks
*/ */
api.getUserTasks = { api.getUserTasks = {
method: 'GET', method: 'GET',
@@ -198,7 +198,7 @@ api.getUserTasks = {
* @apiParam {UUID} challengeId The id of the challenge from which to retrieve the tasks. * @apiParam {UUID} challengeId The id of the challenge from which to retrieve the tasks.
* @apiParam {string="habits","dailys","todos","rewards"} type Optional query parameter to return just a type of tasks * @apiParam {string="habits","dailys","todos","rewards"} type Optional query parameter to return just a type of tasks
* *
* @apiSuccess {Array} tasks An array of task objects * @apiSuccess {Array} data An array of tasks
*/ */
api.getChallengeTasks = { api.getChallengeTasks = {
method: 'GET', method: 'GET',
@@ -225,14 +225,14 @@ api.getChallengeTasks = {
}; };
/** /**
* @api {get} /api/v3/task/:taskId Get a task given its id * @api {get} /api/v3/task/:taskId Get a task
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName GetTask * @apiName GetTask
* @apiGroup Task * @apiGroup Task
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* *
* @apiSuccess {object} task The task object * @apiSuccess {object} data The task object
*/ */
api.getTask = { api.getTask = {
method: 'GET', method: 'GET',
@@ -273,7 +273,7 @@ api.getTask = {
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* *
* @apiSuccess {object} task The updated task * @apiSuccess {object} data The updated task
*/ */
api.updateTask = { api.updateTask = {
method: 'PUT', method: 'PUT',
@@ -284,8 +284,6 @@ api.updateTask = {
let challenge; let challenge;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID(); req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
// TODO check that req.body isn't empty
// TODO make sure tags are updated correctly (they aren't set as modified!) maybe use specific routes
let validationErrors = req.validationErrors(); let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;
@@ -304,10 +302,10 @@ api.updateTask = {
throw new NotFound(res.t('taskNotFound')); throw new NotFound(res.t('taskNotFound'));
} }
// TODO we have to convert task to an object because otherwise things don't get merged correctly. Bad for performances? // we have to convert task to an object because otherwise things don't get merged correctly. Bad for performances?
// TODO regarding comment above, make sure other models with nested fields are using this trick too // TODO regarding comment above, make sure other models with nested fields are using this trick too
_.assign(task, Tasks.Task.sanitize(common.ops.updateTask(task.toObject(), req))); _.assign(task, Tasks.Task.sanitize(common.ops.updateTask(task.toObject(), req)));
// TODO console.log(task.modifiedPaths(), task.toObject().repeat === tep) // console.log(task.modifiedPaths(), task.toObject().repeat === tep)
// repeat is always among modifiedPaths because mongoose changes the other of the keys when using .toObject() // repeat is always among modifiedPaths because mongoose changes the other of the keys when using .toObject()
// see https://github.com/Automattic/mongoose/issues/2749 // see https://github.com/Automattic/mongoose/issues/2749
@@ -351,7 +349,9 @@ function _generateWebhookTaskData (task, direction, delta, stats, user) {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {string="up","down"} direction The direction for scoring the task * @apiParam {string="up","down"} direction The direction for scoring the task
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data._tmp If an item was dropped it'll be returned in te _tmp object
* @apiSuccess {number} data.delta
* @apiSuccess {object} data The user stats
*/ */
api.scoreTask = { api.scoreTask = {
method: 'POST', method: 'POST',
@@ -389,7 +389,7 @@ api.scoreTask = {
let hasTask = removeFromArray(user.tasksOrder.todos, task._id); let hasTask = removeFromArray(user.tasksOrder.todos, task._id);
if (!hasTask) { if (!hasTask) {
user.tasksOrder.todos.push(task._id); // TODO push at the top? user.tasksOrder.todos.push(task._id); // TODO push at the top?
} // If for some reason it hadn't been removed previously don't do anything TODO ok? } // If for some reason it hadn't been removed previously don't do anything
} }
} }
@@ -406,7 +406,6 @@ api.scoreTask = {
sendTaskWebhook(user.preferences.webhooks, _generateWebhookTaskData(task, direction, delta, userStats, user)); sendTaskWebhook(user.preferences.webhooks, _generateWebhookTaskData(task, direction, delta, userStats, user));
// TODO test?
if (task.challenge.id && task.challenge.taskId && !task.challenge.broken && task.type !== 'reward') { 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 // 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 { try {
@@ -423,7 +422,6 @@ api.scoreTask = {
}; };
// completed todos cannot be moved, they'll be returned ordered by date of completion // completed todos cannot be moved, they'll be returned ordered by date of completion
// TODO check that it works when a tag is selected or todos are split between dated and due
// TODO support challenges? // TODO support challenges?
/** /**
* @api {post} /api/v3/tasks/:taskId/move/to/:position Move a task to a new position * @api {post} /api/v3/tasks/:taskId/move/to/:position Move a task to a new position
@@ -432,9 +430,9 @@ api.scoreTask = {
* @apiGroup Task * @apiGroup Task
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {Number} position Where to move the task (-1 means push to bottom). First position is 0 * @apiParam {Number} position Query parameter - Where to move the task (-1 means push to bottom). First position is 0
* *
* @apiSuccess {object} tasksOrder The new tasks order (user.tasksOrder.{task.type}s) * @apiSuccess {array} data The new tasks order (user.tasksOrder.{task.type}s)
*/ */
api.moveTask = { api.moveTask = {
method: 'POST', method: 'POST',
@@ -481,14 +479,14 @@ api.moveTask = {
}; };
/** /**
* @api {post} /api/v3/tasks/:taskId/checklist Add an item to a checklist, creating the checklist if it doesn't exist * @api {post} /api/v3/tasks/:taskId/checklist Add an item to the task's checklist
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName AddChecklistItem * @apiName AddChecklistItem
* @apiGroup Task * @apiGroup Task
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* *
* @apiSuccess {object} task The updated task * @apiSuccess {object} data The updated task
*/ */
api.addChecklistItem = { api.addChecklistItem = {
method: 'POST', method: 'POST',
@@ -499,7 +497,6 @@ api.addChecklistItem = {
let challenge; let challenge;
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID(); req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
// TODO check that req.body isn't empty and is an array
let validationErrors = req.validationErrors(); let validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;
@@ -523,7 +520,7 @@ api.addChecklistItem = {
task.checklist.push(Tasks.Task.sanitizeChecklist(req.body)); // TODO why not allow to supply _id on creation? task.checklist.push(Tasks.Task.sanitizeChecklist(req.body)); // TODO why not allow to supply _id on creation?
let savedTask = await task.save(); let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask); if (challenge) challenge.updateTask(savedTask);
}, },
}; };
@@ -537,7 +534,7 @@ api.addChecklistItem = {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {UUID} itemId The checklist item _id * @apiParam {UUID} itemId The checklist item _id
* *
* @apiSuccess {object} task The updated task * @apiSuccess {object} data The updated task
*/ */
api.scoreCheckListItem = { api.scoreCheckListItem = {
method: 'POST', method: 'POST',
@@ -566,7 +563,7 @@ api.scoreCheckListItem = {
item.completed = !item.completed; item.completed = !item.completed;
let savedTask = await task.save(); let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return res.respond(200, savedTask);
}, },
}; };
@@ -579,7 +576,7 @@ api.scoreCheckListItem = {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {UUID} itemId The checklist item _id * @apiParam {UUID} itemId The checklist item _id
* *
* @apiSuccess {object} task The updated task * @apiSuccess {object} data The updated task
*/ */
api.updateChecklistItem = { api.updateChecklistItem = {
method: 'PUT', method: 'PUT',
@@ -616,7 +613,7 @@ api.updateChecklistItem = {
_.merge(item, Tasks.Task.sanitizeChecklist(req.body)); _.merge(item, Tasks.Task.sanitizeChecklist(req.body));
let savedTask = await task.save(); let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask); if (challenge) challenge.updateTask(savedTask);
}, },
}; };
@@ -630,7 +627,7 @@ api.updateChecklistItem = {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {UUID} itemId The checklist item _id * @apiParam {UUID} itemId The checklist item _id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data The updated task
*/ */
api.removeChecklistItem = { api.removeChecklistItem = {
method: 'DELETE', method: 'DELETE',
@@ -665,7 +662,7 @@ api.removeChecklistItem = {
if (!hasItem) throw new NotFound(res.t('checklistItemNotFound')); if (!hasItem) throw new NotFound(res.t('checklistItemNotFound'));
let savedTask = await task.save(); let savedTask = await task.save();
res.respond(200, {}); // TODO what to return res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask); if (challenge) challenge.updateTask(savedTask);
}, },
}; };
@@ -679,7 +676,7 @@ api.removeChecklistItem = {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {UUID} tagId The tag id * @apiParam {UUID} tagId The tag id
* *
* @apiSuccess {object} task The updated task * @apiSuccess {object} data The updated task
*/ */
api.addTagToTask = { api.addTagToTask = {
method: 'POST', method: 'POST',
@@ -709,12 +706,12 @@ api.addTagToTask = {
task.tags.push(tagId); task.tags.push(tagId);
let savedTask = await task.save(); let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return res.respond(200, savedTask);
}, },
}; };
/** /**
* @api {delete} /api/v3/tasks/:taskId/tags/:tagId Remove a tag * @api {delete} /api/v3/tasks/:taskId/tags/:tagId Remove a tag from atask
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName RemoveTagFromTask * @apiName RemoveTagFromTask
* @apiGroup Task * @apiGroup Task
@@ -722,7 +719,7 @@ api.addTagToTask = {
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* @apiParam {UUID} tagId The tag id * @apiParam {UUID} tagId The tag id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data The updated task
*/ */
api.removeTagFromTask = { api.removeTagFromTask = {
method: 'DELETE', method: 'DELETE',
@@ -747,8 +744,8 @@ api.removeTagFromTask = {
let hasTag = removeFromArray(task.tags, req.params.tagId); let hasTag = removeFromArray(task.tags, req.params.tagId);
if (!hasTag) throw new NotFound(res.t('tagNotFound')); if (!hasTag) throw new NotFound(res.t('tagNotFound'));
await task.save(); let savedTask = await task.save();
res.respond(200, {}); // TODO what to return res.respond(200, savedTask);
}, },
}; };
@@ -761,7 +758,7 @@ api.removeTagFromTask = {
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data An empty object
*/ */
api.unlinkTask = { api.unlinkTask = {
method: 'POST', method: 'POST',
@@ -798,7 +795,7 @@ api.unlinkTask = {
} }
} }
res.respond(200, {}); // TODO what to return res.respond(200, {});
}, },
}; };
@@ -808,7 +805,7 @@ api.unlinkTask = {
* @apiName ClearCompletedTodos * @apiName ClearCompletedTodos
* @apiGroup Task * @apiGroup Task
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data An empty object
*/ */
api.clearCompletedTodos = { api.clearCompletedTodos = {
method: 'POST', method: 'POST',
@@ -841,7 +838,7 @@ api.clearCompletedTodos = {
* *
* @apiParam {UUID} taskId The task _id * @apiParam {UUID} taskId The task _id
* *
* @apiSuccess {object} empty An empty object * @apiSuccess {object} data An empty object
*/ */
api.deleteTask = { api.deleteTask = {
method: 'DELETE', method: 'DELETE',

View File

@@ -24,7 +24,7 @@ let api = {};
* @apiName UserGet * @apiName UserGet
* @apiGroup User * @apiGroup User
* *
* @apiSuccess {Object} user The user object * @apiSuccess {Object} data The user object
*/ */
api.getUser = { api.getUser = {
method: 'GET', method: 'GET',
@@ -51,7 +51,7 @@ api.getUser = {
* @apiName UserGetBuyList * @apiName UserGetBuyList
* @apiGroup User * @apiGroup User
* *
* @apiSuccess {Object} list The buy list * @apiSuccess {Object} data The buy list
*/ */
api.getBuyList = { api.getBuyList = {
method: 'GET', method: 'GET',
@@ -141,12 +141,13 @@ let checkPreferencePurchase = (user, path, item) => {
}; };
/** /**
* @api {put} /api/v3/user Update the user. Example body: {'stats.hp':50, 'preferences.background': 'beach'} * @api {put} /api/v3/user Update the user.
* @apiDescription Example body: {'stats.hp':50, 'preferences.background': 'beach'}
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName UserUpdate * @apiName UserUpdate
* @apiGroup User * @apiGroup User
* *
* @apiSuccess user object The updated user object * @apiSuccess {object} data The updated user object
*/ */
api.updateUser = { api.updateUser = {
method: 'PUT', method: 'PUT',
@@ -175,14 +176,14 @@ api.updateUser = {
}; };
/** /**
* @api {delete} /api/v3/user DELETE an authenticated user's profile * @api {delete} /api/v3/user DELETE an authenticated user's account
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName UserDelete * @apiName UserDelete
* @apiGroup User * @apiGroup User
* *
* @apiParam {string} password The user's password unless it's a Facebook account * @apiParam {string} password The user's password (unless it's a Facebook account)
* *
* @apiSuccess {Object} empty An empty Object * @apiSuccess {Object} data An empty Object
*/ */
api.deleteUser = { api.deleteUser = {
method: 'DELETE', method: 'DELETE',
@@ -242,7 +243,9 @@ function _cleanChecklist (task) {
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName UserGetAnonymized * @apiName UserGetAnonymized
* @apiGroup User * @apiGroup User
* @apiSuccess {Object} object The object { user, tasks } *
* @apiSuccess {Object} data.user
* @apiSuccess {Array} data.tasks
**/ **/
api.getUserAnonymized = { api.getUserAnonymized = {
method: 'GET', method: 'GET',
@@ -309,7 +312,7 @@ const partyMembersFields = 'profile.name stats achievements items.special';
* @apiParam {string} spellId The spell to cast. * @apiParam {string} spellId The spell to cast.
* @apiParam {UUID} targetId Optional query parameter, the id of the target when casting a spell on a party member or a task. * @apiParam {UUID} targetId Optional query parameter, the id of the target when casting a spell on a party member or a task.
* *
* @apiSuccess mixed Will return the modified targets. For party members only the necessary fields will be populated. * @apiSuccess data Will return the modified targets. For party members only the necessary fields will be populated.
*/ */
api.castSpell = { api.castSpell = {
method: 'POST', method: 'POST',
@@ -419,7 +422,7 @@ api.castSpell = {
* @apiName UserSleep * @apiName UserSleep
* @apiGroup User * @apiGroup User
* *
* @apiSuccess {Object} Will return an object with the new `user.preferences.sleep` value. Example `{preferences: {sleep: true}}` * @apiSuccess {Object} data Will return an object with the new `user.preferences.sleep` value. Example `{preferences: {sleep: true}}`
*/ */
api.sleep = { api.sleep = {
method: 'POST', method: 'POST',

View File

@@ -1,7 +1,3 @@
import {
authWithSession,
} from '../../middlewares/api-v3/auth';
let api = {}; let api = {};
// Internal authentication routes // Internal authentication routes

View File

@@ -26,11 +26,11 @@ const BASE_URL = nconf.get('BASE_URL');
let api = {}; let api = {};
/** /**
* @api {get} /export/history.csv Export user tasks history in CSV format. History is only available for habits and dailys so todos and rewards won't be included * @api {get} /export/history.csv Export user tasks history in CSV format.
* @apiDescription History is only available for habits and dailys so todos and rewards won't be included NOTE: Part of the private API that may change at any time.
* @apiVersion 3.0.0 * @apiVersion 3.0.0
* @apiName ExportUserHistory * @apiName ExportUserHistory
* @apiGroup DataExport * @apiGroup DataExport
* @apiDescription NOTE: Part of the private API that may change at any time.
* *
* @apiSuccess {string} A cvs file * @apiSuccess {string} A cvs file
*/ */

View File

@@ -2,6 +2,7 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import _ from 'lodash'; import _ from 'lodash';
import shared from '../../../../common'; import shared from '../../../../common';
import logger from './logger';
export const localePath = path.join(__dirname, '/../../../../common/locales/'); export const localePath = path.join(__dirname, '/../../../../common/locales/');
@@ -68,8 +69,7 @@ langCodes.forEach((code) => {
momentLangs[code] = f; momentLangs[code] = f;
} catch (e) { // eslint-disable-lint no-empty } catch (e) { // eslint-disable-lint no-empty
// TODO implement some type of error loggin? // The catch block is mandatory so it won't crash the server
// The catch block is mandatory so can't be removed
} }
}); });

View File

@@ -31,7 +31,7 @@ export let schema = new Schema({
type: {type: String, enum: ['guild', 'party'], required: true}, type: {type: String, enum: ['guild', 'party'], required: true},
privacy: {type: String, enum: ['private', 'public'], default: 'private', required: true}, privacy: {type: String, enum: ['private', 'public'], default: 'private', required: true},
// _v: {type: Number,'default': 0}, // TODO ? // _v: {type: Number,'default': 0}, // TODO ?
chat: Array, // TODO ? chat: Array,
/* /*
# [{ # [{
# timestamp: Date # timestamp: Date
@@ -44,7 +44,7 @@ export let schema = new Schema({
*/ */
leaderOnly: { // restrict group actions to leader (members can't do them) leaderOnly: { // restrict group actions to leader (members can't do them)
challenges: {type: Boolean, default: false, required: true}, challenges: {type: Boolean, default: false, required: true},
// invites: {type:Boolean, 'default':false} // TODO ? // invites: {type:Boolean, 'default':false}
}, },
memberCount: {type: Number, default: 1}, memberCount: {type: Number, default: 1},
challengeCount: {type: Number, default: 0}, challengeCount: {type: Number, default: 0},
@@ -66,7 +66,6 @@ export let schema = new Schema({
// Shows boolean for each party-member who has accepted the quest. Eg {UUID: true, UUID: false}. Once all users click // Shows boolean for each party-member who has accepted the quest. Eg {UUID: true, UUID: false}. Once all users click
// 'Accept', the quest begins. If a false user waits too long, probably a good sign to prod them or boot them. // 'Accept', the quest begins. If a false user waits too long, probably a good sign to prod them or boot them.
// TODO when booting user, remove from .joined and check again if we can now start the quest // TODO when booting user, remove from .joined and check again if we can now start the quest
// TODO as long as quests are party only we can keep it here
members: {type: Schema.Types.Mixed, default: () => { members: {type: Schema.Types.Mixed, default: () => {
return {}; return {};
}}, }},
@@ -277,7 +276,7 @@ schema.methods.sendChat = function sendChat (message, user) {
this.chat.unshift(chatDefaults(message, user)); this.chat.unshift(chatDefaults(message, user));
this.chat.splice(200); this.chat.splice(200);
// Kick off chat notifications in the background. // TODO refactor // Kick off chat notifications in the background.
let lastSeenUpdate = {$set: {}, $inc: {_v: 1}}; let lastSeenUpdate = {$set: {}, $inc: {_v: 1}};
lastSeenUpdate.$set[`newMessages.${this._id}`] = {name: this.name, value: true}; lastSeenUpdate.$set[`newMessages.${this._id}`] = {name: this.name, value: true};

View File

@@ -231,7 +231,6 @@ export let schema = new Schema({
}, },
history: { history: {
// TODO absolutely preen these for everyone
exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined
todos: Array, // [{data: Date, value: Number}] // big peformance issues if these are defined todos: Array, // [{data: Date, value: Number}] // big peformance issues if these are defined
}, },