diff --git a/test/api/v3/unit/middlewares/errorHandler.test.js b/test/api/v3/unit/middlewares/errorHandler.test.js index f93d741820..7c75be9f28 100644 --- a/test/api/v3/unit/middlewares/errorHandler.test.js +++ b/test/api/v3/unit/middlewares/errorHandler.test.js @@ -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'); }); diff --git a/test/api/v3/unit/middlewares/getUserLanguage.test.js b/test/api/v3/unit/middlewares/getUserLanguage.test.js deleted file mode 100644 index bd7e6aa48c..0000000000 --- a/test/api/v3/unit/middlewares/getUserLanguage.test.js +++ /dev/null @@ -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(); - }); - }); - }); -}); diff --git a/test/api/v3/unit/middlewares/language.test.js b/test/api/v3/unit/middlewares/language.test.js new file mode 100644 index 0000000000..30feadd10c --- /dev/null +++ b/test/api/v3/unit/middlewares/language.test.js @@ -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(); + }); + }); + }); + }); +}); diff --git a/website/src/controllers/api-v3/auth.js b/website/src/controllers/api-v3/auth.js index c2faf298a9..37d3b08499 100644 --- a/website/src/controllers/api-v3/auth.js +++ b/website/src/controllers/api-v3/auth.js @@ -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; diff --git a/website/src/controllers/api-v3/challenges.js b/website/src/controllers/api-v3/challenges.js index b3dd588118..5ee92d8d22 100644 --- a/website/src/controllers/api-v3/challenges.js +++ b/website/src/controllers/api-v3/challenges.js @@ -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; diff --git a/website/src/controllers/api-v3/chat.js b/website/src/controllers/api-v3/chat.js index 43e4ba69e9..ddc6cf3df8 100644 --- a/website/src/controllers/api-v3/chat.js +++ b/website/src/controllers/api-v3/chat.js @@ -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; diff --git a/website/src/controllers/api-v3/coupon.js b/website/src/controllers/api-v3/coupon.js index 0890878a54..2fa572f000 100644 --- a/website/src/controllers/api-v3/coupon.js +++ b/website/src/controllers/api-v3/coupon.js @@ -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; diff --git a/website/src/controllers/api-v3/debug.js b/website/src/controllers/api-v3/debug.js index b5bc63a45e..1616bf2574 100644 --- a/website/src/controllers/api-v3/debug.js +++ b/website/src/controllers/api-v3/debug.js @@ -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; diff --git a/website/src/controllers/api-v3/groups.js b/website/src/controllers/api-v3/groups.js index 333e38a4a5..7fffb7f3c0 100644 --- a/website/src/controllers/api-v3/groups.js +++ b/website/src/controllers/api-v3/groups.js @@ -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; diff --git a/website/src/controllers/api-v3/hall.js b/website/src/controllers/api-v3/hall.js index 35d5dec2af..05ff2fc54e 100644 --- a/website/src/controllers/api-v3/hall.js +++ b/website/src/controllers/api-v3/hall.js @@ -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; diff --git a/website/src/controllers/api-v3/members.js b/website/src/controllers/api-v3/members.js index 0123955a73..f6ee561981 100644 --- a/website/src/controllers/api-v3/members.js +++ b/website/src/controllers/api-v3/members.js @@ -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(); diff --git a/website/src/controllers/api-v3/quests.js b/website/src/controllers/api-v3/quests.js index 9c0cf44502..bc808ab973 100644 --- a/website/src/controllers/api-v3/quests.js +++ b/website/src/controllers/api-v3/quests.js @@ -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; diff --git a/website/src/controllers/api-v3/tags.js b/website/src/controllers/api-v3/tags.js index 4a68512b19..76c3ffb7fa 100644 --- a/website/src/controllers/api-v3/tags.js +++ b/website/src/controllers/api-v3/tags.js @@ -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; diff --git a/website/src/controllers/api-v3/tasks.js b/website/src/controllers/api-v3/tasks.js index 5a06a58f25..5e9756da49 100644 --- a/website/src/controllers/api-v3/tasks.js +++ b/website/src/controllers/api-v3/tasks.js @@ -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; diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index af1fb94ee4..083aaef5fa 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -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; diff --git a/website/src/controllers/top-level/dataexport.js b/website/src/controllers/top-level/dataexport.js index 81f257cb58..5b0b2eb277 100644 --- a/website/src/controllers/top-level/dataexport.js +++ b/website/src/controllers/top-level/dataexport.js @@ -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); diff --git a/website/src/controllers/top-level/pages.js b/website/src/controllers/top-level/pages.js index 3174c8fe17..0d1800ee16 100644 --- a/website/src/controllers/top-level/pages.js +++ b/website/src/controllers/top-level/pages.js @@ -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'); }, diff --git a/website/src/libs/api-v3/routes.js b/website/src/libs/api-v3/routes.js index 0a6f3170ab..588cd50004 100644 --- a/website/src/libs/api-v3/routes.js +++ b/website/src/libs/api-v3/routes.js @@ -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)); }); }; diff --git a/website/src/middlewares/api-v3/auth.js b/website/src/middlewares/api-v3/auth.js index f1672dcf06..d1fcfe2e7b 100644 --- a/website/src/middlewares/api-v3/auth.js +++ b/website/src/middlewares/api-v3/auth.js @@ -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(); diff --git a/website/src/middlewares/api-v3/cron.js b/website/src/middlewares/api-v3/cron.js index 79eec6d654..bcdcc3591c 100644 --- a/website/src/middlewares/api-v3/cron.js +++ b/website/src/middlewares/api-v3/cron.js @@ -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; diff --git a/website/src/middlewares/api-v3/index.js b/website/src/middlewares/api-v3/index.js index 8e71e22e84..54567791e3 100644 --- a/website/src/middlewares/api-v3/index.js +++ b/website/src/middlewares/api-v3/index.js @@ -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`)); diff --git a/website/src/middlewares/api-v3/getUserLanguage.js b/website/src/middlewares/api-v3/language.js similarity index 87% rename from website/src/middlewares/api-v3/getUserLanguage.js rename to website/src/middlewares/api-v3/language.js index df372c02b4..8508a09187 100644 --- a/website/src/middlewares/api-v3/getUserLanguage.js +++ b/website/src/middlewares/api-v3/language.js @@ -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(); } -}; +} diff --git a/website/src/middlewares/api-v3/v3.js b/website/src/middlewares/api-v3/v3.js index bd9fe7c4da..f9aa637fa0 100644 --- a/website/src/middlewares/api-v3/v3.js +++ b/website/src/middlewares/api-v3/v3.js @@ -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); diff --git a/website/src/routes/api-v2/auth.js b/website/src/routes/api-v2/auth.js index 468612f8cf..f8af1b4338 100644 --- a/website/src/routes/api-v2/auth.js +++ b/website/src/routes/api-v2/auth.js @@ -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 diff --git a/website/src/routes/api-v2/coupon.js b/website/src/routes/api-v2/coupon.js index 29fdd75312..7caee3f815 100644 --- a/website/src/routes/api-v2/coupon.js +++ b/website/src/routes/api-v2/coupon.js @@ -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); diff --git a/website/src/routes/api-v2/swagger.js b/website/src/routes/api-v2/swagger.js index 4912bbd70b..c60d8364b6 100644 --- a/website/src/routes/api-v2/swagger.js +++ b/website/src/routes/api-v2/swagger.js @@ -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) { diff --git a/website/src/routes/api-v2/unsubscription.js b/website/src/routes/api-v2/unsubscription.js index 08393edb79..cbd2e16554 100644 --- a/website/src/routes/api-v2/unsubscription.js +++ b/website/src/routes/api-v2/unsubscription.js @@ -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); diff --git a/website/src/routes/payments.js b/website/src/routes/payments.js index 7b7f538eb8..13e9ec9163 100644 --- a/website/src/routes/payments.js +++ b/website/src/routes/payments.js @@ -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);