mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
v3: general cleanup
This commit is contained in:
@@ -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');
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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 }));
|
||||
|
||||
res.respond(200, {});
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import {
|
||||
authWithSession,
|
||||
} from '../../middlewares/api-v3/auth';
|
||||
|
||||
let api = {};
|
||||
|
||||
// Internal authentication routes
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user