refactor getUserLanguage, automatically apply getUserLanguage and cron middlewares where needed

This commit is contained in:
Matteo Pagliazzi
2016-04-14 13:30:58 +02:00
parent a590a66c47
commit bc9f2b81e7
28 changed files with 507 additions and 431 deletions

View File

@@ -6,7 +6,10 @@ import {
import errorHandler from '../../../../../website/src/middlewares/api-v3/errorHandler';
import responseMiddleware from '../../../../../website/src/middlewares/api-v3/response';
import getUserLanguage from '../../../../../website/src/middlewares/api-v3/getUserLanguage';
import {
getUserLanguage,
attachTranslateFunction,
} from '../../../../../website/src/middlewares/api-v3/language';
import { BadRequest } from '../../../../../website/src/libs/api-v3/errors';
import logger from '../../../../../website/src/libs/api-v3/logger';
@@ -20,6 +23,7 @@ describe('errorHandler', () => {
next = generateNext();
responseMiddleware(req, res, next);
getUserLanguage(req, res, next);
attachTranslateFunction(req, res, next);
sandbox.stub(logger, 'error');
});

View File

@@ -1,267 +0,0 @@
import {
generateRes,
generateReq,
generateNext,
} from '../../../../helpers/api-unit.helper';
import getUserLanguage from '../../../../../website/src/middlewares/api-v3/getUserLanguage';
import { i18n } from '../../../../../common';
import Q from 'q';
import { model as User } from '../../../../../website/src/models/user';
describe('getUserLanguage', () => {
let res, req, next;
let checkResT = (resToCheck) => {
expect(resToCheck.t).to.be.a('function');
expect(resToCheck.t('help')).to.equal(i18n.t('help', req.language));
};
beforeEach(() => {
res = generateRes();
req = generateReq();
next = generateNext();
});
context('query parameter', () => {
it('uses the language in the query parameter if avalaible', () => {
req.query = {
lang: 'es',
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('es');
checkResT(res);
});
it('falls back to english if the query parameter language does not exists', () => {
req.query = {
lang: 'bla',
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('en');
checkResT(res);
});
it('uses query even if the request includes a user and session', () => {
req.query = {
lang: 'es',
};
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
req.session = {
userId: 123,
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('es');
checkResT(res);
});
});
context('authorized request', () => {
it('uses the user preferred language if avalaible', () => {
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('it');
checkResT(res);
});
it('falls back to english if the user preferred language is not avalaible', (done) => {
req.locals = {
user: {
preferences: {
language: 'bla',
},
},
};
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses the user preferred language even if a session is included in request', () => {
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
req.session = {
userId: 123,
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('it');
checkResT(res);
});
});
context('request with session', () => {
it('uses the user preferred language if avalaible', (done) => {
sandbox.stub(User, 'findOne').returns({
lean () {
return this;
},
exec () {
return Q.resolve({
preferences: {
language: 'it',
},
});
},
});
req.session = {
userId: 123,
};
getUserLanguage(req, res, () => {
expect(req.language).to.equal('it');
checkResT(res);
done();
});
});
});
context('browser fallback', () => {
it('uses browser specificed language', (done) => {
req.headers['accept-language'] = 'pt';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('pt');
checkResT(res);
done();
});
});
it('uses first language in series if browser specifies multiple', (done) => {
req.headers['accept-language'] = 'he, pt, it';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('he');
checkResT(res);
done();
});
});
it('skips invalid lanaguages and uses first language in series if browser specifies multiple', (done) => {
req.headers['accept-language'] = 'blah, he, pt, it';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('he');
checkResT(res);
done();
});
});
it('uses normal version of language if specialized locale is passed in', (done) => {
req.headers['accept-language'] = 'fr-CA';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('fr');
checkResT(res);
done();
});
});
it('uses normal version of language if specialized locale is passed in', (done) => {
req.headers['accept-language'] = 'fr-CA';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('fr');
checkResT(res);
done();
});
});
it('uses es if es is passed in', (done) => {
req.headers['accept-language'] = 'es';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es');
checkResT(res);
done();
});
});
it('uses es_419 if applicable es-languages are passed in', (done) => {
req.headers['accept-language'] = 'es-mx';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es_419');
checkResT(res);
done();
});
});
it('uses es_419 if multiple es languages are passed in', (done) => {
req.headers['accept-language'] = 'es-GT, es-MX, es-CR';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es_419');
checkResT(res);
done();
});
});
it('zh', (done) => {
req.headers['accept-language'] = 'zh-TW';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('zh_TW');
checkResT(res);
done();
});
});
it('uses english if browser specified language is not compatible', (done) => {
req.headers['accept-language'] = 'blah';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses english if browser does not specify', (done) => {
req.headers['accept-language'] = '';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses english if browser does not supply an accept-language header', (done) => {
delete req.headers['accept-language'];
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
});
});

View File

