From f95dac7d1d7589f04360b3444fc34abfe7b72d58 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:06:10 -0700 Subject: [PATCH 01/10] chore(analytics): upgrade GA to universal analytics (cc @deilann) --- public/js/controllers/footerCtrl.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js index 6541f6f70f..3a256b8fbf 100644 --- a/public/js/controllers/footerCtrl.js +++ b/public/js/controllers/footerCtrl.js @@ -22,8 +22,12 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not // Google Analytics, only in production if (window.env.NODE_ENV === 'production') { - window._gaq = [["_setAccount", "UA-33510635-1"], ["_setDomainName", "habitrpg.com"], ["_trackPageview"]]; - $.getScript(("https:" === document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js"); + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + ga('create', 'UA-33510635-1', 'habitrpg.com'); + ga('send', 'pageview'); } // Scripts only for desktop From 535fd4fe8229e197b727338eda6ddcc9ed889bb1 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:41:47 -0700 Subject: [PATCH 02/10] refactor(footer): remove amazon affiliate code --- public/js/controllers/footerCtrl.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js index 3a256b8fbf..825092053b 100644 --- a/public/js/controllers/footerCtrl.js +++ b/public/js/controllers/footerCtrl.js @@ -13,13 +13,6 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not // Stripe $.getScript('//checkout.stripe.com/v2/checkout.js'); - // Amazon Affiliate -// if ($rootScope.authenticated() && !User.user.purchased.ads) { -// $.getScript('//wms.assoc-amazon.com/20070822/US/js/link-enhancer-common.js?tag=ha0d2-20').fail(function() { -// $('body').append(''); -// }); -// } - // Google Analytics, only in production if (window.env.NODE_ENV === 'production') { (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ From 43d05a54a310ddacd6094ff14cbf546f13b3cda3 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:42:23 -0700 Subject: [PATCH 03/10] refactor(footer): ensure debug buttons only show in development --- public/js/controllers/footerCtrl.js | 47 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js index 825092053b..30ccbd2c8b 100644 --- a/public/js/controllers/footerCtrl.js +++ b/public/js/controllers/footerCtrl.js @@ -41,27 +41,30 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not /** * Debug functions. Note that the server route for gems is only available if process.env.DEBUG=true */ - $scope.addMissedDay = function(){ - if (!confirm("Are you sure you want to reset the day?")) return; - var dayBefore = moment(User.user.lastCron).subtract('days', 1).toDate(); - User.set({'lastCron': dayBefore}); - Notification.text('-1 day, remember to refresh'); - } - $scope.addTenGems = function(){ - $http.post(API_URL + '/api/v2/user/addTenGems').success(function(){ - User.log({}); - }) - } - $scope.addLevelsAndGold = function(){ - User.set({ - 'stats.exp': User.user.stats.exp + 10000, - 'stats.gp': User.user.stats.gp + 10000, - 'stats.mp': User.user.stats.mp + 10000 - }); - } - $scope.addOneLevel = function(){ - User.set({ - 'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10) - }); + if (window.env.NODE_ENV === 'development') { + $scope.addMissedDay = function(){ + if (!confirm("Are you sure you want to reset the day?")) return; + var dayBefore = moment(User.user.lastCron).subtract('days', 1).toDate(); + User.set({'lastCron': dayBefore}); + Notification.text('-1 day, remember to refresh'); + } + $scope.addTenGems = function(){ + $http.post(API_URL + '/api/v2/user/addTenGems').success(function(){ + User.log({}); + }) + } + $scope.addLevelsAndGold = function(){ + User.set({ + 'stats.exp': User.user.stats.exp + 10000, + 'stats.gp': User.user.stats.gp + 10000, + 'stats.mp': User.user.stats.mp + 10000 + }); + } + $scope.addOneLevel = function(){ + User.set({ + 'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10) + }); + } } + }]) \ No newline at end of file From 67ee011aa35969db93e2d7dc1cd1e1f587f146de Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:43:03 -0700 Subject: [PATCH 04/10] fix(footer): ensure window.env is accessible from static pages, so we can get deferred scripts on frontpage (esp google analytics) --- public/js/controllers/footerCtrl.js | 3 ++- public/manifest.json | 3 ++- views/static/layout.jade | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js index 30ccbd2c8b..bcdd7ea6a5 100644 --- a/public/js/controllers/footerCtrl.js +++ b/public/js/controllers/footerCtrl.js @@ -1,6 +1,7 @@ "use strict"; -habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Notification', 'API_URL', +(typeof habitrpg !== 'undefined' ? habitrpg : habitrpgStatic) + .controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Notification', 'API_URL', function($scope, $rootScope, User, $http, Notification, API_URL) { /** diff --git a/public/manifest.json b/public/manifest.json index 2d616d2a19..416553e18e 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -84,7 +84,8 @@ "js/static.js", "js/services/notificationServices.js", "bower_components/habitrpg-shared/script/userServices.js", - "js/controllers/authCtrl.js" + "js/controllers/authCtrl.js", + "js/controllers/footerCtrl.js" ], "css": [ "bower_components/bootstrap/docs/assets/css/bootstrap.css", diff --git a/views/static/layout.jade b/views/static/layout.jade index 5492c2365f..081fbdb637 100644 --- a/views/static/layout.jade +++ b/views/static/layout.jade @@ -1,12 +1,15 @@ //Trick needed to pass 'env' to ./layout block vars doctype 5 -html +html(ng-app='habitrpgStatic') head block title title=env.t('titleIndex') + script(type='text/javascript'). + window.env = !{JSON.stringify(env)}; + link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=2') meta(charset='utf-8') @@ -18,7 +21,7 @@ html $.getScript("//s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire"); body - div(ng-app='habitrpgStatic',ng-controller='AuthCtrl',style='margin-top:60px;') + div(ng-controller='AuthCtrl',style='margin-top:60px;') include ./login-modal .navbar.navbar-inverse.navbar.navbar-inverse.navbar-fixed-top .navbar-inner From 4d32092e8f403e1091cef7ec4aae5c2613cb4690 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:53:32 -0700 Subject: [PATCH 05/10] refactor(addthis): remove superfluous addthis inclusion --- views/static/layout.jade | 3 --- 1 file changed, 3 deletions(-) diff --git a/views/static/layout.jade b/views/static/layout.jade index 081fbdb637..c55193eb13 100644 --- a/views/static/layout.jade +++ b/views/static/layout.jade @@ -17,9 +17,6 @@ html(ng-app='habitrpgStatic') != env.getManifestFiles("static") - script(type='text/javascript'). - $.getScript("//s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire"); - body div(ng-controller='AuthCtrl',style='margin-top:60px;') include ./login-modal From 2e2fcfcf464fbae21bff9e1be1ca915f071b976b Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 11:53:52 -0700 Subject: [PATCH 06/10] fix(swagger): fix jade script warning in swagger --- views/static/api.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/static/api.jade b/views/static/api.jade index 16b55d8277..276f3bee20 100644 --- a/views/static/api.jade +++ b/views/static/api.jade @@ -16,7 +16,7 @@ html script(src='/bower_components/swagger-ui/dist/lib/swagger.js', type='text/javascript') script(src='/bower_components/swagger-ui/dist/swagger-ui.js', type='text/javascript') script(src='/bower_components/swagger-ui/dist/lib/highlight.7.3.pack.js', type='text/javascript') - script(type='text/javascript') + script(type='text/javascript'). $(function () { window.swaggerUi = new SwaggerUi({ url: "/api/v2/api-docs", From 1a652eefd6640471ca747765acd92aeff5708ecf Mon Sep 17 00:00:00 2001 From: deilann Date: Mon, 3 Feb 2014 12:42:09 -0800 Subject: [PATCH 07/10] pull correct information for member modal class --- views/shared/modals/members.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/shared/modals/members.jade b/views/shared/modals/members.jade index 925d9267df..508ecce4e1 100644 --- a/views/shared/modals/members.jade +++ b/views/shared/modals/members.jade @@ -16,7 +16,7 @@ div(ng-controller='MemberModalCtrl') li(ng-show='profile.auth.timestamps.loggedin')=env.t('lastLoggedIn') | {{timestamp(profile.auth.timestamps.loggedin)}} - h3=env.t('stats') - .label.label-info {{ {warrior:'Warrior',wizard:'Mage',healer:'Healer',rogue:'Rogue'}[user.stats.class] }} + .label.label-info {{ {warrior:'Warrior',wizard:'Mage',healer:'Healer',rogue:'Rogue'}[profile.stats.class] }} include ../profiles/stats .span6 include ../header/avatar From 6a86da316bc310f295d4af72ce1362bb0c78bef2 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 17:05:18 -0700 Subject: [PATCH 08/10] chore(mongoose): set some options per #2725 to address high number of open connections, replset connection timeout, and close mongoose connection on process death --- src/models/challenge.js | 1 - src/models/group.js | 3 --- src/server.js | 21 ++++++++++++--------- src/utils.js | 29 ++++++++--------------------- 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/models/challenge.js b/src/models/challenge.js index 2656bebe1b..a01cea9575 100644 --- a/src/models/challenge.js +++ b/src/models/challenge.js @@ -3,7 +3,6 @@ var Schema = mongoose.Schema; var shared = require('habitrpg-shared'); var _ = require('lodash'); var TaskSchemas = require('./task'); -var Group = require('./group').model; var ChallengeSchema = new Schema({ _id: {type: String, 'default': shared.uuid}, diff --git a/src/models/group.js b/src/models/group.js index fa901dad8f..f3b3cad8e5 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -3,7 +3,6 @@ var Schema = mongoose.Schema; var shared = require('habitrpg-shared'); var _ = require('lodash'); var async = require('async'); -var User = require('./user').model; var GroupSchema = new Schema({ _id: {type: String, 'default': shared.uuid}, @@ -161,8 +160,6 @@ GroupSchema.methods.finishQuest = function(quest, cb) { }) var members = _.keys(group.quest.members); group.quest = {};group.markModified('quest'); - // FIXME this is TERRIBLE practice. Looks like there are circular dependencies in the models, such that `var User` at - // this point is undefined. So we get around that by loading from mongoose only once we get to this point mongoose.models.User.update({_id:{$in:members}}, updates, {multi:true}, cb); } diff --git a/src/server.js b/src/server.js index aa734c7d3a..81ffb155d4 100644 --- a/src/server.js +++ b/src/server.js @@ -35,14 +35,18 @@ if (cluster.isMaster && (isDev || isProd)) { // ------------ MongoDB Configuration ------------ mongoose = require('mongoose'); - require('./models/user'); //load up the user schema - TODO is this necessary? - require('./models/group'); - require('./models/challenge'); - mongoose.connect(nconf.get('NODE_DB_URI'), {auto_reconnect:true}, function(err) { - if (err) throw err; - logging.info('Connected with Mongoose'); + var mongooseOptions = !isProd ? {} : { + replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }, + server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } } + }; + mongoose.connect(nconf.get('NODE_DB_URI'), mongooseOptions, function(err) { + if (err) throw err; + logging.info('Connected with Mongoose'); }); - + // load schemas & models + require('./challenge'); + require('./group'); + require('./user'); // ------------ Passport Configuration ------------ var passport = require('passport') @@ -63,7 +67,6 @@ if (cluster.isMaster && (isDev || isProd)) { done(null, obj); }); - // Use the FacebookStrategy within Passport. // Strategies in Passport require a `verify` function, which accept // credentials (in this case, an accessToken, refreshToken, and Facebook @@ -135,7 +138,7 @@ if (cluster.isMaster && (isDev || isProd)) { app.use('/api/v1', require('./routes/apiv1').middleware); app.use('/export', require('./routes/dataexport').middleware); - app.use(utils.crashWorker(server)); + app.use(utils.crashWorker(server,mongoose)); app.use(utils.errorHandler); require('./routes/apiv2.coffee')(swagger, v2); diff --git a/src/utils.js b/src/utils.js index 4ff8f2a895..1fb45587af 100644 --- a/src/utils.js +++ b/src/utils.js @@ -6,10 +6,10 @@ var cluster = require("cluster"); module.exports.sendEmail = function(mailData) { var smtpTransport = nodemailer.createTransport("SMTP",{ - service: nconf.get('SMTP_SERVICE'), + service: nconf.get('SMTP_SERVICE'), auth: { - user: nconf.get('SMTP_USER'), - pass: nconf.get('SMTP_PASS') + user: nconf.get('SMTP_USER'), + pass: nconf.get('SMTP_PASS') } }); smtpTransport.sendMail(mailData, function(error, response){ @@ -33,8 +33,6 @@ module.exports.makeSalt = function() { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len); } - - /** * Load nconf and define default configuration values if config.json or ENV vars are not found */ @@ -44,25 +42,13 @@ module.exports.setupConfig = function(){ //.file('defaults', path.join(path.resolve(__dirname, '../config.json.example'))) .file('user', path.join(path.resolve(__dirname, '../config.json'))); -// var agent; -// if (process.env.NODE_ENV === 'development') { -// // Follow these instructions for profiling / debugging leaks -// // * https://developers.google.com/chrome-developer-tools/docs/heap-profiling -// // * https://developers.google.com/chrome-developer-tools/docs/memory-analysis-101 -// agent = require('webkit-devtools-agent'); -// var logging = require('./logging'); -// logging.info("To debug memory leaks:" + -// "\n\t(1) Run `kill -SIGUSR2 " + process.pid + "`" + -// "\n\t(2) open http://c4milo.github.com/node-webkit-agent/21.0.1180.57/inspector.html?host=localhost:1337&page=0"); -// } - - if (nconf.get('NODE_ENV') === "development") { + if (nconf.get('NODE_ENV') === "development") Error.stackTraceLimit = Infinity; - } - if (nconf.get('NODE_ENV') === 'production') require('newrelic'); + if (nconf.get('NODE_ENV') === 'production') + require('newrelic'); }; -module.exports.crashWorker = function(server) { +module.exports.crashWorker = function(server,mongoose) { return function(err, req, res, next) { if (!cluster.isMaster) { // make sure we close down within 30 seconds @@ -73,6 +59,7 @@ module.exports.crashWorker = function(server) { killtimer.unref(); // stop taking new requests. server.close(); + mongoose.connection.close(); cluster.worker.disconnect(); } next(err); From 2786b362067efdd245c3efa3a4891021fcfaab2d Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 18:14:17 -0700 Subject: [PATCH 09/10] fix(mongoose): typo --- src/server.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server.js b/src/server.js index 81ffb155d4..04981a8147 100644 --- a/src/server.js +++ b/src/server.js @@ -44,9 +44,9 @@ if (cluster.isMaster && (isDev || isProd)) { logging.info('Connected with Mongoose'); }); // load schemas & models - require('./challenge'); - require('./group'); - require('./user'); + require('./models/challenge'); + require('./models/group'); + require('./models/user'); // ------------ Passport Configuration ------------ var passport = require('passport') From 9b3814575e5c2191fd9452ba7fd4a9f47bba6141 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Tue, 4 Feb 2014 09:49:49 -0700 Subject: [PATCH 10/10] perf(hall): use $gt in contributors.level index instead of $ne:null for better performance --- src/controllers/hall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/hall.js b/src/controllers/hall.js index 068efdfc3e..0edbd9e867 100644 --- a/src/controllers/hall.js +++ b/src/controllers/hall.js @@ -13,7 +13,7 @@ api.ensureAdmin = function(req, res, next) { } api.getHeroes = function(req,res,next) { - User.find({'contributor.level':{$ne:null}})// {$exists:true} causes terrible performance http://goo.gl/GCxzC9 + User.find({'contributor.level':{$gt:0}}) .select('contributor backer balance profile.name') .sort('-contributor.level') .exec(function(err, users){