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 {
generateUser,
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;
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 () => {
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,
error: 'BadRequest',
message: t('invalidReqParams'),
@@ -21,7 +21,7 @@ describe('GET /meta/models/:model/paths', () => {
let models = ['habit', 'daily', 'todo', 'reward', 'user', 'tag', 'challenge', 'group'];
models.forEach(model => {
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).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} 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 = {
method: 'POST',
@@ -174,8 +174,8 @@ function _loginRes (user, req, res) {
* @apiParam {String} username Body parameter - Username or email of the user
* @apiParam {String} password Body parameter - The user's password
*
* @apiSuccess {String} _id The user's unique identifier
* @apiSuccess {String} apiToken The user's api token that must be used to authenticate requests.
* @apiSuccess {String} data._id The user's unique identifier
* @apiSuccess {String} data.apiToken The user's api token that must be used to authenticate requests.
*/
api.loginLocal = {
method: 'POST',
@@ -229,6 +229,7 @@ function _passportFbProfile (accessToken) {
}
// Called as a callback by Facebook (or other social providers). Internal route
// TODO move to top-level/auth?
api.loginSocial = {
method: 'POST',
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} username Body parameter - The new username
* @apiSuccess {String} username The new username
* @apiSuccess {String} data.username The new username
**/
api.updateUsername = {
method: 'PUT',
@@ -339,7 +340,7 @@ api.updateUsername = {
* @apiParam {string} newPassword Body parameter - The new password
* @apiParam {string} confirmPassword Body parameter - New password confirmation
*
* @apiSuccess {Object} emoty An empty object
* @apiSuccess {Object} data An empty object
**/
api.updatePassword = {
method: 'PUT',
@@ -379,7 +380,7 @@ api.updatePassword = {
*
* @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 = {
method: 'POST',
@@ -433,7 +434,7 @@ api.resetPassword = {
* @apiParam {string} Body parameter - newEmail The new email address.
* @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 = {
method: 'PUT',
@@ -488,7 +489,7 @@ api.getFirebaseToken = {
* @apiName UserDeleteSocial
* @apiGroup User
*
* @apiSuccess {Object} empty Empty object
* @apiSuccess {Object} data Empty object
*/
api.deleteSocial = {
method: 'DELETE',

View File

@@ -29,7 +29,7 @@ let api = {};
* @apiName CreateChallenge
* @apiGroup Challenge
*
* @apiSuccess {object} challenge The newly created challenge
* @apiSuccess {object} data The newly created challenge
*/
api.createChallenge = {
method: 'POST',
@@ -119,7 +119,7 @@ api.createChallenge = {
* @apiGroup Challenge
* @apiParam {UUID} challengeId The challenge _id
*
* @apiSuccess {object} challenge The challenge the user joined
* @apiSuccess {object} data The challenge the user joined
*/
api.joinChallenge = {
method: 'POST',
@@ -165,7 +165,7 @@ api.joinChallenge = {
* @apiGroup Challenge
* @apiParam {UUID} challengeId The challenge _id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data An empty object
*/
api.leaveChallenge = {
method: 'POST',
@@ -202,7 +202,7 @@ api.leaveChallenge = {
* @apiName GetUserChallenges
* @apiGroup Challenge
*
* @apiSuccess {Array} challenges An array of challenges
* @apiSuccess {Array} data An array of challenges
*/
api.getUserChallenges = {
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
})
.sort('-official -timestamp')
// see below why we're not using populate
// .populate('group', basicGroupFields)
// .populate('leader', nameFields)
.exec();
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) => {
return Q.all([
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
* @apiDescription Get challenges that the user is a member, public challenges and the ones from the user's groups.
* @apiVersion 3.0.0
* @apiName GetGroupChallenges
* @apiGroup Challenge
*
* @apiParam {groupId} groupId The group _id
*
* @apiSuccess {Array} challenges An array of challenges
* @apiSuccess {Array} data An array of challenges
*/
api.getGroupChallenges = {
method: 'GET',
@@ -272,7 +274,7 @@ api.getGroupChallenges = {
.exec();
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) => {
return User.findById(chal.leader).select(nameFields).exec().then(populatedLeader => {
resChals[index].leader = populatedLeader.toJSON({minimize: true});
@@ -291,7 +293,7 @@ api.getGroupChallenges = {
*
* @apiParam {UUID} challengeId The challenge _id
*
* @apiSuccess {object} challenge The challenge object
* @apiSuccess {object} data The challenge object
*/
api.getChallenge = {
method: 'GET',
@@ -318,7 +320,7 @@ api.getChallenge = {
let chalRes = challenge.toJSON();
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});
res.respond(200, chalRes);
@@ -333,7 +335,7 @@ api.getChallenge = {
*
* @apiParam {UUID} challengeId The challenge _id
*
* @apiSuccess {object} challenge The challenge object
* @apiSuccess {string} challenge A csv file
*/
api.exportChallengeCsv = {
method: 'GET',
@@ -406,7 +408,7 @@ api.exportChallengeCsv = {
*
* @apiParam {UUID} challengeId The challenge _id
*
* @apiSuccess {object} challenge The updated challenge object
* @apiSuccess {object} data The updated challenge
*/
api.updateChallenge = {
method: 'PUT',
@@ -507,7 +509,9 @@ export async function _closeChal (challenge, broken = {}) {
* @apiName DeleteChallenge
* @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 = {
method: 'DELETE',
@@ -537,7 +541,10 @@ api.deleteChallenge = {
* @apiName SelectChallengeWinner
* @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 = {
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)
*
* @apiSuccess {Array} chat An array of chat messages
* @apiSuccess {Array} data An array of chat messages
*/
api.getChat = {
method: 'GET',
@@ -54,11 +54,11 @@ api.getChat = {
* @apiName PostCat
* @apiGroup Chat
*
* @apiParam {UUID} groupId The group _id
* @apiParam {message} message The chat's message
* @apiParam {previousMsg} previousMsg The previous chat message which will force a return of the full group chat
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {message} Body parameter - message The message to post
* @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 = {
method: 'POST',
@@ -107,10 +107,10 @@ api.postChat = {
* @apiName LikeChat
* @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
*
* @apiSuccess {Array} chat An array of chat messages
* @apiSuccess {Object} data The liked chat message
*/
api.likeChat = {
method: 'POST',
@@ -154,10 +154,10 @@ api.likeChat = {
* @apiName LikeChat
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id
* @apiParam {chatId} chatId The chat message _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
*
* @apiSuccess {Array} chat An array of chat messages
* @apiSuccess {object} data The flagged chat message
*/
api.flagChat = {
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
* @apiDescription Admin-only
* @apiVersion 3.0.0
* @apiName ClearFlags
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id
* @apiParam {chatId} chatId The chat message _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
*
* @apiSuccess {Object} An empty object
* @apiSuccess {Object} data An empty object
*/
api.clearChatFlags = {
method: 'Post',
@@ -306,7 +307,9 @@ api.clearChatFlags = {
* @apiName SeenChat
* @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 = {
method: 'POST',
@@ -328,7 +331,7 @@ api.seenChat = {
update.$unset[`newMessages.${groupId}`] = true;
await User.update({_id: user._id}, update).exec();
res.respond(200);
res.respond(200, {});
},
};
@@ -338,11 +341,12 @@ api.seenChat = {
* @apiName DeleteChat
* @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} chatId The chat _id
* @apiParam {string} chatId The chat message id
*
* @apiSuccess {Array} The update chat array
* @apiSuccess {Object} An empty object when the previous message was deleted
* @apiSuccess data The updated chat array or an empty object if no message was posted after previousMsg
* @apiSuccess {Object} data An empty object when the previous message was deleted
*/
api.deleteChat = {
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
* @apiName ContentGet
* @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 = {
method: 'GET',
@@ -95,7 +96,7 @@ api.getContent = {
res.set({
'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
if (cachedContentResponses[language] !== true && cacheBeingWritten[language] !== true) {

View File

@@ -11,12 +11,13 @@ import couponCode from 'coupon-code';
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
* @apiName GetCoupons
* @apiGroup Coupon
*
* @apiSuccess string Coupons in CSV format
* @apiSuccess {string} Coupons in CSV format
*/
api.getCoupons = {
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
* @apiName GenerateCoupons
* @apiGroup Coupon
@@ -47,7 +49,7 @@ api.getCoupons = {
* @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
*
* @apiSuccess array Generated coupons
* @apiSuccess {array} data Generated coupons
*/
api.generateCoupons = {
method: 'POST',
@@ -73,7 +75,7 @@ api.generateCoupons = {
*
* @apiParam {string} code The coupon code to apply
*
* @apiSuccess object User object
* @apiSuccess {object} data User object
*/
api.enterCouponCode = {
method: 'POST',
@@ -98,7 +100,7 @@ api.enterCouponCode = {
* @apiName ValidateCoupon
* @apiGroup Coupon
*
* @apiSuccess valid {boolean} true or false
* @apiSuccess {boolean} data.valid True or false
*/
api.validateCoupon = {
method: 'POST',

View File

@@ -4,12 +4,13 @@ import ensureDevelpmentMode from '../../middlewares/api-v3/ensureDevelpmentMode'
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
* @apiName AddTenGems
* @apiGroup Development
*
* @apiSuccess {Object} empty An empty Object
* @apiSuccess {Object} data An empty Object
*/
api.addTenGems = {
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
* @apiName AddHourglass
* @apiGroup Development
*
* @apiSuccess {Object} empty An empty Object
* @apiSuccess {Object} data An empty Object
*/
api.addHourglass = {
method: 'POST',

View File

@@ -7,21 +7,22 @@ import {
let api = {};
// TODO move to top-level controllers?
/**
* @api {get} /api/v3/email/unsubscribe Unsubscribe an email or user from email notifications
* @apiDescription Does not require authentication
* @apiVersion 3.0.0
* @apiName UnsubscribeEmail
* @apiGroup Unsubscribe
* @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 = {
method: 'GET',
url: '/email/unsubscribe',
middlewares: [],
async handler (req, res) {
req.checkQuery({
code: {

View File

@@ -24,15 +24,13 @@ import common from '../../../../common';
import sendPushNotification from '../../libs/api-v3/pushNotifications';
let api = {};
// TODO shall we accept party as groupId in all routes?
/**
* @api {post} /api/v3/groups Create group
* @apiVersion 3.0.0
* @apiName CreateGroup
* @apiGroup Group
*
* @apiSuccess {Object} group The group object
* @apiSuccess {Object} data The create group
*/
api.createGroup = {
method: 'POST',
@@ -40,7 +38,7 @@ api.createGroup = {
middlewares: [authWithHeaders()],
async handler (req, res) {
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;
if (group.type === 'guild') {
@@ -60,7 +58,7 @@ api.createGroup = {
let results = await Q.all([user.save(), group.save()]);
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
let response = savedGroup.toJSON();
// 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
* @apiName GetGroups
* @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
*
* @apiSuccess {Array} groups An array of the requested groups
* @apiSuccess {Array} data An array of the requested groups
*/
api.getGroups = {
method: 'GET',
@@ -92,7 +90,7 @@ api.getGroups = {
async handler (req, res) {
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();
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)
*
* @apiSuccess {Object} group The group object
* @apiSuccess {Object} data The group object
*/
api.getGroup = {
method: 'GET',
@@ -137,7 +135,7 @@ api.getGroup = {
if (!group) throw new NotFound(res.t('groupNotFound'));
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();
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)
*
* @apiSuccess {Object} group The updated group object
* @apiSuccess {Object} data The updated group
*/
api.updateGroup = {
method: 'PUT',
@@ -197,9 +195,9 @@ api.updateGroup = {
* @apiName JoinGroup
* @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 = {
method: 'POST',
@@ -288,9 +286,9 @@ api.joinGroup = {
* @apiName RejectGroupInvite
* @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 = {
method: 'POST',
@@ -334,9 +332,9 @@ api.rejectGroupInvite = {
* @apiGroup Group
*
* @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 = {
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 {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 = {
method: 'POST',
@@ -448,7 +446,7 @@ api.removeGroupMember = {
if (isInGroup === 'guild') {
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]) {
member.newMessages[group._id] = undefined;
@@ -456,13 +454,16 @@ api.removeGroupMember = {
}
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) {
if (isInvited === 'guild') {
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 {
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 {array} emails An array of emails addresses to invite (optional) (inside body)
* @apiParam {array} uuids An array of uuids to invite (optional) (inside body)
* @apiParam {string} inviter The inviters' name (optional) (inside body)
* @apiParam {array} emails Body parameter - An array of emails addresses to invite (optional)
* @apiParam {array} uuids Body parameter - An array of uuids to invite (optional)
* @apiParam {string} inviter Body parameter - The inviters' name (optional)
*
* @apiSuccess {Object} empty An empty object
* @apiSuccess {array} data The invites
*/
api.inviteToGroup = {
method: 'POST',

View File

@@ -9,14 +9,15 @@ import _ from 'lodash';
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
* @apiName GetPatrons
* @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 = {
method: 'GET',
@@ -52,7 +53,7 @@ api.getPatrons = {
* @apiName GetHeroes
* @apiGroup Hall
*
* @apiSuccess {Array} hero An array of heroes
* @apiSuccess {Array} data An array of heroes
*/
api.getHeroes = {
method: 'GET',
@@ -74,17 +75,17 @@ api.getHeroes = {
// Note, while the following routes are called getHero / updateHero
// they can be used by admins to get/update any user
// TODO rename?
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
* @apiName GetHero
* @apiGroup Hall
*
* @apiSuccess {Object} hero The hero object
* @apiSuccess {Object} data The hero object
*/
api.getHero = {
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};
/**
* @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
* @apiName UpdateHero
* @apiGroup Hall
*
* @apiSuccess {Object} hero The updated hero object
* @apiSuccess {Object} data The updated hero object
*/
api.updateHero = {
method: 'PUT',
@@ -162,7 +164,7 @@ api.updateHero = {
if (updateData.itemPath && updateData.itemVal &&
updateData.itemPath.indexOf('items.') === 0 &&
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;

View File

@@ -27,7 +27,7 @@ let api = {};
*
* @apiParam {UUID} memberId The member's id
*
* @apiSuccess {object} member The member object
* @apiSuccess {object} data The member object
*/
api.getMember = {
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
* @apiName GetMembersForGroup
* @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 {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 = {
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
* @apiName GetInvitesForGroup
* @apiGroup Member
@@ -156,7 +158,7 @@ api.getMembersForGroup = {
* @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
*
* @apiSuccess {array} invites An array of invites, sorted by _id
* @apiSuccess {array} data An array of invites, sorted by _id
*/
api.getInvitesForGroup = {
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
* @apiName GetMembersForChallenge
* @apiGroup Member
@@ -174,7 +177,7 @@ api.getInvitesForGroup = {
* @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
*
* @apiSuccess {array} members An array of members, sorted by _id
* @apiSuccess {array} data An array of members, sorted by _id
*/
api.getMembersForChallenge = {
method: 'GET',
@@ -192,7 +195,7 @@ api.getMembersForChallenge = {
* @apiParam {UUID} challengeId The challenge _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 = {
method: 'GET',
@@ -242,10 +245,10 @@ api.getChallengeMemberProgress = {
* @apiName SendPrivateMessage
* @apiGroup Members
*
* @apiParam {String} message The message
* @apiParam {UUID} toUserId The toUser _id
* @apiParam {String} message Body parameter - The message
* @apiParam {UUID} toUserId Body parameter - The user to contact
*
* @apiSuccess {Object} empty An empty Object
* @apiSuccess {Object} data An empty Object
*/
api.sendPrivateMessage = {
method: 'POST',
@@ -291,10 +294,10 @@ api.sendPrivateMessage = {
* @apiName TransferGems
* @apiGroup Members
*
* @apiParam {String} message The message
* @apiParam {UUID} toUserId The toUser _id
* @apiParam {String} message Body parameter The message
* @apiParam {UUID} toUserId Body parameter The toUser _id
*
* @apiSuccess {Object} empty An empty Object
* @apiSuccess {Object} data An empty Object
*/
api.transferGems = {
method: 'POST',
@@ -346,8 +349,8 @@ api.transferGems = {
]);
}
// @TODO: Add push notifications
// pushNotify.sendNotify(sender, res.t('giftedGems'), res.t('giftedGemsInfo', { amount: gemAmount, name: byUsername }));
// TODO: Add push notifications
// pushNotify.sendNotify(sender, res.t('giftedGems'), res.t('giftedGemsInfo', { amount: gemAmount, name: byUsername }));
res.respond(200, {});
},

View File

@@ -6,18 +6,19 @@ let tasksModels = ['habit', 'daily', 'todo', 'reward'];
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
* @apiName GetUserModelPaths
* @apiGroup Meta
*
* @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 = {
method: 'GET',
url: '/meta/models/:model/paths',
url: '/models/:model/paths',
async handler (req, res) {
req.checkParams('model', res.t('modelNotFound')).notEmpty().isIn(allModels);

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ let api = {};
* @apiName CreateTag
* @apiGroup Tag
*
* @apiSuccess {Object} tag The newly created tag
* @apiSuccess {Object} data The newly created tag
*/
api.createTag = {
method: 'POST',
@@ -38,7 +38,7 @@ api.createTag = {
* @apiName GetTags
* @apiGroup Tag
*
* @apiSuccess {Array} tags An array of tag objects
* @apiSuccess {Array} data An array of tags
*/
api.getTags = {
method: 'GET',
@@ -58,7 +58,7 @@ api.getTags = {
*
* @apiParam {UUID} tagId The tag _id
*
* @apiSuccess {object} tag The tag object
* @apiSuccess {object} data The tag object
*/
api.getTag = {
method: 'GET',
@@ -86,7 +86,7 @@ api.getTag = {
*
* @apiParam {UUID} tagId The tag _id
*
* @apiSuccess {object} tag The updated tag
* @apiSuccess {object} data The updated tag
*/
api.updateTag = {
method: 'PUT',
@@ -120,7 +120,7 @@ api.updateTag = {
*
* @apiParam {UUID} tagId The tag _id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data An empty object
*/
api.deleteTag = {
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
* @apiName CreateUserTasks
* @apiGroup Task
*
* @apiSuccess {Object} task The newly created task
* @apiSuccess {Object[]} tasks The newly created tasks (if more than one was created)
* @apiSuccess data An object if a single task was created, otherwise an array of tasks
*/
api.createUserTasks = {
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
* @apiName CreateChallengeTasks
* @apiGroup Task
*
* @apiParam {UUID} challengeId The id of the challenge the new task(s) will belong to.
*
* @apiSuccess {Object} task The newly created task
* @apiSuccess {Object[]} tasks The newly created tasks (if more than one was created)
* @apiSuccess data An object if a single task was created, otherwise an array of tasks
*/
api.createChallengeTasks = {
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.
*
* @apiSuccess {Array} tasks An array of task objects
* @apiSuccess {Array} data An array of tasks
*/
api.getUserTasks = {
method: 'GET',
@@ -198,7 +198,7 @@ api.getUserTasks = {
* @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
*
* @apiSuccess {Array} tasks An array of task objects
* @apiSuccess {Array} data An array of tasks
*/
api.getChallengeTasks = {
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
* @apiName GetTask
* @apiGroup Task
*
* @apiParam {UUID} taskId The task _id
*
* @apiSuccess {object} task The task object
* @apiSuccess {object} data The task object
*/
api.getTask = {
method: 'GET',
@@ -273,7 +273,7 @@ api.getTask = {
*
* @apiParam {UUID} taskId The task _id
*
* @apiSuccess {object} task The updated task
* @apiSuccess {object} data The updated task
*/
api.updateTask = {
method: 'PUT',
@@ -284,8 +284,6 @@ api.updateTask = {
let challenge;
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();
if (validationErrors) throw validationErrors;
@@ -304,10 +302,10 @@ api.updateTask = {
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
_.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()
// 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 {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 = {
method: 'POST',
@@ -389,7 +389,7 @@ api.scoreTask = {
let hasTask = removeFromArray(user.tasksOrder.todos, task._id);
if (!hasTask) {
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));
// 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 {
@@ -423,7 +422,6 @@ api.scoreTask = {
};
// 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?
/**
* @api {post} /api/v3/tasks/:taskId/move/to/:position Move a task to a new position
@@ -432,9 +430,9 @@ api.scoreTask = {
* @apiGroup Task
*
* @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 = {
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
* @apiName AddChecklistItem
* @apiGroup Task
*
* @apiParam {UUID} taskId The task _id
*
* @apiSuccess {object} task The updated task
* @apiSuccess {object} data The updated task
*/
api.addChecklistItem = {
method: 'POST',
@@ -499,7 +497,6 @@ api.addChecklistItem = {
let challenge;
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) 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?
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask);
},
};
@@ -537,7 +534,7 @@ api.addChecklistItem = {
* @apiParam {UUID} taskId The task _id
* @apiParam {UUID} itemId The checklist item _id
*
* @apiSuccess {object} task The updated task
* @apiSuccess {object} data The updated task
*/
api.scoreCheckListItem = {
method: 'POST',
@@ -566,7 +563,7 @@ api.scoreCheckListItem = {
item.completed = !item.completed;
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} itemId The checklist item _id
*
* @apiSuccess {object} task The updated task
* @apiSuccess {object} data The updated task
*/
api.updateChecklistItem = {
method: 'PUT',
@@ -616,7 +613,7 @@ api.updateChecklistItem = {
_.merge(item, Tasks.Task.sanitizeChecklist(req.body));
let savedTask = await task.save();
res.respond(200, savedTask); // TODO what to return
res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask);
},
};
@@ -630,7 +627,7 @@ api.updateChecklistItem = {
* @apiParam {UUID} taskId The task _id
* @apiParam {UUID} itemId The checklist item _id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data The updated task
*/
api.removeChecklistItem = {
method: 'DELETE',
@@ -665,7 +662,7 @@ api.removeChecklistItem = {
if (!hasItem) throw new NotFound(res.t('checklistItemNotFound'));
let savedTask = await task.save();
res.respond(200, {}); // TODO what to return
res.respond(200, savedTask);
if (challenge) challenge.updateTask(savedTask);
},
};
@@ -679,7 +676,7 @@ api.removeChecklistItem = {
* @apiParam {UUID} taskId The task _id
* @apiParam {UUID} tagId The tag id
*
* @apiSuccess {object} task The updated task
* @apiSuccess {object} data The updated task
*/
api.addTagToTask = {
method: 'POST',
@@ -709,12 +706,12 @@ api.addTagToTask = {
task.tags.push(tagId);
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
* @apiName RemoveTagFromTask
* @apiGroup Task
@@ -722,7 +719,7 @@ api.addTagToTask = {
* @apiParam {UUID} taskId The task _id
* @apiParam {UUID} tagId The tag id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data The updated task
*/
api.removeTagFromTask = {
method: 'DELETE',
@@ -747,8 +744,8 @@ api.removeTagFromTask = {
let hasTag = removeFromArray(task.tags, req.params.tagId);
if (!hasTag) throw new NotFound(res.t('tagNotFound'));
await task.save();
res.respond(200, {}); // TODO what to return
let savedTask = await task.save();
res.respond(200, savedTask);
},
};
@@ -761,7 +758,7 @@ api.removeTagFromTask = {
*
* @apiParam {UUID} taskId The task _id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data An empty object
*/
api.unlinkTask = {
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
* @apiGroup Task
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data An empty object
*/
api.clearCompletedTodos = {
method: 'POST',
@@ -841,7 +838,7 @@ api.clearCompletedTodos = {
*
* @apiParam {UUID} taskId The task _id
*
* @apiSuccess {object} empty An empty object
* @apiSuccess {object} data An empty object
*/
api.deleteTask = {
method: 'DELETE',

View File

@@ -24,7 +24,7 @@ let api = {};
* @apiName UserGet
* @apiGroup User
*
* @apiSuccess {Object} user The user object
* @apiSuccess {Object} data The user object
*/
api.getUser = {
method: 'GET',
@@ -51,7 +51,7 @@ api.getUser = {
* @apiName UserGetBuyList
* @apiGroup User
*
* @apiSuccess {Object} list The buy list
* @apiSuccess {Object} data The buy list
*/
api.getBuyList = {
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
* @apiName UserUpdate
* @apiGroup User
*
* @apiSuccess user object The updated user object
* @apiSuccess {object} data The updated user object
*/
api.updateUser = {
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
* @apiName UserDelete
* @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 = {
method: 'DELETE',
@@ -242,7 +243,9 @@ function _cleanChecklist (task) {
* @apiVersion 3.0.0
* @apiName UserGetAnonymized
* @apiGroup User
* @apiSuccess {Object} object The object { user, tasks }
*
* @apiSuccess {Object} data.user
* @apiSuccess {Array} data.tasks
**/
api.getUserAnonymized = {
method: 'GET',
@@ -309,7 +312,7 @@ const partyMembersFields = 'profile.name stats achievements items.special';
* @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.
*
* @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 = {
method: 'POST',
@@ -419,7 +422,7 @@ api.castSpell = {
* @apiName UserSleep
* @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 = {
method: 'POST',

View File

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

View File

@@ -26,11 +26,11 @@ const BASE_URL = nconf.get('BASE_URL');
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
* @apiName ExportUserHistory
* @apiGroup DataExport
* @apiDescription NOTE: Part of the private API that may change at any time.
*
* @apiSuccess {string} A cvs file
*/

View File

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

View File

@@ -31,7 +31,7 @@ export let schema = new Schema({
type: {type: String, enum: ['guild', 'party'], required: true},
privacy: {type: String, enum: ['private', 'public'], default: 'private', required: true},
// _v: {type: Number,'default': 0}, // TODO ?
chat: Array, // TODO ?
chat: Array,
/*
# [{
# timestamp: Date
@@ -44,7 +44,7 @@ export let schema = new Schema({
*/
leaderOnly: { // restrict group actions to leader (members can't do them)
challenges: {type: Boolean, default: false, required: true},
// invites: {type:Boolean, 'default':false} // TODO ?
// invites: {type:Boolean, 'default':false}
},
memberCount: {type: Number, default: 1},
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
// '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 as long as quests are party only we can keep it here
members: {type: Schema.Types.Mixed, default: () => {
return {};
}},
@@ -277,7 +276,7 @@ schema.methods.sendChat = function sendChat (message, user) {
this.chat.unshift(chatDefaults(message, user));
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}};
lastSeenUpdate.$set[`newMessages.${this._id}`] = {name: this.name, value: true};

View File

@@ -231,7 +231,6 @@ export let schema = new Schema({
},
history: {
// TODO absolutely preen these for everyone
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
},