@@ -0,0 +1,307 @@
import {
generateRes,
generateReq,
generateNext,
} from '../../../../helpers/api-unit.helper';
import {
getUserLanguage,
attachTranslateFunction,
} from '../../../../../website/src/middlewares/api-v3/language';
import common from '../../../../../common';
import Q from 'q';
import { model as User } from '../../../../../website/src/models/user';
const i18n = common.i18n;
describe('language middleware', () => {
describe('res.t', () => {
let res, req, next;
beforeEach(() => {
res = generateRes();
req = generateReq();
next = generateNext();
sinon.stub(i18n, 't');
});
afterEach(() => {
i18n.t.restore();
});
it('attaches t method to res', () => {
attachTranslateFunction(req, res, next);
expect(res.t).to.exist;
});
it('uses the language specified in req.language', () => {
req.language = 'de';
attachTranslateFunction(req, res, next);
res.t(1, 2);
expect(i18n.t).to.be.calledOnce;
expect(i18n.t).to.be.calledWith(1, 2);
});
});
describe('getUserLanguage', () => {
let res, req, next;
let checkResT = (resToCheck) => {
expect(resToCheck.t).to.be.a('function');
expect(resToCheck.t('help')).to.equal(i18n.t('help', req.language));
};
beforeEach(() => {
res = generateRes();
req = generateReq();
next = generateNext();
attachTranslateFunction(req, res, next);
});
context('query parameter', () => {
it('uses the language in the query parameter if avalaible', () => {
req.query = {
lang: 'es',
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('es');
checkResT(res);
});
it('falls back to english if the query parameter language does not exists', () => {
req.query = {
lang: 'bla',
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('en');
checkResT(res);
});
it('uses query even if the request includes a user and session', () => {
req.query = {
lang: 'es',
};
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
req.session = {
userId: 123,
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('es');
checkResT(res);
});
});
context('authorized request', () => {
it('uses the user preferred language if avalaible', () => {
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('it');
checkResT(res);
});
it('falls back to english if the user preferred language is not avalaible', (done) => {
req.locals = {
user: {
preferences: {
language: 'bla',
},
},
};
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses the user preferred language even if a session is included in request', () => {
req.locals = {
user: {
preferences: {
language: 'it',
},
},
};
req.session = {
userId: 123,
};
getUserLanguage(req, res, next);
expect(req.language).to.equal('it');
checkResT(res);
});
});
context('request with session', () => {
it('uses the user preferred language if avalaible', (done) => {
sandbox.stub(User, 'findOne').returns({
lean () {
return this;
},
exec () {
return Q.resolve({
preferences: {
language: 'it',
},
});
},
});
req.session = {
userId: 123,
};
getUserLanguage(req, res, () => {
expect(req.language).to.equal('it');
checkResT(res);
done();
});
});
});
context('browser fallback', () => {
it('uses browser specificed language', (done) => {
req.headers['accept-language'] = 'pt';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('pt');
checkResT(res);
done();
});
});
it('uses first language in series if browser specifies multiple', (done) => {
req.headers['accept-language'] = 'he, pt, it';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('he');
checkResT(res);
done();
});
});
it('skips invalid lanaguages and uses first language in series if browser specifies multiple', (done) => {
req.headers['accept-language'] = 'blah, he, pt, it';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('he');
checkResT(res);
done();
});
});
it('uses normal version of language if specialized locale is passed in', (done) => {
req.headers['accept-language'] = 'fr-CA';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('fr');
checkResT(res);
done();
});
});
it('uses normal version of language if specialized locale is passed in', (done) => {
req.headers['accept-language'] = 'fr-CA';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('fr');
checkResT(res);
done();
});
});
it('uses es if es is passed in', (done) => {
req.headers['accept-language'] = 'es';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es');
checkResT(res);
done();
});
});
it('uses es_419 if applicable es-languages are passed in', (done) => {
req.headers['accept-language'] = 'es-mx';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es_419');
checkResT(res);
done();
});
});
it('uses es_419 if multiple es languages are passed in', (done) => {
req.headers['accept-language'] = 'es-GT, es-MX, es-CR';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('es_419');
checkResT(res);
done();
});
});
it('zh', (done) => {
req.headers['accept-language'] = 'zh-TW';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('zh_TW');
checkResT(res);
done();
});
});
it('uses english if browser specified language is not compatible', (done) => {
req.headers['accept-language'] = 'blah';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses english if browser does not specify', (done) => {
req.headers['accept-language'] = '';
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
it('uses english if browser does not supply an accept-language header', (done) => {
delete req.headers['accept-language'];
getUserLanguage(req, res, () => {
expect(req.language).to.equal('en');
checkResT(res);
done();
});
});
});
});
});

View File

