diff --git a/package.json b/package.json index a3fc0957cc..a9117cd89b 100644 --- a/package.json +++ b/package.json @@ -4,20 +4,24 @@ "version": "0.0.0-152", "main": "./website/src/server.js", "dependencies": { + "accepts": "^1.3.0", "amazon-payments": "0.0.4", "amplitude": "^2.0.1", "async": "~0.9.0", "aws-sdk": "^2.0.25", "babel": "^5.5.4", - "gulp-babel": "^5.2.1", + "body-parser": "^1.14.1", "bower": "~1.3.12", "browserify": "~3.30.2", "coffee-script": "1.6.x", "coffeeify": "0.6.0", + "compression": "^1.6.0", "connect-ratelimit": "0.0.7", + "cookie-parser": "^1.4.0", + "cookie-session": "^1.2.0", "coupon-code": "~0.3.0", "domain-middleware": "~0.1.0", - "express": "~3.17.5", + "express": "~4.13.3", "express-csv": "~0.6.0", "firebase": "^2.2.9", "firebase-token-generator": "^2.0.0", @@ -34,6 +38,7 @@ "grunt-hashres": "~0.4.1", "grunt-karma": "~0.6.2", "gulp": "^3.9.0", + "gulp-babel": "^5.2.1", "gulp-clean": "^0.3.1", "gulp-eslint": "^1.0.0", "gulp-grunt": "^0.5.2", @@ -53,8 +58,9 @@ "merge-stream": "^1.0.0", "method-override": "~2.2.0", "moment": "~2.8.3", - "mongoose": "~3.8.23", + "mongoose": "~4.2.3", "mongoose-id-autoinc": "~2013.7.14-4", + "morgan": "^1.6.1", "nconf": "~0.6.9", "newrelic": "~1.23.0", "nib": "~1.0.1", @@ -71,6 +77,7 @@ "qs": "^2.3.2", "request": "~2.44.0", "s3-upload-stream": "^1.0.6", + "serve-favicon": "^2.3.0", "stripe": "*", "superagent": "~1.4.0", "swagger-node-express": "lefnire/swagger-node-express#habitrpg", @@ -82,8 +89,8 @@ }, "private": true, "engines": { - "node": "^0.10.40", - "npm": "^2.14.9" + "node": "^4.2.1", + "npm": "^3.3.10" }, "scripts": { "test": "gulp test", @@ -115,6 +122,7 @@ "karma-ng-html2js-preprocessor": "~0.1.0", "karma-phantomjs-launcher": "~0.1.0", "karma-requirejs": "~0.2.0", + "requirejs": "~2.1", "karma-script-launcher": "~0.1.0", "lcov-result-merger": "^1.0.2", "mocha": "^2.3.3", diff --git a/website/src/controllers/api-v2/unsubscription.js b/website/src/controllers/api-v2/unsubscription.js index f768236ee5..772d0580e9 100644 --- a/website/src/controllers/api-v2/unsubscription.js +++ b/website/src/controllers/api-v2/unsubscription.js @@ -15,7 +15,7 @@ api.unsubscribe = function(req, res, next){ $set: {'preferences.emailNotifications.unsubscribeFromAll': true} }, {multi: false}, function(err, updateRes){ if(err) return next(err); - if(updateRes !== 1) return res.json(404, {err: 'User not found'}); + if(updateRes.n !== 1) return res.json(404, {err: 'User not found'}); res.send('

' + i18n.t('unsubscribedSuccessfully', null, req.language) + '

' + i18n.t('unsubscribedTextUsers', null, req.language)); }); diff --git a/website/src/libs/i18n.js b/website/src/libs/i18n.js index f2170b453c..b769afe697 100644 --- a/website/src/libs/i18n.js +++ b/website/src/libs/i18n.js @@ -2,6 +2,7 @@ var fs = require('fs'), path = require('path'), _ = require('lodash'), User = require('../models/user').model, + accepts = require('accepts'), shared = require('../../../common'), translations = {}; @@ -54,7 +55,7 @@ _.each(langCodes, function(code){ lang.momentLangCode = (momentLangsMapping[code] || code); try{ // MomentJS lang files are JS files that has to be executed in the browser so we load them as plain text files - var f = fs.readFileSync(path.join(__dirname, '/../../../node_modules/moment/locale/' + lang.momentLangCode + '.js'), 'utf8'); + var f = fs.readFileSync(path.join(__dirname, '/../../node_modules/moment/locale/' + lang.momentLangCode + '.js'), 'utf8'); momentLangs[code] = f; }catch (e){} }); @@ -74,7 +75,9 @@ var chineseVersions = ['zh-tw']; var getUserLanguage = function(req, res, next){ var getFromBrowser = function(){ - var acceptable = _(req.acceptedLanguages).map(function(lang){ + var acceptedLanguages = accepts(req).languages(); + + var acceptable = _(acceptedLanguages).map(function(lang){ return lang.slice(0, 2); }).uniq().value(); @@ -83,7 +86,7 @@ var getUserLanguage = function(req, res, next){ var iAcceptedCompleteLang = (matches.length > 0) ? multipleVersionsLanguages.indexOf(matches[0].toLowerCase()) : -1; if(iAcceptedCompleteLang !== -1){ - var acceptedCompleteLang = _.find(req.acceptedLanguages, function(accepted){ + var acceptedCompleteLang = _.find(acceptedLanguages, function(accepted){ return accepted.slice(0, 2) == multipleVersionsLanguages[iAcceptedCompleteLang]; }); diff --git a/website/src/server.js b/website/src/server.js index 94bffe592b..8a25354e93 100644 --- a/website/src/server.js +++ b/website/src/server.js @@ -12,13 +12,14 @@ var cores = +nconf.get("WEB_CONCURRENCY") || 0; if (cores!==0 && cluster.isMaster && (isDev || isProd)) { // Fork workers. If config.json has CORES=x, use that - otherwise, use all cpus-1 (production) - _.times(cores, cluster.fork); + for (var i = 0; i < cores; i += 1) { + cluster.fork(); + } cluster.on('disconnect', function(worker, code, signal) { var w = cluster.fork(); // replace the dead worker logging.info('[%s] [master:%s] worker:%s disconnect! new worker:%s fork', new Date(), process.pid, worker.process.pid, w.process.pid); }); - } else { require('coffee-script'); // remove this once we've fully converted over var express = require("express"); @@ -98,38 +99,60 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) { var newApp = express(); // api v3 // Route requests to the right app - app.use(app.router); // Matches all request except the ones going to /api/v3/** app.all(/^(?!\/api\/v3).+/i, oldApp); // Matches all requests going to /api/v3 app.all('/api/v3', newApp); - require('./middlewares/apiThrottle')(oldApp); + //require('./middlewares/apiThrottle')(oldApp); oldApp.use(require('./middlewares/domain')(server,mongoose)); - if (!isProd && !DISABLE_LOGGING) oldApp.use(express.logger("dev")); - oldApp.use(express.compress()); + if (!isProd && !DISABLE_LOGGING) oldApp.use(require('morgan')("dev")); + oldApp.use(require('compression')()); oldApp.set("views", __dirname + "/../views"); oldApp.set("view engine", "jade"); - oldApp.use(express.favicon(publicDir + '/favicon.ico')); + oldApp.use(require('serve-favicon')(publicDir + '/favicon.ico')); oldApp.use(require('./middlewares/cors')); var redirects = require('./middlewares/redirects'); oldApp.use(redirects.forceHabitica); oldApp.use(redirects.forceSSL); - oldApp.use(express.urlencoded()); - oldApp.use(express.json()); + var bodyParser = require('body-parser'); + // Default limit is 100kb, need that because we actually send whole groups to the server + // FIXME as soon as possible (need to move on the client from $resource -> $http) + oldApp.use(bodyParser.urlencoded({ + limit: '1mb', + parameterLimit: 10000, // Upped for safety from 1k, FIXME as above + extended: true // Uses 'qs' library as old connect middleware + })); + oldApp.use(bodyParser.json({ + limit: '1mb' + })); oldApp.use(require('method-override')()); - //oldApp.use(express.cookieParser(nconf.get('SESSION_SECRET'))); - oldApp.use(express.cookieParser()); - oldApp.use(express.cookieSession({ secret: nconf.get('SESSION_SECRET'), httpOnly: false, cookie: { maxAge: TWO_WEEKS }})); - //oldApp.use(express.session()); + + oldApp.use(require('cookie-parser')()); + oldApp.use(require('cookie-session')({ + name: 'connect:sess', // Used to keep backward compatibility with Express 3 cookies + secret: nconf.get('SESSION_SECRET'), + httpOnly: false, + maxAge: TWO_WEEKS + })); // Initialize Passport! Also use passport.session() middleware, to support // persistent login sessions (recommended). oldApp.use(passport.initialize()); oldApp.use(passport.session()); - oldApp.use(oldApp.router); + // Custom Directives + oldApp.use(require('./routes/pages')); + oldApp.use(require('./routes/payments')); + oldApp.use(require('./routes/api-v2/auth')); + oldApp.use(require('./routes/api-v2/coupon')); + oldApp.use(require('./routes/api-v2/unsubscription')); + var v2 = express(); + oldApp.use('/api/v2', v2); + oldApp.use('/api/v1', require('./routes/api-v1')); + oldApp.use('/export', require('./routes/dataexport')); + require('./routes/api-v2/swagger')(swagger, v2); var maxAge = isProd ? 31536000000 : 0; // Cache emojis without copying them to build, they are too many @@ -140,17 +163,6 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) { oldApp.use('/common/img', express['static'](publicDir + "/../../common/img", { maxAge: maxAge })); oldApp.use(express['static'](publicDir)); - // Custom Directives - oldApp.use(require('./routes/pages').middleware); - oldApp.use(require('./routes/payments').middleware); - oldApp.use(require('./routes/api-v2/auth').middleware); - oldApp.use(require('./routes/api-v2/coupon').middleware); - oldApp.use(require('./routes/api-v2/unsubscription').middleware); - var v2 = express(); - oldApp.use('/api/v2', v2); - oldApp.use('/api/v1', require('./routes/api-v1').middleware); - oldApp.use('/export', require('./routes/dataexport').middleware); - require('./routes/api-v2/swagger')(swagger, v2); oldApp.use(require('./middlewares/errorHandler')); server.on('request', app);