From 34dd4494ec6fe7a9d98de237769444f71c9d0891 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 13:10:53 +0200 Subject: [PATCH 01/10] in locals middleware require tavern and mods only once --- website/src/middlewares/locals.js | 5 +++-- website/src/models/user.js | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index fa693895c1..1ba502eda8 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -6,6 +6,8 @@ var i18n = require('../i18n.js'); var buildManifest = require('../libs/buildManifest'); var shared = require('../../../common'); var forceRefresh = require('./forceRefresh'); +var tavern = require('../models/group').tavern; +var mods = require('../models/user').mods; module.exports = function(req, res, next) { var language = _.find(i18n.avalaibleLanguages, {code: req.language}); @@ -14,7 +16,6 @@ module.exports = function(req, res, next) { // Load moment.js language file only when not on static pages language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined); - var tavern = require('../models/group').tavern; var envVars = _.pick(nconf.get(), 'NODE_ENV BASE_URL GA_ID STRIPE_PUB_KEY FACEBOOK_KEY AMPLITUDE_KEY'.split(' ')); res.locals.habitrpg = _.merge(envVars, { IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), @@ -31,7 +32,7 @@ module.exports = function(req, res, next) { }, siteVersion: forceRefresh.siteVersion, Content: shared.content, - mods: require('../models/user').mods, + mods: mods, tavern: tavern, // for world boss worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {}, _: _, diff --git a/website/src/models/user.js b/website/src/models/user.js index c06765f805..2f8da5a0ee 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -577,6 +577,10 @@ UserSchema.methods.unlink = function(options, cb) { module.exports.schema = UserSchema; module.exports.model = mongoose.model("User", UserSchema); +// Initially export an empty object so external requires will get +// the right object by reference when it's defined later +// Otherwise it would remain undefined if requested before the query executes +module.exports.mods = {}; mongoose.model("User") .find({'contributor.admin':true}) From e1620bad2baa7e4033ecbf4f24fad45492caf587 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 14:53:17 +0200 Subject: [PATCH 02/10] stringify into window.env only what we really need, save a lot of KBs --- website/src/controllers/dataexport.js | 4 ++- website/src/middlewares/locals.js | 52 ++++++++++++++++++--------- website/views/avatar-static.jade | 4 ++- website/views/static/front.jade | 2 +- website/views/static/layout.jade | 2 +- website/views/static/new-stuff.jade | 2 +- 6 files changed, 44 insertions(+), 22 deletions(-) diff --git a/website/src/controllers/dataexport.js b/website/src/controllers/dataexport.js index 6439408327..c309857434 100644 --- a/website/src/controllers/dataexport.js +++ b/website/src/controllers/dataexport.js @@ -99,10 +99,12 @@ expressres.jsonstring = function(obj, headers, status) { dataexport.avatarPage = function(req, res) { + var env = _.defaults({user:user}, res.locals.habitrpg); + User.findById(req.params.uuid).select('stats profile items achievements preferences backer contributor').exec(function(err, user){ res.render('avatar-static', { title: user.profile.name, - env: _.defaults({user:user},res.locals.habitrpg) + env: env }); }) }; diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index 1ba502eda8..4e0ca864c6 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -9,6 +9,33 @@ var forceRefresh = require('./forceRefresh'); var tavern = require('../models/group').tavern; var mods = require('../models/user').mods; +// To avoid stringifying more data then we need, +// items from `env` used on the client will have to be specified in this array +var clientVars = ['language', 'isStaticPage', 'avalaibleLanguages', 'translations', + 'FACEBOOK_KEY', 'NODE_ENV', 'BASE_URL', 'GA_ID', + 'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY', + 'worldDmg', 'IS_MOBILE']; + +var env = { + getManifestFiles: buildManifest.getManifestFiles, + getBuildUrl: buildManifest.getBuildUrl, + _: _, + clientVars: clientVars, + tavern: tavern, // for world boss + mods: mods, + Content: shared.content, + siteVersion: forceRefresh.siteVersion, + avalaibleLanguages: i18n.avalaibleLanguages, + AMAZON_PAYMENTS: { + SELLER_ID: nconf.get('AMAZON_PAYMENTS:SELLER_ID'), + CLIENT_ID: nconf.get('AMAZON_PAYMENTS:CLIENT_ID') + } +}; + +'NODE_ENV BASE_URL GA_ID STRIPE_PUB_KEY FACEBOOK_KEY AMPLITUDE_KEY'.split(' ').forEach(function(key){ + env[key] = nconf.get(key); +}); + module.exports = function(req, res, next) { var language = _.find(i18n.avalaibleLanguages, {code: req.language}); var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' @@ -16,12 +43,8 @@ module.exports = function(req, res, next) { // Load moment.js language file only when not on static pages language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined); - var envVars = _.pick(nconf.get(), 'NODE_ENV BASE_URL GA_ID STRIPE_PUB_KEY FACEBOOK_KEY AMPLITUDE_KEY'.split(' ')); - res.locals.habitrpg = _.merge(envVars, { + res.locals.habitrpg = _.merge(env, { IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), - getManifestFiles: buildManifest.getManifestFiles, - getBuildUrl: buildManifest.getBuildUrl, - avalaibleLanguages: i18n.avalaibleLanguages, language: language, isStaticPage: isStaticPage, translations: i18n.translations[language.code], @@ -30,23 +53,18 @@ module.exports = function(req, res, next) { args.push(language.code); return shared.i18n.t.apply(null, args); }, - siteVersion: forceRefresh.siteVersion, - Content: shared.content, - mods: mods, - tavern: tavern, // for world boss + // Defined here and not outside of the middleware because tavern might be an + // empty object until the query to fetch it finishes worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {}, - _: _, - AMAZON_PAYMENTS: { - SELLER_ID: nconf.get('AMAZON_PAYMENTS:SELLER_ID'), - CLIENT_ID: nconf.get('AMAZON_PAYMENTS:CLIENT_ID') - } }); // Put query-string party (& guild but use partyInvite for backward compatibility) // invitations into session to be handled later - try{ - req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)); - } catch(e){} + if(req.query.partyInvite){ + try{ + req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)); + } catch(e){} + } next(); }; \ No newline at end of file diff --git a/website/views/avatar-static.jade b/website/views/avatar-static.jade index 66c57040f8..d699391c39 100644 --- a/website/views/avatar-static.jade +++ b/website/views/avatar-static.jade @@ -8,8 +8,10 @@ html(ng-app="habitrpg") meta(name='viewport', content='width=device-width, initial-scale=1.0') meta(name='apple-mobile-web-app-capable', content='yes') + // .slice(0).push('user') is to clone the array, + // to be surethat `user` is never avalaible to other requests' env script(type='text/javascript'). - window.env = !{JSON.stringify(env)}; + window.env = !{JSON.stringify(env._.pick(env, env.clientVars.slice(0).push('user')))}; != env.getManifestFiles("app") diff --git a/website/views/static/front.jade b/website/views/static/front.jade index 490e6fd01c..a377ea0fe7 100644 --- a/website/views/static/front.jade +++ b/website/views/static/front.jade @@ -26,7 +26,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') link(rel='stylesheet', type='text/css', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css') script(type='text/javascript'). - window.env = !{JSON.stringify(env)}; + window.env = !{JSON.stringify(env._.pick(env, env.clientVars))}; != env.getManifestFiles("tmp_static_front") script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js') diff --git a/website/views/static/layout.jade b/website/views/static/layout.jade index 329f84e455..db2355b8c9 100644 --- a/website/views/static/layout.jade +++ b/website/views/static/layout.jade @@ -17,7 +17,7 @@ html(ng-app='habitrpg') script(type='text/javascript'). - window.env = !{JSON.stringify(env)}; + window.env = !{JSON.stringify(env._.pick(env, env.clientVars))}; link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=4') diff --git a/website/views/static/new-stuff.jade b/website/views/static/new-stuff.jade index f50551269d..b2a6befbb1 100644 --- a/website/views/static/new-stuff.jade +++ b/website/views/static/new-stuff.jade @@ -7,7 +7,7 @@ html(ng-app='habitrpg') title=env.t('newStuff') script(type='text/javascript'). - window.env = !{JSON.stringify(env)}; + window.env = !{JSON.stringify(env._.pick(env, env.clientVars))}; link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=4') From d3c78bb890288953ca1cd947f4630585babd283c Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 15:02:16 +0200 Subject: [PATCH 03/10] revert dataexport controller changes --- website/src/controllers/dataexport.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/src/controllers/dataexport.js b/website/src/controllers/dataexport.js index c309857434..045d2c363f 100644 --- a/website/src/controllers/dataexport.js +++ b/website/src/controllers/dataexport.js @@ -99,12 +99,10 @@ expressres.jsonstring = function(obj, headers, status) { dataexport.avatarPage = function(req, res) { - var env = _.defaults({user:user}, res.locals.habitrpg); - User.findById(req.params.uuid).select('stats profile items achievements preferences backer contributor').exec(function(err, user){ res.render('avatar-static', { title: user.profile.name, - env: env + env: _.defaults({user:user}, res.locals.habitrpg); }); }) }; From 289d288f386d1d64a305512e282c77ac60d3d503 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 15:02:46 +0200 Subject: [PATCH 04/10] fix typo --- website/src/controllers/dataexport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/controllers/dataexport.js b/website/src/controllers/dataexport.js index 045d2c363f..1c88d2d90f 100644 --- a/website/src/controllers/dataexport.js +++ b/website/src/controllers/dataexport.js @@ -102,7 +102,7 @@ dataexport.avatarPage = function(req, res) { User.findById(req.params.uuid).select('stats profile items achievements preferences backer contributor').exec(function(err, user){ res.render('avatar-static', { title: user.profile.name, - env: _.defaults({user:user}, res.locals.habitrpg); + env: _.defaults({user:user}, res.locals.habitrpg) }); }) }; From dc4c6fa6e7c08c9d4a3e67be4e7881422a4a6b1d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 15:21:17 +0200 Subject: [PATCH 05/10] add TODO commit about logging errors catched when party invite code is invalid --- website/src/middlewares/locals.js | 1 + 1 file changed, 1 insertion(+) diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index 4e0ca864c6..b820e9e303 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -60,6 +60,7 @@ module.exports = function(req, res, next) { // Put query-string party (& guild but use partyInvite for backward compatibility) // invitations into session to be handled later + // TODO once we have proper logging in place, log errors here if(req.query.partyInvite){ try{ req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)); From 1840c3907bdcb3e6bf1fe33cbee76b8e9d9d9a15 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 15:37:04 +0200 Subject: [PATCH 06/10] fix avatar export page --- website/views/avatar-static.jade | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/website/views/avatar-static.jade b/website/views/avatar-static.jade index d699391c39..79cab4c963 100644 --- a/website/views/avatar-static.jade +++ b/website/views/avatar-static.jade @@ -10,8 +10,12 @@ html(ng-app="habitrpg") // .slice(0).push('user') is to clone the array, // to be surethat `user` is never avalaible to other requests' env + - + clientVars = env.clientVars.slice(0); + clientVars.push('user'); + script(type='text/javascript'). - window.env = !{JSON.stringify(env._.pick(env, env.clientVars.slice(0).push('user')))}; + window.env = !{JSON.stringify(env._.pick(env, clientVars))}; != env.getManifestFiles("app") From 3cda8b0b5688ab9ce2564c83746f2207010fac77 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 20:40:51 +0200 Subject: [PATCH 07/10] remove newrelic javascript from client --- website/views/index.jade | 3 ++- website/views/static/layout.jade | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/website/views/index.jade b/website/views/index.jade index 7770fb9e3c..c5c2ba0a90 100644 --- a/website/views/index.jade +++ b/website/views/index.jade @@ -10,7 +10,8 @@ html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":a meta(name='viewport', content='width=device-width, initial-scale=1.0') meta(name='apple-mobile-web-app-capable', content='yes') - if(env.NODE_ENV == 'production') + //- Disable NewRelic until we add it again on the server + if(env.NODE_ENV == 'production' && false) script(type='text/javascript'). window.NREUM||(NREUM={}),__nr_require=function(t,e,n){function r(n){if(!e[n]){var o=e[n]={exports:{}};t[n][0].call(o.exports,function(e){var o=t[n][1][e];return r(o?o:e)},o,o.exports)}return e[n].exports}if("function"==typeof __nr_require)return __nr_require;for(var o=0;od;d++)c[d].apply(u,n);return u}function a(t,e){f[t]=s(t).concat(e)}function s(t){return f[t]||[]}function c(){return n(e)}var f={};return{on:a,emit:e,create:c,listeners:s,_events:f}}function r(){return{}}var o="nr@context",i=t("gos");e.exports=n()},{gos:"7eSDFh"}],ee:[function(t,e){e.exports=t("QJf3ax")},{}],3:[function(t){function e(t,e,n,i,s){try{c?c-=1:r("err",[s||new UncaughtException(t,e,n)])}catch(f){try{r("ierr",[f,(new Date).getTime(),!0])}catch(u){}}return"function"==typeof a?a.apply(this,o(arguments)):!1}function UncaughtException(t,e,n){this.message=t||"Uncaught error with no additional information",this.sourceURL=e,this.line=n}function n(t){r("err",[t,(new Date).getTime()])}var r=t("handle"),o=t(5),i=t("ee"),a=window.onerror,s=!1,c=0;t("loader").features.err=!0,window.onerror=e,NREUM.noticeError=n;try{throw new Error}catch(f){"stack"in f&&(t(1),t(4),"addEventListener"in window&&t(2),window.XMLHttpRequest&&XMLHttpRequest.prototype&&XMLHttpRequest.prototype.addEventListener&&t(3),s=!0)}i.on("fn-start",function(){s&&(c+=1)}),i.on("fn-err",function(t,e,r){s&&(this.thrown=!0,n(r))}),i.on("fn-end",function(){s&&!this.thrown&&c>0&&(c-=1)}),i.on("internal-error",function(t){r("ierr",[t,(new Date).getTime(),!0])})},{1:8,2:5,3:9,4:7,5:21,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],4:[function(t){function e(){}if(window.performance&&window.performance.timing&&window.performance.getEntriesByType){var n=t("ee"),r=t("handle"),o=t(2);t("loader").features.stn=!0,t(1),n.on("fn-start",function(t){var e=t[0];e instanceof Event&&(this.bstStart=Date.now())}),n.on("fn-end",function(t,e){var n=t[0];n instanceof Event&&r("bst",[n,e,this.bstStart,Date.now()])}),o.on("fn-start",function(t,e,n){this.bstStart=Date.now(),this.bstType=n}),o.on("fn-end",function(t,e){r("bstTimer",[e,this.bstStart,Date.now(),this.bstType])}),n.on("pushState-start",function(){this.time=Date.now(),this.startPath=location.pathname+location.hash}),n.on("pushState-end",function(){r("bstHist",[location.pathname+location.hash,this.startPath,this.time])}),"addEventListener"in window.performance&&(window.performance.addEventListener("webkitresourcetimingbufferfull",function(){r("bstResource",[window.performance.getEntriesByType("resource")]),window.performance.webkitClearResourceTimings()},!1),window.performance.addEventListener("resourcetimingbufferfull",function(){r("bstResource",[window.performance.getEntriesByType("resource")]),window.performance.clearResourceTimings()},!1)),document.addEventListener("scroll",e,!1),document.addEventListener("keypress",e,!1),document.addEventListener("click",e,!1)}},{1:6,2:8,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],5:[function(t,e){function n(t){i.inPlace(t,["addEventListener","removeEventListener"],"-",r)}function r(t){return t[1]}var o=(t(1),t("ee").create()),i=t(2)(o),a=t("gos");if(e.exports=o,n(window),"getPrototypeOf"in Object){for(var s=document;s&&!s.hasOwnProperty("addEventListener");)s=Object.getPrototypeOf(s);s&&n(s);for(var c=XMLHttpRequest.prototype;c&&!c.hasOwnProperty("addEventListener");)c=Object.getPrototypeOf(c);c&&n(c)}else XMLHttpRequest.prototype.hasOwnProperty("addEventListener")&&n(XMLHttpRequest.prototype);o.on("addEventListener-start",function(t){if(t[1]){var e=t[1];"function"==typeof e?this.wrapped=t[1]=a(e,"nr@wrapped",function(){return i(e,"fn-",null,e.name||"anonymous")}):"function"==typeof e.handleEvent&&i.inPlace(e,["handleEvent"],"fn-")}}),o.on("removeEventListener-start",function(t){var e=this.wrapped;e&&(t[1]=e)})},{1:21,2:22,ee:"QJf3ax",gos:"7eSDFh"}],6:[function(t,e){var n=(t(2),t("ee").create()),r=t(1)(n);e.exports=n,r.inPlace(window.history,["pushState"],"-")},{1:22,2:21,ee:"QJf3ax"}],7:[function(t,e){var n=(t(2),t("ee").create()),r=t(1)(n);e.exports=n,r.inPlace(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame"],"raf-"),n.on("raf-start",function(t){t[0]=r(t[0],"fn-")})},{1:22,2:21,ee:"QJf3ax"}],8:[function(t,e){function n(t,e,n){var r=t[0];"string"==typeof r&&(r=new Function(r)),t[0]=o(r,"fn-",null,n)}var r=(t(2),t("ee").create()),o=t(1)(r);e.exports=r,o.inPlace(window,["setTimeout","setInterval","setImmediate"],"setTimer-"),r.on("setTimer-start",n)},{1:22,2:21,ee:"QJf3ax"}],9:[function(t,e){function n(){c.inPlace(this,d,"fn-")}function r(t,e){c.inPlace(e,["onreadystatechange"],"fn-")}function o(t,e){return e}var i=t("ee").create(),a=t(1),s=t(2),c=s(i),f=s(a),u=window.XMLHttpRequest,d=["onload","onerror","onabort","onloadstart","onloadend","onprogress","ontimeout"];e.exports=i,window.XMLHttpRequest=function(t){var e=new u(t);try{i.emit("new-xhr",[],e),f.inPlace(e,["addEventListener","removeEventListener"],"-",function(t,e){return e}),e.addEventListener("readystatechange",n,!1)}catch(r){try{i.emit("internal-error",[r])}catch(o){}}return e},window.XMLHttpRequest.prototype=u.prototype,c.inPlace(XMLHttpRequest.prototype,["open","send"],"-xhr-",o),i.on("send-xhr-start",r),i.on("open-xhr-start",r)},{1:5,2:22,ee:"QJf3ax"}],10:[function(t){function e(t){if("string"==typeof t&&t.length)return t.length;if("object"!=typeof t)return void 0;if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer&&t.byteLength)return t.byteLength;if("undefined"!=typeof Blob&&t instanceof Blob&&t.size)return t.size;if("undefined"!=typeof FormData&&t instanceof FormData)return void 0;try{return JSON.stringify(t).length}catch(e){return void 0}}function n(t){var n=this.params,r=this.metrics;if(!this.ended){this.ended=!0;for(var i=0;c>i;i++)t.removeEventListener(s[i],this.listener,!1);if(!n.aborted){if(r.duration=(new Date).getTime()-this.startTime,4===t.readyState){n.status=t.status;var a=t.responseType,f="arraybuffer"===a||"blob"===a||"json"===a?t.response:t.responseText,u=e(f);if(u&&(r.rxSize=u),this.sameOrigin){var d=t.getResponseHeader("X-NewRelic-App-Data");d&&(n.cat=d.split(", ").pop())}}else n.status=0;r.cbTime=this.cbTime,o("xhr",[n,r,this.startTime])}}}function r(t,e){var n=i(e),r=t.params;r.host=n.hostname+":"+n.port,r.pathname=n.pathname,t.sameOrigin=n.sameOrigin}if(window.XMLHttpRequest&&XMLHttpRequest.prototype&&XMLHttpRequest.prototype.addEventListener&&!/CriOS/.test(navigator.userAgent)){t("loader").features.xhr=!0;var o=t("handle"),i=t(2),a=t("ee"),s=["load","error","abort","timeout"],c=s.length,f=t(1);t(4),t(3),a.on("new-xhr",function(){this.totalCbs=0,this.called=0,this.cbTime=0,this.end=n,this.ended=!1,this.xhrGuids={}}),a.on("open-xhr-start",function(t){this.params={method:t[0]},r(this,t[1]),this.metrics={}}),a.on("open-xhr-end",function(t,e){"loader_config"in NREUM&&"xpid"in NREUM.loader_config&&this.sameOrigin&&e.setRequestHeader("X-NewRelic-ID",NREUM.loader_config.xpid)}),a.on("send-xhr-start",function(t,n){var r=this.metrics,o=t[0],i=this;if(r&&o){var f=e(o);f&&(r.txSize=f)}this.startTime=(new Date).getTime(),this.listener=function(t){try{"abort"===t.type&&(i.params.aborted=!0),("load"!==t.type||i.called===i.totalCbs&&(i.onloadCalled||"function"!=typeof n.onload))&&i.end(n)}catch(e){try{a.emit("internal-error",[e])}catch(r){}}};for(var u=0;c>u;u++)n.addEventListener(s[u],this.listener,!1)}),a.on("xhr-cb-time",function(t,e,n){this.cbTime+=t,e?this.onloadCalled=!0:this.called+=1,this.called!==this.totalCbs||!this.onloadCalled&&"function"==typeof n.onload||this.end(n)}),a.on("xhr-load-added",function(t,e){var n=""+f(t)+!!e;this.xhrGuids&&!this.xhrGuids[n]&&(this.xhrGuids[n]=!0,this.totalCbs+=1)}),a.on("xhr-load-removed",function(t,e){var n=""+f(t)+!!e;this.xhrGuids&&this.xhrGuids[n]&&(delete this.xhrGuids[n],this.totalCbs-=1)}),a.on("addEventListener-end",function(t,e){e instanceof XMLHttpRequest&&"load"===t[0]&&a.emit("xhr-load-added",[t[1],t[2]],e)}),a.on("removeEventListener-end",function(t,e){e instanceof XMLHttpRequest&&"load"===t[0]&&a.emit("xhr-load-removed",[t[1],t[2]],e)}),a.on("fn-start",function(t,e,n){e instanceof XMLHttpRequest&&("onload"===n&&(this.onload=!0),("load"===(t[0]&&t[0].type)||this.onload)&&(this.xhrCbStart=(new Date).getTime()))}),a.on("fn-end",function(t,e){this.xhrCbStart&&a.emit("xhr-cb-time",[(new Date).getTime()-this.xhrCbStart,this.onload,e],e)})}},{1:"XL7HBI",2:11,3:9,4:5,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],11:[function(t,e){e.exports=function(t){var e=document.createElement("a"),n=window.location,r={};e.href=t,r.port=e.port;var o=e.href.split("://");return!r.port&&o[1]&&(r.port=o[1].split("/")[0].split("@").pop().split(":")[1]),r.port&&"0"!==r.port||(r.port="https"===o[0]?"443":"80"),r.hostname=e.hostname||n.hostname,r.pathname=e.pathname,r.protocol=o[0],"/"!==r.pathname.charAt(0)&&(r.pathname="/"+r.pathname),r.sameOrigin=!e.hostname||e.hostname===document.domain&&e.port===n.port&&e.protocol===n.protocol,r}},{}],gos:[function(t,e){e.exports=t("7eSDFh")},{}],"7eSDFh":[function(t,e){function n(t,e,n){if(r.call(t,e))return t[e];var o=n();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(t,e,{value:o,writable:!0,enumerable:!1}),o}catch(i){}return t[e]=o,o}var r=Object.prototype.hasOwnProperty;e.exports=n},{}],D5DuLP:[function(t,e){function n(t,e,n){return r.listeners(t).length?r.emit(t,e,n):(o[t]||(o[t]=[]),void o[t].push(e))}var r=t("ee").create(),o={};e.exports=n,n.ee=r,r.q=o},{ee:"QJf3ax"}],handle:[function(t,e){e.exports=t("D5DuLP")},{}],XL7HBI:[function(t,e){function n(t){var e=typeof t;return!t||"object"!==e&&"function"!==e?-1:t===window?0:i(t,o,function(){return r++})}var r=1,o="nr@id",i=t("gos");e.exports=n},{gos:"7eSDFh"}],id:[function(t,e){e.exports=t("XL7HBI")},{}],loader:[function(t,e){e.exports=t("G9z0Bl")},{}],G9z0Bl:[function(t,e){function n(){var t=l.info=NREUM.info;if(t&&t.licenseKey&&t.applicationID&&f&&f.body){s(h,function(e,n){e in t||(t[e]=n)}),l.proto="https"===p.split(":")[0]||t.sslForHttp?"https://":"http://",a("mark",["onload",i()]);var e=f.createElement("script");e.src=l.proto+t.agent,f.body.appendChild(e)}}function r(){"complete"===f.readyState&&o()}function o(){a("mark",["domContent",i()])}function i(){return(new Date).getTime()}var a=t("handle"),s=t(1),c=window,f=c.document,u="addEventListener",d="attachEvent",p=(""+location).split("?")[0],h={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",agent:"js-agent.newrelic.com/nr-515.min.js"},l=e.exports={offset:i(),origin:p,features:{}};f[u]?(f[u]("DOMContentLoaded",o,!1),c[u]("load",n,!1)):(f[d]("onreadystatechange",r),c[d]("onload",n)),a("mark",["firstbyte",i()])},{1:20,handle:"D5DuLP"}],20:[function(t,e){function n(t,e){var n=[],o="",i=0;for(o in t)r.call(t,o)&&(n[i]=e(o,t[o]),i+=1);return n}var r=Object.prototype.hasOwnProperty;e.exports=n},{}],21:[function(t,e){function n(t,e,n){e||(e=0),"undefined"==typeof n&&(n=t?t.length:0);for(var r=-1,o=n-e||0,i=Array(0>o?0:o);++rd;d++)c[d].apply(u,n);return u}function a(t,e){f[t]=s(t).concat(e)}function s(t){return f[t]||[]}function c(){return n(e)}var f={};return{on:a,emit:e,create:c,listeners:s,_events:f}}function r(){return{}}var o="nr@context",i=t("gos");e.exports=n()},{gos:"7eSDFh"}],ee:[function(t,e){e.exports=t("QJf3ax")},{}],3:[function(t){function e(t,e,n,i,s){try{c?c-=1:r("err",[s||new UncaughtException(t,e,n)])}catch(f){try{r("ierr",[f,(new Date).getTime(),!0])}catch(u){}}return"function"==typeof a?a.apply(this,o(arguments)):!1}function UncaughtException(t,e,n){this.message=t||"Uncaught error with no additional information",this.sourceURL=e,this.line=n}function n(t){r("err",[t,(new Date).getTime()])}var r=t("handle"),o=t(5),i=t("ee"),a=window.onerror,s=!1,c=0;t("loader").features.err=!0,window.onerror=e,NREUM.noticeError=n;try{throw new Error}catch(f){"stack"in f&&(t(1),t(4),"addEventListener"in window&&t(2),window.XMLHttpRequest&&XMLHttpRequest.prototype&&XMLHttpRequest.prototype.addEventListener&&t(3),s=!0)}i.on("fn-start",function(){s&&(c+=1)}),i.on("fn-err",function(t,e,r){s&&(this.thrown=!0,n(r))}),i.on("fn-end",function(){s&&!this.thrown&&c>0&&(c-=1)}),i.on("internal-error",function(t){r("ierr",[t,(new Date).getTime(),!0])})},{1:8,2:5,3:9,4:7,5:21,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],4:[function(t){function e(){}if(window.performance&&window.performance.timing&&window.performance.getEntriesByType){var n=t("ee"),r=t("handle"),o=t(2);t("loader").features.stn=!0,t(1),n.on("fn-start",function(t){var e=t[0];e instanceof Event&&(this.bstStart=Date.now())}),n.on("fn-end",function(t,e){var n=t[0];n instanceof Event&&r("bst",[n,e,this.bstStart,Date.now()])}),o.on("fn-start",function(t,e,n){this.bstStart=Date.now(),this.bstType=n}),o.on("fn-end",function(t,e){r("bstTimer",[e,this.bstStart,Date.now(),this.bstType])}),n.on("pushState-start",function(){this.time=Date.now(),this.startPath=location.pathname+location.hash}),n.on("pushState-end",function(){r("bstHist",[location.pathname+location.hash,this.startPath,this.time])}),"addEventListener"in window.performance&&(window.performance.addEventListener("webkitresourcetimingbufferfull",function(){r("bstResource",[window.performance.getEntriesByType("resource")]),window.performance.webkitClearResourceTimings()},!1),window.performance.addEventListener("resourcetimingbufferfull",function(){r("bstResource",[window.performance.getEntriesByType("resource")]),window.performance.clearResourceTimings()},!1)),document.addEventListener("scroll",e,!1),document.addEventListener("keypress",e,!1),document.addEventListener("click",e,!1)}},{1:6,2:8,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],5:[function(t,e){function n(t){i.inPlace(t,["addEventListener","removeEventListener"],"-",r)}function r(t){return t[1]}var o=(t(1),t("ee").create()),i=t(2)(o),a=t("gos");if(e.exports=o,n(window),"getPrototypeOf"in Object){for(var s=document;s&&!s.hasOwnProperty("addEventListener");)s=Object.getPrototypeOf(s);s&&n(s);for(var c=XMLHttpRequest.prototype;c&&!c.hasOwnProperty("addEventListener");)c=Object.getPrototypeOf(c);c&&n(c)}else XMLHttpRequest.prototype.hasOwnProperty("addEventListener")&&n(XMLHttpRequest.prototype);o.on("addEventListener-start",function(t){if(t[1]){var e=t[1];"function"==typeof e?this.wrapped=t[1]=a(e,"nr@wrapped",function(){return i(e,"fn-",null,e.name||"anonymous")}):"function"==typeof e.handleEvent&&i.inPlace(e,["handleEvent"],"fn-")}}),o.on("removeEventListener-start",function(t){var e=this.wrapped;e&&(t[1]=e)})},{1:21,2:22,ee:"QJf3ax",gos:"7eSDFh"}],6:[function(t,e){var n=(t(2),t("ee").create()),r=t(1)(n);e.exports=n,r.inPlace(window.history,["pushState"],"-")},{1:22,2:21,ee:"QJf3ax"}],7:[function(t,e){var n=(t(2),t("ee").create()),r=t(1)(n);e.exports=n,r.inPlace(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame"],"raf-"),n.on("raf-start",function(t){t[0]=r(t[0],"fn-")})},{1:22,2:21,ee:"QJf3ax"}],8:[function(t,e){function n(t,e,n){var r=t[0];"string"==typeof r&&(r=new Function(r)),t[0]=o(r,"fn-",null,n)}var r=(t(2),t("ee").create()),o=t(1)(r);e.exports=r,o.inPlace(window,["setTimeout","setInterval","setImmediate"],"setTimer-"),r.on("setTimer-start",n)},{1:22,2:21,ee:"QJf3ax"}],9:[function(t,e){function n(){c.inPlace(this,d,"fn-")}function r(t,e){c.inPlace(e,["onreadystatechange"],"fn-")}function o(t,e){return e}var i=t("ee").create(),a=t(1),s=t(2),c=s(i),f=s(a),u=window.XMLHttpRequest,d=["onload","onerror","onabort","onloadstart","onloadend","onprogress","ontimeout"];e.exports=i,window.XMLHttpRequest=function(t){var e=new u(t);try{i.emit("new-xhr",[],e),f.inPlace(e,["addEventListener","removeEventListener"],"-",function(t,e){return e}),e.addEventListener("readystatechange",n,!1)}catch(r){try{i.emit("internal-error",[r])}catch(o){}}return e},window.XMLHttpRequest.prototype=u.prototype,c.inPlace(XMLHttpRequest.prototype,["open","send"],"-xhr-",o),i.on("send-xhr-start",r),i.on("open-xhr-start",r)},{1:5,2:22,ee:"QJf3ax"}],10:[function(t){function e(t){if("string"==typeof t&&t.length)return t.length;if("object"!=typeof t)return void 0;if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer&&t.byteLength)return t.byteLength;if("undefined"!=typeof Blob&&t instanceof Blob&&t.size)return t.size;if("undefined"!=typeof FormData&&t instanceof FormData)return void 0;try{return JSON.stringify(t).length}catch(e){return void 0}}function n(t){var n=this.params,r=this.metrics;if(!this.ended){this.ended=!0;for(var i=0;c>i;i++)t.removeEventListener(s[i],this.listener,!1);if(!n.aborted){if(r.duration=(new Date).getTime()-this.startTime,4===t.readyState){n.status=t.status;var a=t.responseType,f="arraybuffer"===a||"blob"===a||"json"===a?t.response:t.responseText,u=e(f);if(u&&(r.rxSize=u),this.sameOrigin){var d=t.getResponseHeader("X-NewRelic-App-Data");d&&(n.cat=d.split(", ").pop())}}else n.status=0;r.cbTime=this.cbTime,o("xhr",[n,r,this.startTime])}}}function r(t,e){var n=i(e),r=t.params;r.host=n.hostname+":"+n.port,r.pathname=n.pathname,t.sameOrigin=n.sameOrigin}if(window.XMLHttpRequest&&XMLHttpRequest.prototype&&XMLHttpRequest.prototype.addEventListener&&!/CriOS/.test(navigator.userAgent)){t("loader").features.xhr=!0;var o=t("handle"),i=t(2),a=t("ee"),s=["load","error","abort","timeout"],c=s.length,f=t(1);t(4),t(3),a.on("new-xhr",function(){this.totalCbs=0,this.called=0,this.cbTime=0,this.end=n,this.ended=!1,this.xhrGuids={}}),a.on("open-xhr-start",function(t){this.params={method:t[0]},r(this,t[1]),this.metrics={}}),a.on("open-xhr-end",function(t,e){"loader_config"in NREUM&&"xpid"in NREUM.loader_config&&this.sameOrigin&&e.setRequestHeader("X-NewRelic-ID",NREUM.loader_config.xpid)}),a.on("send-xhr-start",function(t,n){var r=this.metrics,o=t[0],i=this;if(r&&o){var f=e(o);f&&(r.txSize=f)}this.startTime=(new Date).getTime(),this.listener=function(t){try{"abort"===t.type&&(i.params.aborted=!0),("load"!==t.type||i.called===i.totalCbs&&(i.onloadCalled||"function"!=typeof n.onload))&&i.end(n)}catch(e){try{a.emit("internal-error",[e])}catch(r){}}};for(var u=0;c>u;u++)n.addEventListener(s[u],this.listener,!1)}),a.on("xhr-cb-time",function(t,e,n){this.cbTime+=t,e?this.onloadCalled=!0:this.called+=1,this.called!==this.totalCbs||!this.onloadCalled&&"function"==typeof n.onload||this.end(n)}),a.on("xhr-load-added",function(t,e){var n=""+f(t)+!!e;this.xhrGuids&&!this.xhrGuids[n]&&(this.xhrGuids[n]=!0,this.totalCbs+=1)}),a.on("xhr-load-removed",function(t,e){var n=""+f(t)+!!e;this.xhrGuids&&this.xhrGuids[n]&&(delete this.xhrGuids[n],this.totalCbs-=1)}),a.on("addEventListener-end",function(t,e){e instanceof XMLHttpRequest&&"load"===t[0]&&a.emit("xhr-load-added",[t[1],t[2]],e)}),a.on("removeEventListener-end",function(t,e){e instanceof XMLHttpRequest&&"load"===t[0]&&a.emit("xhr-load-removed",[t[1],t[2]],e)}),a.on("fn-start",function(t,e,n){e instanceof XMLHttpRequest&&("onload"===n&&(this.onload=!0),("load"===(t[0]&&t[0].type)||this.onload)&&(this.xhrCbStart=(new Date).getTime()))}),a.on("fn-end",function(t,e){this.xhrCbStart&&a.emit("xhr-cb-time",[(new Date).getTime()-this.xhrCbStart,this.onload,e],e)})}},{1:"XL7HBI",2:11,3:9,4:5,ee:"QJf3ax",handle:"D5DuLP",loader:"G9z0Bl"}],11:[function(t,e){e.exports=function(t){var e=document.createElement("a"),n=window.location,r={};e.href=t,r.port=e.port;var o=e.href.split("://");return!r.port&&o[1]&&(r.port=o[1].split("/")[0].split("@").pop().split(":")[1]),r.port&&"0"!==r.port||(r.port="https"===o[0]?"443":"80"),r.hostname=e.hostname||n.hostname,r.pathname=e.pathname,r.protocol=o[0],"/"!==r.pathname.charAt(0)&&(r.pathname="/"+r.pathname),r.sameOrigin=!e.hostname||e.hostname===document.domain&&e.port===n.port&&e.protocol===n.protocol,r}},{}],gos:[function(t,e){e.exports=t("7eSDFh")},{}],"7eSDFh":[function(t,e){function n(t,e,n){if(r.call(t,e))return t[e];var o=n();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(t,e,{value:o,writable:!0,enumerable:!1}),o}catch(i){}return t[e]=o,o}var r=Object.prototype.hasOwnProperty;e.exports=n},{}],D5DuLP:[function(t,e){function n(t,e,n){return r.listeners(t).length?r.emit(t,e,n):(o[t]||(o[t]=[]),void o[t].push(e))}var r=t("ee").create(),o={};e.exports=n,n.ee=r,r.q=o},{ee:"QJf3ax"}],handle:[function(t,e){e.exports=t("D5DuLP")},{}],XL7HBI:[function(t,e){function n(t){var e=typeof t;return!t||"object"!==e&&"function"!==e?-1:t===window?0:i(t,o,function(){return r++})}var r=1,o="nr@id",i=t("gos");e.exports=n},{gos:"7eSDFh"}],id:[function(t,e){e.exports=t("XL7HBI")},{}],loader:[function(t,e){e.exports=t("G9z0Bl")},{}],G9z0Bl:[function(t,e){function n(){var t=l.info=NREUM.info;if(t&&t.licenseKey&&t.applicationID&&f&&f.body){s(h,function(e,n){e in t||(t[e]=n)}),l.proto="https"===p.split(":")[0]||t.sslForHttp?"https://":"http://",a("mark",["onload",i()]);var e=f.createElement("script");e.src=l.proto+t.agent,f.body.appendChild(e)}}function r(){"complete"===f.readyState&&o()}function o(){a("mark",["domContent",i()])}function i(){return(new Date).getTime()}var a=t("handle"),s=t(1),c=window,f=c.document,u="addEventListener",d="attachEvent",p=(""+location).split("?")[0],h={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",agent:"js-agent.newrelic.com/nr-515.min.js"},l=e.exports={offset:i(),origin:p,features:{}};f[u]?(f[u]("DOMContentLoaded",o,!1),c[u]("load",n,!1)):(f[d]("onreadystatechange",r),c[d]("onload",n)),a("mark",["firstbyte",i()])},{1:20,handle:"D5DuLP"}],20:[function(t,e){function n(t,e){var n=[],o="",i=0;for(o in t)r.call(t,o)&&(n[i]=e(o,t[o]),i+=1);return n}var r=Object.prototype.hasOwnProperty;e.exports=n},{}],21:[function(t,e){function n(t,e,n){e||(e=0),"undefined"==typeof n&&(n=t?t.length:0);for(var r=-1,o=n-e||0,i=Array(0>o?0:o);++r Date: Fri, 14 Aug 2015 20:58:57 +0200 Subject: [PATCH 08/10] use only client vars on index.jade --- website/views/index.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views/index.jade b/website/views/index.jade index c5c2ba0a90..a314059877 100644 --- a/website/views/index.jade +++ b/website/views/index.jade @@ -20,7 +20,7 @@ html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":a script(type="text/javascript", src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5016f6cc44ad68a4", async="async") script(type='text/javascript'). - window.env = !{JSON.stringify(env)}; + window.env = !{JSON.stringify(env._.pick(env, env.clientVars))}; != env.getManifestFiles("app") From 2e1b0467016695fe8d2f3c49032ec9075fe8db80 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 21:05:04 +0200 Subject: [PATCH 09/10] add TODO comments, send mods to client as they are used there --- website/src/middlewares/locals.js | 2 +- website/views/avatar-static.jade | 1 + website/views/options/social/tavern.jade | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index b820e9e303..f846f2776d 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -14,7 +14,7 @@ var mods = require('../models/user').mods; var clientVars = ['language', 'isStaticPage', 'avalaibleLanguages', 'translations', 'FACEBOOK_KEY', 'NODE_ENV', 'BASE_URL', 'GA_ID', 'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY', - 'worldDmg', 'IS_MOBILE']; + 'worldDmg', 'mods', 'IS_MOBILE']; var env = { getManifestFiles: buildManifest.getManifestFiles, diff --git a/website/views/avatar-static.jade b/website/views/avatar-static.jade index 79cab4c963..9a3532f726 100644 --- a/website/views/avatar-static.jade +++ b/website/views/avatar-static.jade @@ -10,6 +10,7 @@ html(ng-app="habitrpg") // .slice(0).push('user') is to clone the array, // to be surethat `user` is never avalaible to other requests' env + // TODO does it need only `user` in clientVars, not the others? - clientVars = env.clientVars.slice(0); clientVars.push('user'); diff --git a/website/views/options/social/tavern.jade b/website/views/options/social/tavern.jade index 19da409204..30974567c2 100644 --- a/website/views/options/social/tavern.jade +++ b/website/views/options/social/tavern.jade @@ -144,6 +144,7 @@ include ./chat-box .alert.alert-info.alert-sm != ' ' + env.t('tavernAlert1') + ' ' + env.t('tavernAlert2') + '.
' + env.t('moderatorIntro1') + //- FIXME this could be rendered server-side? span(ng-repeat='mod in env.mods') |    span(ng-if='::mod.contributor.admin',popover=env.t('gamemaster'),popover-trigger='mouseenter',popover-placement='right') From b31966b1ee9fbb47f96c6978364db83c50ce03f4 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 22:02:19 +0200 Subject: [PATCH 10/10] use assign in place of merge, make sure references to tavern and mods are not lost --- website/src/middlewares/locals.js | 2 +- website/src/models/group.js | 3 ++- website/src/models/user.js | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index f846f2776d..3f4de311b5 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -43,7 +43,7 @@ module.exports = function(req, res, next) { // Load moment.js language file only when not on static pages language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined); - res.locals.habitrpg = _.merge(env, { + res.locals.habitrpg = _.assign(env, { IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), language: language, isStaticPage: isStaticPage, diff --git a/website/src/models/group.js b/website/src/models/group.js index 6159b4de6e..cd669b5efd 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -236,7 +236,8 @@ module.exports.tavern = {}; var tavernQ = {_id:'habitrpg','quest.key':{$ne:null}}; process.nextTick(function(){ mongoose.model('Group').findOne(tavernQ,function(err,tavern){ - module.exports.tavern = tavern; + // Using _assign so we don't lose the reference to the exported tavern + _.assign(module.exports.tavern, tavern); }); }) GroupSchema.statics.tavernBoss = function(user,progress) { diff --git a/website/src/models/user.js b/website/src/models/user.js index 2f8da5a0ee..fc52a48f3b 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -580,12 +580,13 @@ module.exports.model = mongoose.model("User", UserSchema); // Initially export an empty object so external requires will get // the right object by reference when it's defined later // Otherwise it would remain undefined if requested before the query executes -module.exports.mods = {}; +module.exports.mods = []; mongoose.model("User") .find({'contributor.admin':true}) .sort('-contributor.level -backer.npc profile.name') .select('profile contributor backer') .exec(function(err,mods){ - module.exports.mods = mods + // Using push to maintain the reference to mods + module.exports.mods.push.apply(module.exports.mods, mods); });