@@ -6,7 +6,6 @@ import {
authWithHeaders,
authWithSession,
} from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import {
NotAuthorized,
BadRequest,
@@ -232,7 +231,6 @@ function _passportFbProfile (accessToken) {
api.loginSocial = {
method: 'POST',
url: '/user/auth/social', // this isn't the most appropriate url but must be the same as v2
middlewares: [cron],
async handler (req, res) {
let accessToken = req.body.authResponse.access_token;
let network = req.body.network;
@@ -292,7 +290,7 @@ api.loginSocial = {
**/
api.updateUsername = {
method: 'PUT',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/auth/update-username',
async handler (req, res) {
let user = res.locals.user;
@@ -338,7 +336,7 @@ api.updateUsername = {
**/
api.updatePassword = {
method: 'PUT',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/auth/update-password',
async handler (req, res) {
let user = res.locals.user;
@@ -428,7 +426,7 @@ api.resetPassword = {
*/
api.updateEmail = {
method: 'PUT',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/auth/update-email',
async handler (req, res) {
let user = res.locals.user;
@@ -456,7 +454,7 @@ const firebaseTokenGenerator = new FirebaseTokenGenerator(nconf.get('FIREBASE:SE
api.getFirebaseToken = {
method: 'POST',
url: '/user/auth/firebase',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
// Expires 24 hours from now (60*60*24*1000) (in milliseconds)
@@ -483,7 +481,7 @@ api.getFirebaseToken = {
api.deleteSocial = {
method: 'DELETE',
url: '/user/auth/social/:network',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let network = req.params.network;
@@ -501,7 +499,7 @@ api.deleteSocial = {
api.logout = {
method: 'GET',
url: '/user/auth/logout', // TODO this is under /api/v3 route, should be accessible through habitica.com/logout
middlewares: [authWithSession, cron],
middlewares: [authWithSession],
async handler (req, res) {
req.logout(); // passportjs method
req.session = null;

View File

@@ -1,6 +1,5 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import _ from 'lodash';
import cron from '../../middlewares/api-v3/cron';
import { model as Challenge } from '../../models/challenge';
import {
model as Group,
@@ -35,7 +34,7 @@ let api = {};
api.createChallenge = {
method: 'POST',
url: '/challenges',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -125,7 +124,7 @@ api.createChallenge = {
api.joinChallenge = {
method: 'POST',
url: '/challenges/:challengeId/join',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -171,7 +170,7 @@ api.joinChallenge = {
api.leaveChallenge = {
method: 'POST',
url: '/challenges/:challengeId/leave',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let keep = req.body.keep === 'remove-all' ? 'remove-all' : 'keep-all';
@@ -208,7 +207,7 @@ api.leaveChallenge = {
api.getUserChallenges = {
method: 'GET',
url: '/challenges/user',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -254,7 +253,7 @@ api.getUserChallenges = {
api.getGroupChallenges = {
method: 'GET',
url: '/challenges/groups/:groupId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -297,7 +296,7 @@ api.getGroupChallenges = {
api.getChallenge = {
method: 'GET',
url: '/challenges/:challengeId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
@@ -339,7 +338,7 @@ api.getChallenge = {
api.exportChallengeCsv = {
method: 'GET',
url: '/challenges/:challengeId/export/csv',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
@@ -412,7 +411,7 @@ api.exportChallengeCsv = {
api.updateChallenge = {
method: 'PUT',
url: '/challenges/:challengeId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
@@ -513,7 +512,7 @@ export async function _closeChal (challenge, broken = {}) {
api.deleteChallenge = {
method: 'DELETE',
url: '/challenges/:challengeId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -543,7 +542,7 @@ api.deleteChallenge = {
api.selectChallengeWinner = {
method: 'POST',
url: '/challenges/:challengeId/selectWinner/:winnerId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,5 +1,4 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import {
model as Group,
TAVERN_ID,
@@ -33,7 +32,7 @@ let api = {};
api.getChat = {
method: 'GET',
url: '/groups/:groupId/chat',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -64,7 +63,7 @@ api.getChat = {
api.postChat = {
method: 'POST',
url: '/groups/:groupId/chat',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -116,7 +115,7 @@ api.postChat = {
api.likeChat = {
method: 'POST',
url: '/groups/:groupId/chat/:chatId/like',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -163,7 +162,7 @@ api.likeChat = {
api.flagChat = {
method: 'POST',
url: '/groups/:groupId/chat/:chatId/flag',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -268,7 +267,7 @@ api.flagChat = {
api.clearChatFlags = {
method: 'Post',
url: '/groups/:groupId/chat/:chatId/clearflags',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -312,7 +311,7 @@ api.clearChatFlags = {
api.seenChat = {
method: 'POST',
url: '/groups/:groupId/chat/seen',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;
@@ -348,7 +347,7 @@ api.seenChat = {
api.deleteChat = {
method: 'DELETE',
url: '/groups/:groupId/chat/:chatId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;

View File

@@ -3,7 +3,6 @@ import {
authWithHeaders,
authWithSession,
} from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { ensureSudo } from '../../middlewares/api-v3/ensureAccessRight';
import { model as Coupon } from '../../models/coupon';
import _ from 'lodash';
@@ -22,7 +21,7 @@ let api = {};
api.getCoupons = {
method: 'GET',
url: '/coupons',
middlewares: [authWithSession, cron, ensureSudo],
middlewares: [authWithSession, ensureSudo],
async handler (req, res) {
let coupons = await Coupon.find().sort('createdAt').lean().exec();
@@ -53,7 +52,7 @@ api.getCoupons = {
api.generateCoupons = {
method: 'POST',
url: '/coupons/generate/:event',
middlewares: [authWithHeaders(), cron, ensureSudo],
middlewares: [authWithHeaders(), ensureSudo],
async handler (req, res) {
req.checkParams('event', res.t('eventRequired')).notEmpty();
req.checkQuery('count', res.t('countRequired')).notEmpty().isNumeric();
@@ -79,7 +78,7 @@ api.generateCoupons = {
api.enterCouponCode = {
method: 'POST',
url: '/coupons/enter/:code',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,15 +1,8 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import ensureDevelpmentMode from '../../middlewares/api-v3/ensureDevelpmentMode';
let api = {};
api.debug = {
method: 'all',
url: '/debug/*',
middlewares: [ensureDevelpmentMode, authWithHeaders(), cron],
};
/**
* @api {post} /debug/add-ten-gems Add ten gems to the current user
* @apiVersion 3.0.0
@@ -21,6 +14,7 @@ api.debug = {
api.addTenGems = {
method: 'POST',
url: '/debug/add-ten-gems',
middlewares: [ensureDevelpmentMode, authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -43,6 +37,7 @@ api.addTenGems = {
api.addHourglass = {
method: 'POST',
url: '/debug/add-hourglass',
middlewares: [ensureDevelpmentMode, authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,7 +1,6 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import Q from 'q';
import _ from 'lodash';
import cron from '../../middlewares/api-v3/cron';
import {
INVITES_LIMIT,
model as Group,
@@ -38,7 +37,7 @@ let api = {};
api.createGroup = {
method: 'POST',
url: '/groups',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let group = new Group(Group.sanitize(req.body)); // TODO validate empty req.body
@@ -89,7 +88,7 @@ api.createGroup = {
api.getGroups = {
method: 'GET',
url: '/groups',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -125,7 +124,7 @@ api.getGroups = {
api.getGroup = {
method: 'GET',
url: '/groups/:groupId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -159,7 +158,7 @@ api.getGroup = {
api.updateGroup = {
method: 'PUT',
url: '/groups/:groupId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -205,7 +204,7 @@ api.updateGroup = {
api.joinGroup = {
method: 'POST',
url: '/groups/:groupId/join',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let inviter;
@@ -296,7 +295,7 @@ api.joinGroup = {
api.rejectGroupInvite = {
method: 'POST',
url: '/groups/:groupId/reject-invite',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -342,7 +341,7 @@ api.rejectGroupInvite = {
api.leaveGroup = {
method: 'POST',
url: '/groups/:groupId/leave',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -399,7 +398,7 @@ function _sendMessageToRemoved (group, removedUser, message) {
api.removeGroupMember = {
method: 'POST',
url: '/groups/:groupId/removeMember/:memberId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -602,7 +601,7 @@ async function _inviteByEmail (invite, group, inviter, req, res) {
api.inviteToGroup = {
method: 'POST',
url: '/groups/:groupId/invite',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,6 +1,5 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import { ensureAdmin } from '../../middlewares/api-v3/ensureAccessRight';
import cron from '../../middlewares/api-v3/cron';
import { model as User } from '../../models/user';
import {
NotFound,
@@ -22,7 +21,7 @@ let api = {};
api.getPatrons = {
method: 'GET',
url: '/hall/patrons',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkQuery('page', res.t('pageMustBeNumber')).optional().isNumeric();
@@ -58,7 +57,7 @@ api.getPatrons = {
api.getHeroes = {
method: 'GET',
url: '/hall/heroes',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let heroes = await User
.find({
@@ -90,7 +89,7 @@ const heroAdminFields = 'contributor balance profile.name purchased items auth';
api.getHero = {
method: 'GET',
url: '/hall/heroes/:heroId',
middlewares: [authWithHeaders(), cron, ensureAdmin],
middlewares: [authWithHeaders(), ensureAdmin],
async handler (req, res) {
let heroId = req.params.heroId;
@@ -127,7 +126,7 @@ const gemsPerTier = {1: 3, 2: 3, 3: 3, 4: 4, 5: 4, 6: 4, 7: 4, 8: 0, 9: 0};
api.updateHero = {
method: 'PUT',
url: '/hall/heroes/:heroId',
middlewares: [authWithHeaders(), cron, ensureAdmin],
middlewares: [authWithHeaders(), ensureAdmin],
async handler (req, res) {
let heroId = req.params.heroId;
let updateData = req.body;

View File

@@ -1,5 +1,4 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import {
model as User,
publicFields as memberFields,
@@ -33,7 +32,7 @@ let api = {};
api.getMember = {
method: 'GET',
url: '/members/:memberId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
@@ -144,7 +143,7 @@ function _getMembersForItem (type) {
api.getMembersForGroup = {
method: 'GET',
url: '/groups/:groupId/members',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
handler: _getMembersForItem('group-members'),
};
@@ -162,7 +161,7 @@ api.getMembersForGroup = {
api.getInvitesForGroup = {
method: 'GET',
url: '/groups/:groupId/invites',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
handler: _getMembersForItem('group-invites'),
};
@@ -180,7 +179,7 @@ api.getInvitesForGroup = {
api.getMembersForChallenge = {
method: 'GET',
url: '/challenges/:challengeId/members',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
handler: _getMembersForItem('challenge-members'),
};
@@ -198,7 +197,7 @@ api.getMembersForChallenge = {
api.getChallengeMemberProgress = {
method: 'GET',
url: '/challenges/:challengeId/members/:memberId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
@@ -251,7 +250,7 @@ api.getChallengeMemberProgress = {
api.sendPrivateMessage = {
method: 'POST',
url: '/members/send-private-message',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkBody('message', res.t('messageRequired')).notEmpty();
req.checkBody('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID();
@@ -300,7 +299,7 @@ api.sendPrivateMessage = {
api.transferGems = {
method: 'POST',
url: '/members/transfer-gems',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkBody('message', res.t('messageRequired')).notEmpty();
req.checkBody('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID();

View File

@@ -1,7 +1,6 @@
import _ from 'lodash';
import Q from 'q';
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import analytics from '../../libs/api-v3/analyticsService';
import {
model as Group,
@@ -42,7 +41,7 @@ let api = {};
api.inviteToQuest = {
method: 'POST',
url: '/groups/:groupId/quests/invite/:questKey',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let questKey = req.params.questKey;
@@ -145,7 +144,7 @@ api.inviteToQuest = {
api.acceptQuest = {
method: 'POST',
url: '/groups/:groupId/quests/accept',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -202,7 +201,7 @@ api.acceptQuest = {
api.rejectQuest = {
method: 'POST',
url: '/groups/:groupId/quests/reject',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -261,7 +260,7 @@ api.rejectQuest = {
api.forceStart = {
method: 'POST',
url: '/groups/:groupId/quests/force-start',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -313,7 +312,7 @@ api.forceStart = {
api.cancelQuest = {
method: 'POST',
url: '/groups/:groupId/quests/cancel',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
// Cancel a quest BEFORE it has begun (i.e., in the invitation stage)
// Quest scroll has not yet left quest owner's inventory so no need to return it.
@@ -362,7 +361,7 @@ api.cancelQuest = {
api.abortQuest = {
method: 'POST',
url: '/groups/:groupId/quests/abort',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
// Abort a quest AFTER it has begun (see questCancel for BEFORE)
let user = res.locals.user;
@@ -416,7 +415,7 @@ api.abortQuest = {
api.leaveQuest = {
method: 'POST',
url: '/groups/:groupId/quests/leave',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let groupId = req.params.groupId;

View File

@@ -1,5 +1,4 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { model as Tag } from '../../models/tag';
import * as Tasks from '../../models/task';
import {
@@ -20,7 +19,7 @@ let api = {};
api.createTag = {
method: 'POST',
url: '/tags',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -44,7 +43,7 @@ api.createTag = {
api.getTags = {
method: 'GET',
url: '/tags',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
res.respond(200, user.tags);
@@ -64,7 +63,7 @@ api.getTags = {
api.getTag = {
method: 'GET',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -92,7 +91,7 @@ api.getTag = {
api.updateTag = {
method: 'PUT',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -126,7 +125,7 @@ api.updateTag = {
api.deleteTag = {
method: 'DELETE',
url: '/tags/:tagId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,5 +1,4 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { sendTaskWebhook } from '../../libs/api-v3/webhook';
import { removeFromArray } from '../../libs/api-v3/collectionManipulators';
import * as Tasks from '../../models/task';
@@ -66,7 +65,7 @@ async function _createTasks (req, res, user, challenge) {
api.createUserTasks = {
method: 'POST',
url: '/tasks/user',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let tasks = await _createTasks(req, res, res.locals.user);
res.respond(201, tasks.length === 1 ? tasks[0] : tasks);
@@ -87,7 +86,7 @@ api.createUserTasks = {
api.createChallengeTasks = {
method: 'POST',
url: '/tasks/challenge/:challengeId', // TODO should be /tasks/challengeS/:challengeId ? plural?
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
@@ -177,7 +176,7 @@ async function _getTasks (req, res, user, challenge) {
api.getUserTasks = {
method: 'GET',
url: '/tasks/user',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let types = Tasks.tasksTypes.map(type => `${type}s`);
types.push('completedTodos');
@@ -204,7 +203,7 @@ api.getUserTasks = {
api.getChallengeTasks = {
method: 'GET',
url: '/tasks/challenge/:challengeId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
let types = Tasks.tasksTypes.map(type => `${type}s`);
@@ -238,7 +237,7 @@ api.getChallengeTasks = {
api.getTask = {
method: 'GET',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -279,7 +278,7 @@ api.getTask = {
api.updateTask = {
method: 'PUT',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let challenge;
@@ -357,7 +356,7 @@ function _generateWebhookTaskData (task, direction, delta, stats, user) {
api.scoreTask = {
method: 'POST',
url: '/tasks/:taskId/score/:direction',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('direction', res.t('directionUpDown')).notEmpty().isIn(['up', 'down']); // TODO what about rewards? maybe separate route?
@@ -440,7 +439,7 @@ api.scoreTask = {
api.moveTask = {
method: 'POST',
url: '/tasks/:taskId/move/to/:position',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkParams('position', res.t('positionRequired')).notEmpty().isNumeric();
@@ -494,7 +493,7 @@ api.moveTask = {
api.addChecklistItem = {
method: 'POST',
url: '/tasks/:taskId/checklist',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let challenge;
@@ -543,7 +542,7 @@ api.addChecklistItem = {
api.scoreCheckListItem = {
method: 'POST',
url: '/tasks/:taskId/checklist/:itemId/score',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -585,7 +584,7 @@ api.scoreCheckListItem = {
api.updateChecklistItem = {
method: 'PUT',
url: '/tasks/:taskId/checklist/:itemId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let challenge;
@@ -636,7 +635,7 @@ api.updateChecklistItem = {
api.removeChecklistItem = {
method: 'DELETE',
url: '/tasks/:taskId/checklist/:itemId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let challenge;
@@ -685,7 +684,7 @@ api.removeChecklistItem = {
api.addTagToTask = {
method: 'POST',
url: '/tasks/:taskId/tags/:tagId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -728,7 +727,7 @@ api.addTagToTask = {
api.removeTagFromTask = {
method: 'DELETE',
url: '/tasks/:taskId/tags/:tagId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -767,7 +766,7 @@ api.removeTagFromTask = {
api.unlinkTask = {
method: 'POST',
url: '/tasks/unlink/:taskId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
req.checkParams('taskId', res.t('taskIdRequired')).notEmpty().isUUID();
req.checkQuery('keep', res.t('keepOrRemove')).notEmpty().isIn(['keep', 'remove']);
@@ -814,7 +813,7 @@ api.unlinkTask = {
api.clearCompletedTodos = {
method: 'POST',
url: '/tasks/clearCompletedTodos',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
@@ -847,7 +846,7 @@ api.clearCompletedTodos = {
api.deleteTask = {
method: 'DELETE',
url: '/tasks/:taskId',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
async handler (req, res) {
let user = res.locals.user;
let challenge;

View File

@@ -1,5 +1,4 @@
import { authWithHeaders } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import common from '../../../../common';
import {
NotFound,
@@ -29,7 +28,7 @@ let api = {};
*/
api.getUser = {
method: 'GET',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user',
async handler (req, res) {
let user = res.locals.user.toJSON();
@@ -56,7 +55,7 @@ api.getUser = {
*/
api.getBuyList = {
method: 'GET',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/inventory/buy',
async handler (req, res) {
let list = _.cloneDeep(common.updateStore(res.locals.user));
@@ -150,7 +149,7 @@ let checkPreferencePurchase = (user, path, item) => {
*/
api.updateUser = {
method: 'PUT',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user',
async handler (req, res) {
let user = res.locals.user;
@@ -186,7 +185,7 @@ api.updateUser = {
*/
api.deleteUser = {
method: 'DELETE',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user',
async handler (req, res) {
let user = res.locals.user;
@@ -246,7 +245,7 @@ function _cleanChecklist (task) {
**/
api.getUserAnonymized = {
method: 'GET',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/anonymized',
async handler (req, res) {
let user = res.locals.user.toJSON();
@@ -313,7 +312,7 @@ const partyMembersFields = 'profile.name stats achievements items.special';
*/
api.castSpell = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/class/cast/:spellId',
async handler (req, res) {
let user = res.locals.user;
@@ -423,7 +422,7 @@ api.castSpell = {
*/
api.sleep = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/sleep',
async handler (req, res) {
let user = res.locals.user;
@@ -443,7 +442,7 @@ api.sleep = {
*/
api.allocate = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/allocate',
async handler (req, res) {
let user = res.locals.user;
@@ -463,7 +462,7 @@ api.allocate = {
*/
api.allocateNow = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/allocate-now',
async handler (req, res) {
let user = res.locals.user;
@@ -487,7 +486,7 @@ api.allocateNow = {
*/
api.buy = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/buy/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -510,7 +509,7 @@ api.buy = {
*/
api.buyMysterySet = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/buy-mystery-set/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -533,7 +532,7 @@ api.buyMysterySet = {
*/
api.buyQuest = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/buy-quest/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -556,7 +555,7 @@ api.buyQuest = {
*/
api.buySpecialSpell = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/buy-special-spell/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -580,7 +579,7 @@ api.buySpecialSpell = {
*/
api.hatch = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/hatch/:egg/:hatchingPotion',
async handler (req, res) {
let user = res.locals.user;
@@ -604,7 +603,7 @@ api.hatch = {
*/
api.equip = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/equip/:type/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -628,7 +627,7 @@ api.equip = {
*/
api.feed = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/feed/:pet/:food',
async handler (req, res) {
let user = res.locals.user;
@@ -650,7 +649,7 @@ api.feed = {
*/
api.changeClass = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/change-class',
async handler (req, res) {
let user = res.locals.user;
@@ -670,7 +669,7 @@ api.changeClass = {
*/
api.disableClasses = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/disable-classes',
async handler (req, res) {
let user = res.locals.user;
@@ -693,7 +692,7 @@ api.disableClasses = {
*/
api.purchase = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/purchase/:type/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -716,7 +715,7 @@ api.purchase = {
*/
api.userPurchaseHourglass = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/purchase-hourglass/:type/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -738,7 +737,7 @@ api.userPurchaseHourglass = {
*/
api.readCard = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/read-card/:cardType',
async handler (req, res) {
let user = res.locals.user;
@@ -758,7 +757,7 @@ api.readCard = {
*/
api.userOpenMysteryItem = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/open-mystery-item',
async handler (req, res) {
let user = res.locals.user;
@@ -835,7 +834,7 @@ api.deleteWebhook = {
*/
api.userReleasePets = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/release-pets',
async handler (req, res) {
let user = res.locals.user;
@@ -855,7 +854,7 @@ api.userReleasePets = {
*/
api.userReleaseBoth = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/release-both',
async handler (req, res) {
let user = res.locals.user;
@@ -875,7 +874,7 @@ api.userReleaseBoth = {
*/
api.userReleaseMounts = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/release-mounts',
async handler (req, res) {
let user = res.locals.user;
@@ -895,7 +894,7 @@ api.userReleaseMounts = {
*/
api.userSell = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/sell/:type/:key',
async handler (req, res) {
let user = res.locals.user;
@@ -915,7 +914,7 @@ api.userSell = {
*/
api.userUnlock = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/unlock',
async handler (req, res) {
let user = res.locals.user;
@@ -935,7 +934,7 @@ api.userUnlock = {
*/
api.userRevive = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/revive',
async handler (req, res) {
let user = res.locals.user;
@@ -955,7 +954,7 @@ api.userRevive = {
*/
api.userRebirth = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/rebirth',
async handler (req, res) {
let user = res.locals.user;
@@ -1002,7 +1001,7 @@ api.blockUser = {
**/
api.deleteMessage = {
method: 'DELETE',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/messages/:id',
async handler (req, res) {
let user = res.locals.user;
@@ -1021,7 +1020,7 @@ api.deleteMessage = {
**/
api.clearMessages = {
method: 'DELETE',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/messages',
async handler (req, res) {
let user = res.locals.user;
@@ -1041,7 +1040,7 @@ api.clearMessages = {
*/
api.userReroll = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/reroll',
async handler (req, res) {
let user = res.locals.user;
@@ -1071,7 +1070,7 @@ api.userReroll = {
*/
api.userAddPushDevice = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/addPushDevice',
async handler (req, res) {
let user = res.locals.user;
@@ -1093,7 +1092,7 @@ api.userAddPushDevice = {
*/
api.userReset = {
method: 'POST',
middlewares: [authWithHeaders(), cron],
middlewares: [authWithHeaders()],
url: '/user/reset',
async handler (req, res) {
let user = res.locals.user;

View File

@@ -1,5 +1,4 @@
import { authWithSession } from '../../middlewares/api-v3/auth';
import cron from '../../middlewares/api-v3/cron';
import { model as User } from '../../models/user';
import * as Tasks from '../../models/task';
import {
@@ -39,7 +38,7 @@ let api = {};
api.exportUserHistory = {
method: 'GET',
url: '/export/history.csv',
middlewares: [authWithSession, cron],
middlewares: [authWithSession],
async handler (req, res) {
let user = res.locals.user;
@@ -107,7 +106,7 @@ async function _getUserDataForExport (user) {
api.exportUserDataJson = {
method: 'GET',
url: '/export/userdata.json',
middlewares: [authWithSession, cron],
middlewares: [authWithSession],
async handler (req, res) {
let userData = await _getUserDataForExport(res.locals.user);
@@ -132,7 +131,7 @@ api.exportUserDataJson = {
api.exportUserDataXml = {
method: 'GET',
url: '/export/userdata.xml',
middlewares: [authWithSession, cron],
middlewares: [authWithSession],
async handler (req, res) {
let userData = await _getUserDataForExport(res.locals.user);

View File

@@ -1,5 +1,4 @@
import locals from '../../middlewares/api-v3/locals';
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import _ from 'lodash';
const marked = require('marked');
@@ -11,7 +10,8 @@ const TOTAL_USER_COUNT = '1,100,000';
api.getFrontPage = {
method: 'GET',
url: '/',
middlewares: [getUserLanguage, locals],
middlewares: [locals],
runCron: false,
async handler (req, res) {
if (!req.header('x-api-user') && !req.header('x-api-key') && !(req.session && req.session.userId)) {
return res.redirect('/static/front');
@@ -34,7 +34,8 @@ _.each(staticPages, (name) => {
api[`get${name}Page`] = {
method: 'GET',
url: `/static/${name}`,
middlewares: [getUserLanguage, locals],
middlewares: [locals],
runCron: false,
async handler (req, res) {
res.render(`static/${name}.jade`, {
env: res.locals.habitrpg,
@@ -51,7 +52,8 @@ _.each(shareables, (name) => {
api[`get${name}ShareablePage`] = {
method: 'GET',
url: `/social/${name}`,
middlewares: [getUserLanguage, locals],
middlewares: [locals],
runCron: false,
async handler (req, res) {
res.render(`social/${name}`, {
env: res.locals.habitrpg,
@@ -65,6 +67,7 @@ _.each(shareables, (name) => {
api.redirectExtensionsPage = {
method: 'GET',
url: '/static/extensions',
runCron: false,
async handler (req, res) {
res.redirect('http://habitica.wikia.com/wiki/App_and_Extension_Integrations');
},

View File

@@ -1,5 +1,9 @@
import fs from 'fs';
import _ from 'lodash';
import {
getUserLanguage,
} from '../../middlewares/api-v3/language';
import cron from '../../middlewares/api-v3/cron';
// Wrapper function to handler `async` route handlers that return promises
// It takes the async function, execute it and pass any error to next (args[2])
@@ -8,12 +12,39 @@ let noop = (req, res, next) => next();
module.exports.readController = function readController (router, controller) {
_.each(controller, (action) => {
let {method, url, middlewares = [], handler} = action;
let {method, url, middlewares = [], handler, runCron} = action;
// If an authentication middleware is used run getUserLanguage after it, otherwise before
// for cron instead use it only if an authentication middleware is present
let authMiddlewareIndex = _.findIndex(middlewares, middleware => {
if (middleware.name.indexOf('authWith') === 0) { // authWith{Headers|Session|Url|...}
return true;
} else {
return false;
}
});
let middlewaresToAdd = [getUserLanguage];
if (authMiddlewareIndex !== -1) { // the user will be authenticated, getUserLanguage and cron after authentication
if (!(runCron === false)) { // eslint-disable-line no-extra-parens
middlewaresToAdd.push(cron);
}
if (authMiddlewareIndex === middlewares.length - 1) {
middlewares.push(...middlewaresToAdd);
} else {
middlewares.splice(authMiddlewareIndex + 1, 0, ...middlewaresToAdd);
}
} else { // no auth, getUserLanguage as the first middleware
middlewares.unshift(...middlewaresToAdd);
}
method = method.toLowerCase();
let fn = handler ? _wrapAsyncFn(handler) : noop;
router[method](url, ...middlewares, fn);
console.log(url, middlewares.map(m => m.name));
});
};

View File

@@ -1,12 +1,11 @@
import {
NotAuthorized,
} from '../../libs/api-v3/errors';
import common from '../../../../common';
import {
model as User,
} from '../../models/user';
const i18n = common.i18n;
// TODO how to translate the strings here since getUserLanguage hasn't run yet?
// Authenticate a request through the x-api-user and x-api key header
// If optional is true, don't error on missing authentication
@@ -26,8 +25,8 @@ export function authWithHeaders (optional = false) {
})
.exec()
.then((user) => {
if (!user) throw new NotAuthorized(i18n.t('invalidCredentials'));
if (user.auth.blocked) throw new NotAuthorized(i18n.t('accountSuspended', {userId: user._id}));
if (!user) throw new NotAuthorized(res.t('invalidCredentials'));
if (user.auth.blocked) throw new NotAuthorized(res.t('accountSuspended', {userId: user._id}));
res.locals.user = user;
// TODO use either session/cookie or headers, not both
@@ -42,14 +41,14 @@ export function authWithHeaders (optional = false) {
export function authWithSession (req, res, next) {
let userId = req.session.userId;
if (!userId) return next(new NotAuthorized(i18n.t('invalidCredentials')));
if (!userId) return next(new NotAuthorized(res.t('invalidCredentials')));
User.findOne({
_id: userId,
})
.exec()
.then((user) => {
if (!user) throw new NotAuthorized(i18n.t('invalidCredentials'));
if (!user) throw new NotAuthorized(res.t('invalidCredentials'));
res.locals.user = user;
next();

View File

@@ -271,7 +271,6 @@ function cron (options = {}) {
return _progress;
}
// TODO check that it's used everywhere
module.exports = function cronMiddleware (req, res, next) {
let user = res.locals.user;
let analytics = res.analytics;

View File

@@ -21,6 +21,10 @@ import {
import v1 from './v1';
import v2 from './v2';
import v3 from './v3';
import responseHandler from './response';
import {
attachTranslateFunction,
} from './language';
const IS_PROD = nconf.get('IS_PROD');
const DISABLE_LOGGING = nconf.get('DISABLE_REQUEST_LOGGING');
@@ -37,6 +41,10 @@ module.exports = function attachMiddlewares (app, server) {
if (!IS_PROD && !DISABLE_LOGGING) app.use(morgan('dev'));
// add res.respond and res.t
app.use(responseHandler);
app.use(attachTranslateFunction);
app.use(compression());
app.use(favicon(`${PUBLIC_DIR}/favicon.ico`));

View File

@@ -1,6 +1,6 @@
import { model as User } from '../../models/user';
import accepts from 'accepts';
import { i18n } from '../../../../common';
import common from '../../../../common';
import _ from 'lodash';
import {
translations,
@@ -8,6 +8,8 @@ import {
multipleVersionsLanguages,
} from '../../libs/api-v3/i18n';
const i18n = common.i18n;
function _getUniqueListOfLanguages (languages) {
let acceptableLanguages = _(languages).map((lang) => {
return lang.slice(0, 2);
@@ -56,7 +58,7 @@ function _getFromUser (user, req) {
return lang;
}
function _attachTranslateFunction (req, res, next) {
export function attachTranslateFunction (req, res, next) {
res.t = function reqTranslation () {
return i18n.t(...arguments, req.language);
};
@@ -64,13 +66,13 @@ function _attachTranslateFunction (req, res, next) {
next();
}
module.exports = function getUserLanguage (req, res, next) {
export function getUserLanguage (req, res, next) {
if (req.query.lang) { // In case the language is specified in the request url, use it
req.language = translations[req.query.lang] ? req.query.lang : 'en';
return _attachTranslateFunction(...arguments);
return next();
} else if (req.locals && req.locals.user) { // If the request is authenticated, use the user's preferred language
req.language = _getFromUser(req.locals.user, req);
return _attachTranslateFunction(...arguments);
return next();
} else if (req.session && req.session.userId) { // Same thing if the user has a valid session
User.findOne({
_id: req.session.userId,
@@ -79,11 +81,11 @@ module.exports = function getUserLanguage (req, res, next) {
.exec()
.then((user) => {
req.language = _getFromUser(user, req);
return _attachTranslateFunction(...arguments);
return next();
})
.catch(next);
} else { // Otherwise get from browser
req.language = _getFromUser(null, req);
return _attachTranslateFunction(...arguments);
return next();
}
};
}

View File

@@ -1,12 +1,13 @@
import express from 'express';
import expressValidator from 'express-validator';
import getUserLanguage from './getUserLanguage';
import responseHandler from './response';
import analytics from './analytics';
import setupBody from './setupBody';
import routes from '../../libs/api-v3/routes';
import path from 'path';
const API_CONTROLLERS_PATH = path.join(__dirname, '/../../controllers/api-v3/');
const TOP_LEVEL_CONTROLLERS_PATH = path.join(__dirname, '/../../controllers/top-level/');
const v3app = express();
// re-set the view options because they are not inherited from the top level app
@@ -16,15 +17,12 @@ v3app.set('views', `${__dirname}/../../../views`);
v3app.use(expressValidator());
v3app.use(analytics);
v3app.use(setupBody);
v3app.use(responseHandler);
v3app.use(getUserLanguage); // TODO move to after auth for authenticated routes
const TOP_LEVEL_CONTROLLERS_PATH = path.join(__dirname, '/../../controllers/top-level/');
const topLevelRouter = express.Router(); // eslint-disable-line babel/new-cap
routes.walkControllers(topLevelRouter, TOP_LEVEL_CONTROLLERS_PATH);
v3app.use('/', topLevelRouter);
const API_CONTROLLERS_PATH = path.join(__dirname, '/../../controllers/api-v3/');
const v3Router = express.Router(); // eslint-disable-line babel/new-cap
routes.walkControllers(v3Router, API_CONTROLLERS_PATH);
v3app.use('/api/v3', v3Router);

View File

@@ -2,7 +2,9 @@ var auth = require('../../controllers/api-v2/auth');
var express = require('express');
var i18n = require('../../libs/api-v2/i18n');
var router = express.Router();
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
/* auth.auth*/
// auth.setupPassport(router); //TODO make this consistent with the others

View File

@@ -4,7 +4,9 @@ var router = express.Router();
var auth = require('../../controllers/api-v2/auth');
var coupon = require('../../controllers/api-v2/coupon');
var i18n = require('../../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
router.get('/coupons', auth.authWithUrl, getUserLanguage, coupon.ensureAdmin, coupon.getCoupons);
router.post('/coupons/generate/:event', auth.auth, getUserLanguage, coupon.ensureAdmin, coupon.generateCoupons);

View File

@@ -19,7 +19,9 @@ var cron = user.cron;
var _ = require('lodash');
var content = require('../../../../common').content;
var i18n = require('../../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
var forceRefresh = require('../../middlewares/forceRefresh').middleware;
module.exports = function(swagger, v2) {

View File

@@ -2,7 +2,9 @@ var express = require('express');
var router = express.Router();
var i18n = require('../../libs/api-v2/i18n');
var unsubscription = require('../../controllers/api-v2/unsubscription');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
router.get('/unsubscribe', getUserLanguage, unsubscription.unsubscribe);

View File

@@ -4,7 +4,9 @@ var router = express.Router();
var auth = require('../controllers/api-v2/auth');
var payments = require('../controllers/payments');
var i18n = require('../libs/api-v2/i18n');
import getUserLanguage from '../../middlewares/api-v3/getUserLanguage';
import {
getUserLanguage
} from '../../middlewares/api-v3/language';
router.get('/paypal/checkout', auth.authWithUrl, getUserLanguage, payments.paypalCheckout);
router.get('/paypal/checkout/success', getUserLanguage, payments.paypalCheckoutSuccess);