From 89a351a0d156950071cc144a125f390f2ec038cd Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Thu, 6 Aug 2015 08:58:58 -0500 Subject: [PATCH 01/56] Add check for if string exists --- test/transifex/malformedStrings.test.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/transifex/malformedStrings.test.js b/test/transifex/malformedStrings.test.js index cd751cd752..11a41c88a9 100644 --- a/test/transifex/malformedStrings.test.js +++ b/test/transifex/malformedStrings.test.js @@ -29,10 +29,16 @@ _(languages).each(function(lang) { var englishString = parsedEnglishFile[key]; var translationString = parsedTranslationFile[key]; + it(key + ' exists in ' + file + ' for the ' + lang + ' language', function() { + expect(translationString).to.exist; + }); + + if(!translationString) return; + var EnglishOccurences = englishString.match(interpolationRegex); var TranslationOccurences = translationString.match(interpolationRegex); - xit(key + ' - contains an interpolation', function() { + it(key + ' - contains an interpolation', function() { if(!TranslationOccurences) console.log("English String:", englishString); expect(EnglishOccurences).to.exist; @@ -40,7 +46,7 @@ _(languages).each(function(lang) { }); if(EnglishOccurences.length > 1) { - it(key + ' - has the correct number of interpolations', function() { + xit(key + ' - has the correct number of interpolations', function() { if(!TranslationOccurences) console.log("English String:", englishString); var numberOfOccurences = TranslationOccurences && TranslationOccurences.length; expect(numberOfOccurences).to.eql(EnglishOccurences.length); From fd76baa6f8411c4b76d6392d771baf124df755ff Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Thu, 6 Aug 2015 22:42:24 -0500 Subject: [PATCH 02/56] Missing strings task --- tasks/gulp-transifex-test.js | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tasks/gulp-transifex-test.js diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js new file mode 100644 index 0000000000..dc53284648 --- /dev/null +++ b/tasks/gulp-transifex-test.js @@ -0,0 +1,96 @@ +import fs from 'fs'; +import _ from 'lodash'; +import nconf from 'nconf'; +import gulp from 'gulp'; +import request from 'superagent'; + +nconf.argv().env().file({ file: 'config.json' }); + +const LOCALES = './common/locales/'; +const ENGLISH_LOCALE = `${LOCALES}en/`; + +const SLACK_URL = nconf.get('TRANSIFEX_SLACK:url'); +const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); +const SLACK_USERNAME = 'Transifex'; +const SLACK_EMOJI = ':transifex:'; + +gulp.task('transifex:exists', () => { + + var missingStrings = []; + + eachTranslationString((language, key, englishString, translationString) => { + if(!translationString) { + let errorString = `${language} - ${key} - ${englishString}`; + missingStrings.push(errorString); + } + }); + + if (!_.isEmpty(missingStrings)) { + post('The following strings are missing', missingStrings); + } +}); + +function eachTranslationFile(cb) { + let languages = fs.readdirSync(LOCALES); + languages.shift(); // Remove README.md from array of languages + + let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE)); + + _(languages).each((lang) => { + _.each(jsonFiles, (file) => { + let translationFile = fs.readFileSync(LOCALES + lang + '/' + file); + let parsedTranslationFile = JSON.parse(translationFile); + + let englishFile = fs.readFileSync(ENGLISH_LOCALE + file); + let parsedEnglishFile = JSON.parse(englishFile); + + cb(lang, parsedEnglishFile, parsedTranslationFile) + }); + }); +} + +function eachTranslationString(cb) { + eachTranslationFile((language, englishJSON, translationJSON) => { + _.each(englishJSON, (string, key) => { + var translationString = translationJSON[key]; + cb(language, key, string, translationString); + }); + }); +} + +function checkForIssues(thingToCheck) { + let hasIssues = !_.isEmpty(thingToCheck); + return hasIssues; +} + +function post(message, items) { + let formattedMessage = formatMessageForPosting(message, items); + + request.post(SLACK_URL) + .send({ + channel: SLACK_CHANNEL, + username: SLACK_USERNAME, + text: formattedMessage, + icon_emoji: SLACK_EMOJI + }) + .end((err, res) => { + if (err) console.error('Unable to post to slack', err); + }); +} + +function formatMessageForPosting(msg, items) { + let body = `*Warning:* ${msg}`; + body += '\n\n```\n'; + body += items.join('\n'); + body += '\n```'; + + return body; +} + +function stripOutNonJsonFiles(collection) { + let onlyJson = _.filter(collection, (file) => { + return file.match(/[a-zA-Z]*\.json/); + }); + + return onlyJson; +} From 563072712baf60d426dd8301dd68be69721564d0 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 7 Aug 2015 09:00:17 -0500 Subject: [PATCH 03/56] Refactor untranslated strings task --- tasks/gulp-transifex-test.js | 44 +++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index dc53284648..f2dfd406bc 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -14,46 +14,64 @@ const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; -gulp.task('transifex:exists', () => { +gulp.task('transifex:untranslatedStrings', () => { - var missingStrings = []; + let missingStrings = []; + let languages = getArrayOfLanguages(); - eachTranslationString((language, key, englishString, translationString) => { + eachTranslationString(languages, (language, filename, key, englishString, translationString) => { if(!translationString) { - let errorString = `${language} - ${key} - ${englishString}`; + let errorString = `${language} - ${filename} - ${key} - ${englishString}`; missingStrings.push(errorString); } }); if (!_.isEmpty(missingStrings)) { - post('The following strings are missing', missingStrings); + let message = 'The following strings are not translated'; + let formattedMessage = formatMessageForPosting(message, missingStrings); + console.log(formattedMessage); } }); -function eachTranslationFile(cb) { +function getArrayOfLanguages() { let languages = fs.readdirSync(LOCALES); languages.shift(); // Remove README.md from array of languages + return languages; +} + +function getEnglishLanguages(cb) { + let allLanguages = getArrayOfLanguages(); + + let nonEnglishLanguages = _.filter(allLanguages, (lang) => { + return lang.indexOf('en') !== 0; + }); + + return nonEnglishLanguages; +} + + +function eachTranslationFile(languages, cb) { let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE)); _(languages).each((lang) => { - _.each(jsonFiles, (file) => { - let translationFile = fs.readFileSync(LOCALES + lang + '/' + file); + _.each(jsonFiles, (filename) => { + let translationFile = fs.readFileSync(LOCALES + lang + '/' + filename); let parsedTranslationFile = JSON.parse(translationFile); - let englishFile = fs.readFileSync(ENGLISH_LOCALE + file); + let englishFile = fs.readFileSync(ENGLISH_LOCALE + filename); let parsedEnglishFile = JSON.parse(englishFile); - cb(lang, parsedEnglishFile, parsedTranslationFile) + cb(lang, filename, parsedEnglishFile, parsedTranslationFile) }); }); } -function eachTranslationString(cb) { - eachTranslationFile((language, englishJSON, translationJSON) => { +function eachTranslationString(languages, cb) { + eachTranslationFile(languages, (language, filename, englishJSON, translationJSON) => { _.each(englishJSON, (string, key) => { var translationString = translationJSON[key]; - cb(language, key, string, translationString); + cb(language, filename, key, string, translationString); }); }); } From 894611bc34a5398d92cc7365dda72372b88a9f45 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 7 Aug 2015 09:34:18 -0500 Subject: [PATCH 04/56] Create shell of task for looking up strings --- package.json | 1 + tasks/gulp-transifex-test.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/package.json b/package.json index b387c0f638..5f0b9ef6c8 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "karma-requirejs": "~0.2.0", "karma-script-launcher": "~0.1.0", "lcov-result-merger": "^1.0.2", + "md5": "^2.0.0", "mocha": "~1.12.1", "mongoskin": "~0.6.1", "phantomjssmith": "~0.5.4", diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index f2dfd406bc..c50562bfc2 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -1,6 +1,7 @@ import fs from 'fs'; import _ from 'lodash'; import nconf from 'nconf'; +import md5 from 'md5'; import gulp from 'gulp'; import request from 'superagent'; @@ -14,6 +15,16 @@ const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; +gulp.task('transifex:look', () => { + // curl -i -L --user username:password -X GET https://www.transifex.com/api/2/project/transifex/resource/core/translation/pt_BR/string/e9fbd679f07d178744bfa80344080962/ + // /project//resource//translation//string// + // request.get('https://www.transifex.com/api/2/project/habitrpg/resource/petsjson/translation/uk/string/7541ebdf41af9839f458f9afb1644882/') + // .end((err, res) => { + // if (err) console.log(":(", err); + // else console.log(res.body); + // }); +}); + gulp.task('transifex:untranslatedStrings', () => { let missingStrings = []; @@ -105,6 +116,11 @@ function formatMessageForPosting(msg, items) { return body; } +function getHash(string) { + let hash = md5(`${string}:`); + return hash; +} + function stripOutNonJsonFiles(collection) { let onlyJson = _.filter(collection, (file) => { return file.match(/[a-zA-Z]*\.json/); From 7ca785f33e75fb22b23aa9c9c21f76016da4eb64 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 7 Aug 2015 19:28:21 -0500 Subject: [PATCH 05/56] Remove unused callback --- tasks/gulp-transifex-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index c50562bfc2..559d48cdaa 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -51,7 +51,7 @@ function getArrayOfLanguages() { return languages; } -function getEnglishLanguages(cb) { +function getEnglishLanguages() { let allLanguages = getArrayOfLanguages(); let nonEnglishLanguages = _.filter(allLanguages, (lang) => { From f355e8e3af77845f0abaf3e6b55a1f994ffff611 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 7 Aug 2015 22:59:55 -0500 Subject: [PATCH 06/56] Wrote task that can look up english strings --- tasks/gulp-transifex-test.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 559d48cdaa..9fff15ae69 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -16,13 +16,18 @@ const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; gulp.task('transifex:look', () => { - // curl -i -L --user username:password -X GET https://www.transifex.com/api/2/project/transifex/resource/core/translation/pt_BR/string/e9fbd679f07d178744bfa80344080962/ - // /project//resource//translation//string// - // request.get('https://www.transifex.com/api/2/project/habitrpg/resource/petsjson/translation/uk/string/7541ebdf41af9839f458f9afb1644882/') - // .end((err, res) => { - // if (err) console.log(":(", err); - // else console.log(res.body); - // }); + + let equivalentStrings = []; + let nonEnglishLanguages = getNonEnglishLanguages(); + + eachTranslationString(nonEnglishLanguages, (language, filename, key, englishString, translationString) => { + if (englishString === translationString) { + let hash = getHash(key); + let json = filename.replace('.',''); + let url = `https://www.transifex.com/api/2/project/habitrpg/resource/${json}/translation/${language}/string/${hash}/` + console.log(url); + } + }); }); gulp.task('transifex:untranslatedStrings', () => { @@ -31,7 +36,7 @@ gulp.task('transifex:untranslatedStrings', () => { let languages = getArrayOfLanguages(); eachTranslationString(languages, (language, filename, key, englishString, translationString) => { - if(!translationString) { + if (!translationString) { let errorString = `${language} - ${filename} - ${key} - ${englishString}`; missingStrings.push(errorString); } @@ -51,7 +56,7 @@ function getArrayOfLanguages() { return languages; } -function getEnglishLanguages() { +function getNonEnglishLanguages() { let allLanguages = getArrayOfLanguages(); let nonEnglishLanguages = _.filter(allLanguages, (lang) => { From 9d3c40122ad193a03c3c1f875575e92c1788b51b Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 8 Aug 2015 22:24:52 -0500 Subject: [PATCH 07/56] REmove unsued task --- tasks/gulp-transifex-test.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 9fff15ae69..ab93e89468 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -15,21 +15,6 @@ const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; -gulp.task('transifex:look', () => { - - let equivalentStrings = []; - let nonEnglishLanguages = getNonEnglishLanguages(); - - eachTranslationString(nonEnglishLanguages, (language, filename, key, englishString, translationString) => { - if (englishString === translationString) { - let hash = getHash(key); - let json = filename.replace('.',''); - let url = `https://www.transifex.com/api/2/project/habitrpg/resource/${json}/translation/${language}/string/${hash}/` - console.log(url); - } - }); -}); - gulp.task('transifex:untranslatedStrings', () => { let missingStrings = []; From f58c9e2192e735919007609e1440374ce96c6cdc Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 8 Aug 2015 22:25:02 -0500 Subject: [PATCH 08/56] Rename task --- tasks/gulp-transifex-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index ab93e89468..c6e1e820e7 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -15,7 +15,7 @@ const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; -gulp.task('transifex:untranslatedStrings', () => { +gulp.task('transifex:missingStrings', () => { let missingStrings = []; let languages = getArrayOfLanguages(); From 092ba23ae4a4136396cf83157d158f8a5e246953 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 8 Aug 2015 22:46:51 -0500 Subject: [PATCH 09/56] Adjust each file to handle errors --- tasks/gulp-transifex-test.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index c6e1e820e7..ef91ecf3c1 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -57,19 +57,24 @@ function eachTranslationFile(languages, cb) { _(languages).each((lang) => { _.each(jsonFiles, (filename) => { - let translationFile = fs.readFileSync(LOCALES + lang + '/' + filename); - let parsedTranslationFile = JSON.parse(translationFile); + try { + var translationFile = fs.readFileSync(LOCALES + lang + '/' + filename); + var parsedTranslationFile = JSON.parse(translationFile); + } catch (err) { + return cb(err); + } let englishFile = fs.readFileSync(ENGLISH_LOCALE + filename); let parsedEnglishFile = JSON.parse(englishFile); - cb(lang, filename, parsedEnglishFile, parsedTranslationFile) + cb(null, lang, filename, parsedEnglishFile, parsedTranslationFile) }); }); } function eachTranslationString(languages, cb) { - eachTranslationFile(languages, (language, filename, englishJSON, translationJSON) => { + eachTranslationFile(languages, (error, language, filename, englishJSON, translationJSON) => { + if (error) return; _.each(englishJSON, (string, key) => { var translationString = translationJSON[key]; cb(language, filename, key, string, translationString); From bfc5ac943583c29790079adcd52e015c3e7b3286 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 8 Aug 2015 22:47:26 -0500 Subject: [PATCH 10/56] Add task to check for missing files --- tasks/gulp-transifex-test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index ef91ecf3c1..2094f06c10 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -15,6 +15,21 @@ const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; +gulp.task('transifex:missingFiles', () => { + let missingStrings = []; + let languages = getArrayOfLanguages(); + eachTranslationFile(languages, (error) => { + if(error) { + missingStrings.push(error.path); + } + }); + + if (!_.isEmpty(missingStrings)) { + let message = 'the following files were missing from the translations folder'; + post(message, missingStrings); + } +}); + gulp.task('transifex:missingStrings', () => { let missingStrings = []; From 8b00a772cf60e38f5179f08b2480baf27852f3eb Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 8 Aug 2015 22:50:18 -0500 Subject: [PATCH 11/56] Remove hash function --- tasks/gulp-transifex-test.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 2094f06c10..517a9b5fd5 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -66,7 +66,6 @@ function getNonEnglishLanguages() { return nonEnglishLanguages; } - function eachTranslationFile(languages, cb) { let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE)); @@ -126,11 +125,6 @@ function formatMessageForPosting(msg, items) { return body; } -function getHash(string) { - let hash = md5(`${string}:`); - return hash; -} - function stripOutNonJsonFiles(collection) { let onlyJson = _.filter(collection, (file) => { return file.match(/[a-zA-Z]*\.json/); From cd15b115ad5f0ee9e34302eecf518d4ff33ffb04 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:13:17 -0500 Subject: [PATCH 12/56] Add constant for all languages array --- tasks/gulp-transifex-test.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 517a9b5fd5..bc280d224b 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -9,6 +9,7 @@ nconf.argv().env().file({ file: 'config.json' }); const LOCALES = './common/locales/'; const ENGLISH_LOCALE = `${LOCALES}en/`; +const ALL_LANGUAGES = getArrayOfLanguages(); const SLACK_URL = nconf.get('TRANSIFEX_SLACK:url'); const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); @@ -17,8 +18,8 @@ const SLACK_EMOJI = ':transifex:'; gulp.task('transifex:missingFiles', () => { let missingStrings = []; - let languages = getArrayOfLanguages(); - eachTranslationFile(languages, (error) => { + + eachTranslationFile(ALL_LANGUAGES, (error) => { if(error) { missingStrings.push(error.path); } @@ -33,9 +34,8 @@ gulp.task('transifex:missingFiles', () => { gulp.task('transifex:missingStrings', () => { let missingStrings = []; - let languages = getArrayOfLanguages(); - eachTranslationString(languages, (language, filename, key, englishString, translationString) => { + eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => { if (!translationString) { let errorString = `${language} - ${filename} - ${key} - ${englishString}`; missingStrings.push(errorString); @@ -57,9 +57,7 @@ function getArrayOfLanguages() { } function getNonEnglishLanguages() { - let allLanguages = getArrayOfLanguages(); - - let nonEnglishLanguages = _.filter(allLanguages, (lang) => { + let nonEnglishLanguages = _.filter(ALL_LANGUAGES, (lang) => { return lang.indexOf('en') !== 0; }); From c1f0fae456222c4ea48b091380fc34ecf04bea2f Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:14:09 -0500 Subject: [PATCH 13/56] Change format of reporting --- tasks/gulp-transifex-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index bc280d224b..8c423fc45a 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -116,9 +116,8 @@ function post(message, items) { function formatMessageForPosting(msg, items) { let body = `*Warning:* ${msg}`; - body += '\n\n```\n'; + body += '\n\n>>>\n'; body += items.join('\n'); - body += '\n```'; return body; } From d0e4590a01c19a33e7a5bae82d510d30132bebb8 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:42:44 -0500 Subject: [PATCH 14/56] Change missingStrings to that it posts to slack --- tasks/gulp-transifex-test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 8c423fc45a..18e4dd94b0 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -37,15 +37,14 @@ gulp.task('transifex:missingStrings', () => { eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => { if (!translationString) { - let errorString = `${language} - ${filename} - ${key} - ${englishString}`; + let errorString = `${language} - ${filename} - ${key} - \`${englishString}\``; missingStrings.push(errorString); } }); if (!_.isEmpty(missingStrings)) { let message = 'The following strings are not translated'; - let formattedMessage = formatMessageForPosting(message, missingStrings); - console.log(formattedMessage); + post(message, missingStrings); } }); From 841532271783a7e645dd7c76f8549f441c5b1d3b Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:43:04 -0500 Subject: [PATCH 15/56] Create malformed string check --- tasks/gulp-transifex-test.js | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 18e4dd94b0..d9f1b6ae5a 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -48,6 +48,51 @@ gulp.task('transifex:missingStrings', () => { } }); +gulp.task('transifex:malformedStrings', () => { + + let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE)); + let interpolationRegex = /<%= [a-zA-Z]* %>/g; + let stringsToLookFor = getStringsWith(jsonFiles, interpolationRegex); + + let stringsWithMalformedInterpolations = []; + let stringsWithIncorrectNumberOfInterpolations = []; + + let count = 0; + _(ALL_LANGUAGES).each(function(lang) { + + _.each(stringsToLookFor, function(strings, file) { + let translationFile = fs.readFileSync(LOCALES + lang + '/' + file); + let parsedTranslationFile = JSON.parse(translationFile); + + _.each(strings, function(value, key) { + let translationString = parsedTranslationFile[key]; + if (!translationString) return; + + let englishOccurences = stringsToLookFor[file][key]; + let translationOccurences = translationString.match(interpolationRegex); + + if (!translationOccurences) { + let malformedString = `${lang} - ${file} - ${key} - \`${translationString}\``; + stringsWithMalformedInterpolations.push(malformedString); + } else if (englishOccurences.length !== translationOccurences.length) { + let missingInterploationString = `${lang} - ${file} - ${key} - \`${translationString}\``; + stringsWithIncorrectNumberOfInterpolations.push(missingInterploationString); + } + }); + }); + }); + + if (!_.isEmpty(stringsWithMalformedInterpolations)) { + let message = '*Warning:* The following strings have malformed interpolations'; + post(message, stringsWithMalformedInterpolations); + } + + if (!_.isEmpty(stringsWithIncorrectNumberOfInterpolations)) { + let message = '*Warning:* The following strings have a different number of string interpolations'; + post(message, stringsWithIncorrectNumberOfInterpolations); + } +}); + function getArrayOfLanguages() { let languages = fs.readdirSync(LOCALES); languages.shift(); // Remove README.md from array of languages @@ -121,6 +166,23 @@ function formatMessageForPosting(msg, items) { return body; } +function getStringsWith(json, interpolationRegex) { + var strings = {}; + + _(json).each(function(file_name) { + var raw_file = fs.readFileSync(ENGLISH_LOCALE + file_name); + var parsed_json = JSON.parse(raw_file); + + strings[file_name] = {}; + _.each(parsed_json, function(value, key) { + var match = value.match(interpolationRegex); + if(match) strings[file_name][key] = match; + }); + }); + + return strings; +} + function stripOutNonJsonFiles(collection) { let onlyJson = _.filter(collection, (file) => { return file.match(/[a-zA-Z]*\.json/); From 6cd3ed3e075c069db902f338558061508755406b Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:44:34 -0500 Subject: [PATCH 16/56] Set default channel --- tasks/gulp-transifex-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index d9f1b6ae5a..d856ed4f25 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -12,7 +12,7 @@ const ENGLISH_LOCALE = `${LOCALES}en/`; const ALL_LANGUAGES = getArrayOfLanguages(); const SLACK_URL = nconf.get('TRANSIFEX_SLACK:url'); -const SLACK_CHANNEL = '#' + nconf.get('TRANSIFEX_SLACK:channel'); +const SLACK_CHANNEL = '#' + (nconf.get('TRANSIFEX_SLACK:channel') || 'general'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; From b35453cd4b470d280b9cc54d86e7939cf08e3f3c Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:52:00 -0500 Subject: [PATCH 17/56] Add transifex config to example config --- config.json.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config.json.example b/config.json.example index a7b1660983..6836f38e74 100644 --- a/config.json.example +++ b/config.json.example @@ -40,6 +40,10 @@ "accessKeyId":"accessKeyId", "secretAccessKey":"secretAccessKey" }, + "transifex_slack": { + "url": "https://hooks.slack.com/services/some-url", + "channel": "general" + }, "PAYPAL":{ "billing_plans": { "basic_earned":"basic_earned", From 1ffad1997eb68146c925b3c8c45e3e6ca39c6141 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 9 Aug 2015 16:52:25 -0500 Subject: [PATCH 18/56] Removed mocha test for translations --- test/transifex/malformedStrings.test.js | 84 ------------------------- 1 file changed, 84 deletions(-) delete mode 100644 test/transifex/malformedStrings.test.js diff --git a/test/transifex/malformedStrings.test.js b/test/transifex/malformedStrings.test.js deleted file mode 100644 index 11a41c88a9..0000000000 --- a/test/transifex/malformedStrings.test.js +++ /dev/null @@ -1,84 +0,0 @@ -var chai = require("chai") -var expect = chai.expect - -var fs = require('fs'); -var _ = require('lodash'); - -var locales = './common/locales/'; -var english = locales + 'en/'; -var interpolationRegex = /<%= [a-zA-Z]* %>/g; - -var languages = fs.readdirSync(locales); -languages.shift(); // Remove README.md from array of languages - -var jsonFiles = stripOutNonJsonFiles(fs.readdirSync(english)); -var stringsToLookFor = stringsWithInterpolations(jsonFiles); - -_(languages).each(function(lang) { - describe('the ' + lang + ' language', function() { - - _.each(stringsToLookFor, function(strings, file) { - context('string in ' + file + ' -', function() { - var translationFile = fs.readFileSync(locales + lang + '/' + file); - var parsedTranslationFile = JSON.parse(translationFile); - - var englishFile = fs.readFileSync(english + file); - var parsedEnglishFile = JSON.parse(englishFile); - - _.each(strings, function(value, key) { - var englishString = parsedEnglishFile[key]; - var translationString = parsedTranslationFile[key]; - - it(key + ' exists in ' + file + ' for the ' + lang + ' language', function() { - expect(translationString).to.exist; - }); - - if(!translationString) return; - - var EnglishOccurences = englishString.match(interpolationRegex); - var TranslationOccurences = translationString.match(interpolationRegex); - - it(key + ' - contains an interpolation', function() { - - if(!TranslationOccurences) console.log("English String:", englishString); - expect(EnglishOccurences).to.exist; - expect(TranslationOccurences).to.exist; - }); - - if(EnglishOccurences.length > 1) { - xit(key + ' - has the correct number of interpolations', function() { - if(!TranslationOccurences) console.log("English String:", englishString); - var numberOfOccurences = TranslationOccurences && TranslationOccurences.length; - expect(numberOfOccurences).to.eql(EnglishOccurences.length); - }); - } - }); - }); - }); - }); -}); - -function stringsWithInterpolations(json) { - var strings = {}; - - _(json).each(function(file_name) { - var raw_file = fs.readFileSync(english + file_name); - var parsed_json = JSON.parse(raw_file); - - strings[file_name] = {}; - _.each(parsed_json, function(value, key) { - var match = value.match(interpolationRegex); - if(match) strings[file_name][key] = true; - }); - }); - - return strings; -} - -function stripOutNonJsonFiles(collection) { - var onlyJson = _.filter(collection, function(file) { - return file.match(/[a-zA-Z]*\.json/); - }); - - return onlyJson; -} From abb19d1d202235cbd24bac6338a9ebf170d6e6fb Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 07:33:14 -0500 Subject: [PATCH 19/56] Correct casing on config example --- config.json.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index 6836f38e74..55adbe801f 100644 --- a/config.json.example +++ b/config.json.example @@ -40,7 +40,7 @@ "accessKeyId":"accessKeyId", "secretAccessKey":"secretAccessKey" }, - "transifex_slack": { + "TRANSIFEX_SLACK": { "url": "https://hooks.slack.com/services/some-url", "channel": "general" }, From c8af280ce4d5b43225d14e057e613302abe12b20 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 07:33:27 -0500 Subject: [PATCH 20/56] Revert formatting back to backticks --- tasks/gulp-transifex-test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index d856ed4f25..157021ee3a 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -37,7 +37,7 @@ gulp.task('transifex:missingStrings', () => { eachTranslationString(ALL_LANGUAGES, (language, filename, key, englishString, translationString) => { if (!translationString) { - let errorString = `${language} - ${filename} - ${key} - \`${englishString}\``; + let errorString = `${language} - ${filename} - ${key} - ${englishString}`; missingStrings.push(errorString); } }); @@ -72,10 +72,10 @@ gulp.task('transifex:malformedStrings', () => { let translationOccurences = translationString.match(interpolationRegex); if (!translationOccurences) { - let malformedString = `${lang} - ${file} - ${key} - \`${translationString}\``; + let malformedString = `${lang} - ${file} - ${key} - ${translationString}`; stringsWithMalformedInterpolations.push(malformedString); } else if (englishOccurences.length !== translationOccurences.length) { - let missingInterploationString = `${lang} - ${file} - ${key} - \`${translationString}\``; + let missingInterploationString = `${lang} - ${file} - ${key} - ${translationString}`; stringsWithIncorrectNumberOfInterpolations.push(missingInterploationString); } }); @@ -160,8 +160,9 @@ function post(message, items) { function formatMessageForPosting(msg, items) { let body = `*Warning:* ${msg}`; - body += '\n\n>>>\n'; + body += '\n\n```\n'; body += items.join('\n'); + body += '\n```'; return body; } From cb89f07dcf4b1cfb1c6f0e5221ef5b9a2b006384 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 07:42:52 -0500 Subject: [PATCH 21/56] Add clarification about missing interpolations --- tasks/gulp-transifex-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 157021ee3a..94a5076874 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -83,7 +83,7 @@ gulp.task('transifex:malformedStrings', () => { }); if (!_.isEmpty(stringsWithMalformedInterpolations)) { - let message = '*Warning:* The following strings have malformed interpolations'; + let message = '*Warning:* The following strings have malformed or missing interpolations'; post(message, stringsWithMalformedInterpolations); } From 6ed3e77008f7a50b1bd01ed47673b776898fbe11 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 07:53:26 -0500 Subject: [PATCH 22/56] Remove double warning --- tasks/gulp-transifex-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 94a5076874..24657b7a09 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -83,12 +83,12 @@ gulp.task('transifex:malformedStrings', () => { }); if (!_.isEmpty(stringsWithMalformedInterpolations)) { - let message = '*Warning:* The following strings have malformed or missing interpolations'; + let message = 'The following strings have malformed or missing interpolations'; post(message, stringsWithMalformedInterpolations); } if (!_.isEmpty(stringsWithIncorrectNumberOfInterpolations)) { - let message = '*Warning:* The following strings have a different number of string interpolations'; + let message = 'The following strings have a different number of string interpolations'; post(message, stringsWithIncorrectNumberOfInterpolations); } }); From ee621b526e09bbe25d0bdfe2bbb8fbc5710634ad Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 17:14:46 -0500 Subject: [PATCH 23/56] Remove unused dependency --- package.json | 1 - tasks/gulp-transifex-test.js | 1 - 2 files changed, 2 deletions(-) diff --git a/package.json b/package.json index 5f0b9ef6c8..b387c0f638 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,6 @@ "karma-requirejs": "~0.2.0", "karma-script-launcher": "~0.1.0", "lcov-result-merger": "^1.0.2", - "md5": "^2.0.0", "mocha": "~1.12.1", "mongoskin": "~0.6.1", "phantomjssmith": "~0.5.4", diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 24657b7a09..7d1f8a6f26 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -1,7 +1,6 @@ import fs from 'fs'; import _ from 'lodash'; import nconf from 'nconf'; -import md5 from 'md5'; import gulp from 'gulp'; import request from 'superagent'; From ae2a9f57560c64363a090f356d337cae3879354b Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 17:16:50 -0500 Subject: [PATCH 24/56] remove unused functions --- tasks/gulp-transifex-test.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 7d1f8a6f26..37d4557609 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -99,14 +99,6 @@ function getArrayOfLanguages() { return languages; } -function getNonEnglishLanguages() { - let nonEnglishLanguages = _.filter(ALL_LANGUAGES, (lang) => { - return lang.indexOf('en') !== 0; - }); - - return nonEnglishLanguages; -} - function eachTranslationFile(languages, cb) { let jsonFiles = stripOutNonJsonFiles(fs.readdirSync(ENGLISH_LOCALE)); @@ -137,11 +129,6 @@ function eachTranslationString(languages, cb) { }); } -function checkForIssues(thingToCheck) { - let hasIssues = !_.isEmpty(thingToCheck); - return hasIssues; -} - function post(message, items) { let formattedMessage = formatMessageForPosting(message, items); From c74625a624be21920ef343ad0d4a9257a3faf9f1 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 17:17:27 -0500 Subject: [PATCH 25/56] Add line break for styling consistency --- tasks/gulp-transifex-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 37d4557609..c4e52466ca 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -16,6 +16,7 @@ const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; gulp.task('transifex:missingFiles', () => { + let missingStrings = []; eachTranslationFile(ALL_LANGUAGES, (error) => { From c46659c6228a6f6cd27aa33a7a9cedcba21ab885 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 10 Aug 2015 17:31:43 -0500 Subject: [PATCH 26/56] Add top level transifex task --- tasks/gulp-transifex-test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index c4e52466ca..3c07fab67a 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -15,6 +15,8 @@ const SLACK_CHANNEL = '#' + (nconf.get('TRANSIFEX_SLACK:channel') || 'general'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; +gulp.task('transifex', ['transifex:missingFiles', 'transifex:missingStrings', 'transifex:malformedStrings']); + gulp.task('transifex:missingFiles', () => { let missingStrings = []; From 9d9e99045db801c041aad9fd257565a41dfcb0e6 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Tue, 11 Aug 2015 08:12:03 -0500 Subject: [PATCH 27/56] Add exceptions to not check for malformities --- tasks/gulp-transifex-test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tasks/gulp-transifex-test.js b/tasks/gulp-transifex-test.js index 3c07fab67a..72b51f54d6 100644 --- a/tasks/gulp-transifex-test.js +++ b/tasks/gulp-transifex-test.js @@ -15,6 +15,12 @@ const SLACK_CHANNEL = '#' + (nconf.get('TRANSIFEX_SLACK:channel') || 'general'); const SLACK_USERNAME = 'Transifex'; const SLACK_EMOJI = ':transifex:'; +const malformedStringExceptions = { + messageDropFood: true, + armoireFood: true, + feedPet: true +} + gulp.task('transifex', ['transifex:missingFiles', 'transifex:missingStrings', 'transifex:malformedStrings']); gulp.task('transifex:missingFiles', () => { @@ -76,7 +82,7 @@ gulp.task('transifex:malformedStrings', () => { if (!translationOccurences) { let malformedString = `${lang} - ${file} - ${key} - ${translationString}`; stringsWithMalformedInterpolations.push(malformedString); - } else if (englishOccurences.length !== translationOccurences.length) { + } else if (englishOccurences.length !== translationOccurences.length && !malformedStringExceptions[key]) { let missingInterploationString = `${lang} - ${file} - ${key} - ${translationString}`; stringsWithIncorrectNumberOfInterpolations.push(missingInterploationString); } From bcf7c9712e7083aaccde2abb603a63ce48fd5f79 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Wed, 12 Aug 2015 18:53:49 -0500 Subject: [PATCH 28/56] Split out potion and armoire out of the itemStore object Fixes #5743 --- common/script/index.coffee | 2 -- test/spec/controllers/tasksCtrlSpec.js | 16 +++++++++++--- website/public/js/controllers/tasksCtrl.js | 9 +++++--- .../tasks/task_view/static_rewards.jade | 22 +++++++++++-------- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/common/script/index.coffee b/common/script/index.coffee index 27b44392f1..eded441aef 100644 --- a/common/script/index.coffee +++ b/common/script/index.coffee @@ -202,8 +202,6 @@ api.updateStore = (user) -> # Add special items (contrib gear, backer gear, etc) changes = changes.concat _.filter content.gear.flat, (v) -> v.klass in ['special','mystery','armoire'] and !user.items.gear.owned[v.key] and v.canOwn?(user) - changes.push content.potion - if user.flags.armoireEnabled then changes.push content.armoire # Return sorted store (array) _.sortBy changes, (c)->sortOrder[c.type] diff --git a/test/spec/controllers/tasksCtrlSpec.js b/test/spec/controllers/tasksCtrlSpec.js index 0b5ebd2cc2..28ffa79f0b 100644 --- a/test/spec/controllers/tasksCtrlSpec.js +++ b/test/spec/controllers/tasksCtrlSpec.js @@ -1,7 +1,7 @@ 'use strict'; describe('Tasks Controller', function() { - var $rootScope, scope, user, ctrl; + var $rootScope, shared, scope, user, ctrl; beforeEach(function() { user = specHelper.newUser(); @@ -10,10 +10,10 @@ describe('Tasks Controller', function() { $provide.value('Guide', {}); }); - inject(function($rootScope, $controller){ + inject(function($rootScope, $controller, Shared){ scope = $rootScope.$new(); - + shared = Shared; $controller('RootCtrl', {$scope: scope, User: {user: user}}); ctrl = $controller('TasksCtrl', {$scope: scope, User: {user: user}}); @@ -28,4 +28,14 @@ describe('Tasks Controller', function() { }); }); }); + + describe('watch to updateStore', function() { + it('updates itemStore when user gear changes', function() { + sinon.stub(shared, 'updateStore').returns({item: true}); + user.items.gear.owned.foo = true; + + scope.$digest(); + expect(scope.itemStore).to.eql({item: true}); + }); + }); }); diff --git a/website/public/js/controllers/tasksCtrl.js b/website/public/js/controllers/tasksCtrl.js index 6fecc56f57..7eee145e37 100644 --- a/website/public/js/controllers/tasksCtrl.js +++ b/website/public/js/controllers/tasksCtrl.js @@ -1,7 +1,7 @@ "use strict"; -habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrl', '$timeout', 'Shared', 'Guide', 'Tasks', 'Analytics', - function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared, Guide, Tasks, Analytics) { +habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrl', '$timeout', 'Content', 'Shared', 'Guide', 'Tasks', 'Analytics', + function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Content, Shared, Guide, Tasks, Analytics) { $scope.obj = User.user; // used for task-lists $scope.user = User.user; @@ -212,10 +212,13 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N ------------------------ */ - $scope.$watchGroup(['user.items.gear.owned', 'user.flags.armoireEnabled'], function(){ + $scope.$watch('user.items.gear.owned', function(){ $scope.itemStore = Shared.updateStore(User.user); },true); + $scope.healthPotion = Content.potion; + $scope.armoire = Content.armoire; + $scope.buy = function(item) { User.user.ops.buy({params:{key:item.key}}); $rootScope.playSound('Reward'); diff --git a/website/views/shared/tasks/task_view/static_rewards.jade b/website/views/shared/tasks/task_view/static_rewards.jade index eb737be5dd..7fad52176c 100644 --- a/website/views/shared/tasks/task_view/static_rewards.jade +++ b/website/views/shared/tasks/task_view/static_rewards.jade @@ -1,18 +1,22 @@ -ul.items.rewards(ng-if='main && list.type=="reward"') - li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.key == "armoire" && !user.flags.armoireEmpty ? env.t("armoireNotesFull") + armoireCount(user.items.gear.owned) : item.notes()}}') +mixin reward(item) + li.task.reward-item(popover-trigger='mouseenter', popover-placement='top', popover='{{::#{item}.notes()}}')&attributes(attributes) // right-hand side control buttons .task-meta-controls span.task-notes span.glyphicon.glyphicon-comment //left-hand size commands .task-controls.task-primary - input.visuallyhidden( - class="reward", + input.reward.visuallyhidden( type='checkbox', - ui-keypress='{13:"buy(item)"}') - a.money.btn-buy.item-btn(ng-class='{highValue: item.value >= 1000}', ng-click='buy(item)') + ui-keypress='{13:"buy(#{item})"}') + a.money.btn-buy.item-btn(ng-class='::{highValue: #{item}.value >= 1000}', ng-click='::buy(#{item})') span.shop_gold - span.reward-cost {{item.value}} + span.reward-cost {{::#{item}.value}} // main content - span(ng-class='::{"shop_{{item.key}} shop-sprite item-img": true}').reward-img - p.task-text {{item.text()}} + span(ng-class='::{"shop_{{#{item}.key}} shop-sprite item-img": true}').reward-img + p.task-text {{::#{item}.text()}} + +ul.items.rewards(ng-if='main && list.type=="reward"') + +reward('item')(ng-repeat='item in itemStore') + +reward('healthPotion') + +reward('armoire')(ng-if='user.flags.armoireEnabled') From 39ead02d6c0a42335af964cde33577d1c62ac85c Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Wed, 12 Aug 2015 19:09:11 -0500 Subject: [PATCH 29/56] Remove comment --- common/script/index.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/common/script/index.coffee b/common/script/index.coffee index eded441aef..9b908de9ca 100644 --- a/common/script/index.coffee +++ b/common/script/index.coffee @@ -190,7 +190,6 @@ preenHistory = (history) -> Update the in-browser store with new gear. FIXME this was in user.fns, but it was causing strange issues there ### sortOrder = _.reduce content.gearTypes,((m,v,k)->m[v]=k;m), {} -#sortOrder.potion = _.size(sortOrder) #potion goes last #actually, _.sortBy puts anything else last, so this is unecessary api.updateStore = (user) -> return unless user changes= [] From 9a27b2e8cbd60c551026b5992df3838aabbae0d0 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Wed, 12 Aug 2015 21:47:04 -0500 Subject: [PATCH 30/56] Add task numbers to analytics --- test/server_side/analytics.test.js | 14 ++++++++++++-- test/spec/services/analyticsServicesSpec.js | 12 +++++++++++- website/public/js/services/analyticsServices.js | 6 ++++++ website/src/analytics.js | 6 ++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/test/server_side/analytics.test.js b/test/server_side/analytics.test.js index 059414be23..7bdc7c88a1 100644 --- a/test/server_side/analytics.test.js +++ b/test/server_side/analytics.test.js @@ -222,7 +222,11 @@ describe('analytics', function() { stats: stats, contributor: { level: 1 }, purchased: { plan: { planId: 'foo-plan' } }, - flags: {tour: {intro: -2}} + flags: {tour: {intro: -2}}, + habits: [{_id: 'habit'}], + dailys: [{_id: 'daily'}], + todos: [{_id: 'todo'}], + rewards: [{_id: 'reward'}] }; analyticsData.user = user; @@ -248,7 +252,13 @@ describe('analytics', function() { Mana: 30, contributorLevel: 1, subscription: 'foo-plan', - tutorialComplete: true + tutorialComplete: true, + numberOfTasks: { + todos: 1, + dailys: 1, + habits: 1, + rewards: 1 + } } }); }); diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index ca726e37ec..939de37a00 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -221,7 +221,13 @@ describe('Analytics Service', function () { Mana: 41, contributorLevel: 1, subscription: 'unique-plan-id', - tutorialComplete: true + tutorialComplete: true, + numberOfTasks: { + todos: 1, + dailys: 1, + habits: 1, + rewards: 1 + } }; beforeEach(function() { @@ -235,6 +241,10 @@ describe('Analytics Service', function () { user.contributor.level = 1; user.purchased.plan.planId = 'unique-plan-id'; user.flags.tour.intro = -2; + user.habits = [{_id: 'habit'}]; + user.dailys = [{_id: 'daily'}]; + user.todos = [{_id: 'todo'}]; + user.rewards = [{_id: 'reward'}]; analytics.updateUser(); clock.tick(); diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index 135e7a205d..72f5a111f4 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -108,6 +108,12 @@ properties.Mana = Math.floor(user.stats.mp); } properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; + properties.numberOfTasks = { + habits: user.habits.length, + dailys: user.dailys.length, + todos: user.todos.length, + rewards: user.rewards.length + }; if (user.contributor && user.contributor.level) properties.contributorLevel = user.contributor.level; if (user.purchased && user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; } diff --git a/website/src/analytics.js b/website/src/analytics.js index ad35adb9e7..20de935126 100644 --- a/website/src/analytics.js +++ b/website/src/analytics.js @@ -153,6 +153,12 @@ function _formatUserData(user) { } properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; + properties.numberOfTasks = { + habits: user.habits.length, + dailys: user.dailys.length, + todos: user.todos.length, + rewards: user.rewards.length + }; if (user.contributor && user.contributor.level) { properties.contributorLevel = user.contributor.level; From ceec310e5fc37f4a536c1b5972b38b1029049bff Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Wed, 12 Aug 2015 22:16:30 -0500 Subject: [PATCH 31/56] Use human readable name --- test/server_side/analytics.test.js | 2 +- test/spec/services/analyticsServicesSpec.js | 2 +- website/public/js/services/analyticsServices.js | 2 +- website/src/analytics.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/server_side/analytics.test.js b/test/server_side/analytics.test.js index 7bdc7c88a1..96caeca914 100644 --- a/test/server_side/analytics.test.js +++ b/test/server_side/analytics.test.js @@ -253,7 +253,7 @@ describe('analytics', function() { contributorLevel: 1, subscription: 'foo-plan', tutorialComplete: true, - numberOfTasks: { + "Number Of Tasks": { todos: 1, dailys: 1, habits: 1, diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index 939de37a00..1c7de0034b 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -222,7 +222,7 @@ describe('Analytics Service', function () { contributorLevel: 1, subscription: 'unique-plan-id', tutorialComplete: true, - numberOfTasks: { + "Number Of Tasks": { todos: 1, dailys: 1, habits: 1, diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index 72f5a111f4..a37c94e1f9 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -108,7 +108,7 @@ properties.Mana = Math.floor(user.stats.mp); } properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; - properties.numberOfTasks = { + properties["Number Of Tasks"] = { habits: user.habits.length, dailys: user.dailys.length, todos: user.todos.length, diff --git a/website/src/analytics.js b/website/src/analytics.js index 20de935126..0d56059704 100644 --- a/website/src/analytics.js +++ b/website/src/analytics.js @@ -153,7 +153,7 @@ function _formatUserData(user) { } properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; - properties.numberOfTasks = { + properties["Number Of Tasks"] = { habits: user.habits.length, dailys: user.dailys.length, todos: user.todos.length, From 3f941c3534fdc29eaf58aa80d4ef3f922d6d044c Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Wed, 12 Aug 2015 22:37:52 -0500 Subject: [PATCH 32/56] chore(i18n): update locales --- common/locales/cs/tasks.json | 2 +- common/locales/da/tasks.json | 2 +- common/locales/de/front.json | 10 +++++----- common/locales/de/settings.json | 6 +++--- common/locales/de/tasks.json | 2 +- common/locales/en@pirate/limited.json | 10 +++++----- common/locales/en@pirate/tasks.json | 2 +- common/locales/en_GB/tasks.json | 2 +- common/locales/es/tasks.json | 2 +- common/locales/es_419/tasks.json | 2 +- common/locales/fr/front.json | 4 ++-- common/locales/fr/tasks.json | 2 +- common/locales/he/tasks.json | 2 +- common/locales/hu/tasks.json | 2 +- common/locales/it/tasks.json | 2 +- common/locales/ja/tasks.json | 2 +- common/locales/nl/limited.json | 8 ++++---- common/locales/nl/tasks.json | 2 +- common/locales/pl/tasks.json | 2 +- common/locales/pt/tasks.json | 2 +- common/locales/ro/tasks.json | 2 +- common/locales/ru/gear.json | 2 +- common/locales/ru/limited.json | 2 +- common/locales/ru/settings.json | 4 ++-- common/locales/ru/tasks.json | 2 +- common/locales/sk/tasks.json | 2 +- common/locales/sr/tasks.json | 2 +- common/locales/sv/tasks.json | 2 +- common/locales/uk/tasks.json | 2 +- common/locales/zh/tasks.json | 2 +- common/locales/zh_TW/tasks.json | 2 +- 31 files changed, 46 insertions(+), 46 deletions(-) diff --git a/common/locales/cs/tasks.json b/common/locales/cs/tasks.json index 512c5e23da..d61fb9fe44 100644 --- a/common/locales/cs/tasks.json +++ b/common/locales/cs/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Posilňující lektvar", "fortifyPop": "Obnoví všechny úkoly do neutrální (žluté) barvy a obnoví ztracené zdraví.", "fortify": "Posilnění", - "fortifyText": "Posilnění vrátí všechny tvé úkoly do neutrálního (žlutého) stavu, ve kterém byly v okamžitku přidání, a doplní zdraví na maximum. Považuj to za poslední možnou variantu. Červené úkoly poskytují dobrou motivaci ke zlepšení. Ale pokud tě všechna ta červená naplňuje zoufalstvím a začátek každého dne se ukáže jako smrtící, investuj drahokamy a oddechni si.", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Určitě chceš odstranit tento úkol?", "streakCoins": "Bonus za šňůru!", "pushTaskToTop": "Přesunout úkol na vrchol", diff --git a/common/locales/da/tasks.json b/common/locales/da/tasks.json index ae8463cf58..53fd80e8b9 100644 --- a/common/locales/da/tasks.json +++ b/common/locales/da/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Forstærkningseliksir", "fortifyPop": "Returnerer alle opgaver til neutral værdi (gul farve) og giver alt tabt helbred tilbage.", "fortify": "Forstærk", - "fortifyText": "Forstærk vil returnere alle dine opgaver til en neutral (gul) værdi, som om du lige har tilføjet dem, og give dig fuldt Helbred tilbage. Tænk på dette som en sidste mulighed! Røde opgaver tilskynder dig til at forbedre dig. Men hvis al den røde farve gør dig trist, og en ny dag er dødbringende, brug ædelstenene og bliv benådet!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Er du sikker på, at du vil slette denne opgave?", "streakCoins": "Stribebonus!", "pushTaskToTop": "Flyt opgave til toppen", diff --git a/common/locales/de/front.json b/common/locales/de/front.json index 4d2ccf67dc..fd80be160c 100644 --- a/common/locales/de/front.json +++ b/common/locales/de/front.json @@ -2,7 +2,7 @@ "FAQ": "FAQ", "accept1Terms": "Durch Klicken auf diesen Knopf, stimme ich den", "accept2Terms": "zu, sowie der", - "alexandraQuote": "Couldn't NOT talk about [Habitica] during my speech in Madrid. Must-have tool for freelancers who still need a boss.", + "alexandraQuote": "Ich konnte während meiner Rede in Madrid nicht NICHT über [Habitica] reden. Ein absolutes Must-have Hilfsmittel für Freiberufler, die trotzdem einen Chef brauchen.", "althaireQuote": "Kontinuierlich eine Quest zu haben, motiviert mich dazu alle meine täglichen und einmaligen Aufgaben zu erledigen. Meine größte Motivation ist, meine Gruppe nicht im Stich zu lassen.", "andeeliaoQuote": "Großartiges Produkt, ich habe gerade erst vor einigen Tagen angefangen und gehe jetzt schon bewusster und produktiver mit meiner Zeit um!", "autumnesquirrelQuote": "Ich schiebe bei der Arbeit und im Haushalt weniger auf und zahle meine Rechnungen rechtzeitig. ", @@ -38,7 +38,7 @@ "elmiQuote": "Jeden Morgen freue ich mich aufzustehen und etwas Gold zu verdienen!", "email": "E-Mail", "emailNewPass": "E-Mail neues Passwort", - "evagantzQuote": "My very first dentist appointment where the hygienist was actually excited about my flossing habits. Thanks [Habitica]!", + "evagantzQuote": "Mein erster Zahnarztbesuch, bei dem die Assistentin tatsächlich begeistert über meine Zahnseide-Gewohnheiten war. Danke [Habitica]!", "examplesHeading": "Spieler benutzen Habitica, um folgendes zu organisieren...", "featureAchievementByline": "Etwas total großartiges gemacht? Erhalte ein Abzeichen und prahle damit!", "featureAchievementHeading": "Erfolgsabzeichen", @@ -55,7 +55,7 @@ "footerMobile": "Mobil", "footerSocial": "Soziales", "forgotPass": "Passwort vergessen", - "frabjabulousQuote": "[Habitica] is the reason I got a killer, high-paying job... and even more miraculous, I'm now a daily flosser!", + "frabjabulousQuote": "[Habitica] ist der Grund, warum ich einen tollen, gut bezahlten Job gefunden habe... und noch erstaunlicher ist, dass ich jetzt täglich Zahnseide benutze!", "free": "Kostenlos spielen", "gamifyButton": "Gestalte dein Leben spielerisch!", "goalSample1": "1 Stunde Klavier üben", @@ -73,9 +73,9 @@ "history": "Verlauf", "infhQuote": "[Habitica] hat mir geholfen Struktur in mein Leben an der Universität zu bringen.", "invalidEmail": "Um das Passwort zurückzusetzen, ist eine gültige Email-Adresse notwendig.", - "irishfeet123Quote": "I've had horrible habits with clearing my place completely after meals and leaving cups all over the place. [Habitica] has cured that!", + "irishfeet123Quote": "Ich hatte die schrecklichen Angewohnheiten, nach Mahlzeiten nicht aufzuräumen und Tassen in der ganzen Wohnung stehen zu lassen. [Habitica] hat mich davon geheilt!", "joinOthers": "Schließe dich 250.000 Leuten an, die Spaß dabei haben, ihre Ziele zu erreichen!", - "kazuiQuote": "Before [Habitica], I was stuck with my thesis, as well as dissatisfied with my personal discipline regarding housework and things like learning vocabulary and studying Go theory. It turns out breaking down these tasks into smaller manageable checklists is quite the thing to keep me motivated and constantly working.", + "kazuiQuote": "Vor [Habitica] kam ich mit meiner Dissertation nicht weiter und war unzufrieden mit meiner Selbstdisziplin bei Hausarbeiten, Vokabellernen und dem Studium der Go-Theorie. Es hat sich herausgestellt, dass das Aufteilen der Aufgaben in kleinere, machbare Checklisten etwas ist, das mich motiviert und zum konstanten Arbeiten anregt.", "landingadminlink": "Verwaltungspakete", "landingend": "Noch nicht überzeugt?", "landingend2": "Hier ist eine genauere Liste", diff --git a/common/locales/de/settings.json b/common/locales/de/settings.json index 2aac51bbe3..efb06e614b 100644 --- a/common/locales/de/settings.json +++ b/common/locales/de/settings.json @@ -42,7 +42,7 @@ "customDayStart": "Tageswechsel einstellen", "24HrClock": "24h Uhr", "customDayStartInfo1": "Habitica ist so eingestellt, dass Deine täglichen Aufgaben um Mitternacht in deiner eigenen Zeitzone überprüft und zurückgesetzt werden. Wir empfehlen den folgenden Text zu lesen, bevor Du diese Einstellungen veränderst:", - "customDayStartInfo4": "Complete all your Dailies before changing the Custom Day Start or Rest in the Inn that day. Changing your Custom Day Start may cause Cron to run immediately, but after the first day it works as expected.

Allow a window of two hours for the change to take effect. For example, if it is currently set to 0 (midnight), change it before 10pm; if you want to set it to 9pm, change it before 7pm.

Enter an hour from 0 to 23 (it uses a 24 hour clock). Typing is more effective than arrow keys. Once set, reload the page to confirm that the new value is being displayed.", + "customDayStartInfo4": "Beende alle deine täglichen Aufgaben bevor du deinen persönlichen Tagesstart änderst oder checke für diesen Tag im Gasthaus ein. Das Ändern deines Tagesstarts kann bewirken, dass dein Cron sofort ausgeführt wird, aber nach dem ersten Tag funktioniert alles wie erwartet.

Plane ein Zeitfenster von zwei Stunden ein, um die Änderungen wirksam werden zu lassen. Wenn die Zeit bisher beispielsweise auf 0 (Mitternacht) gesetzt ist, ändere sie vor 22 Uhr; Wenn du sie auf 21 setzen willst, ändere sie vor 19 Uhr.

Gib eine Zahl zwischen 0 und 23 an. Tippen ist effektiver als das Benutzen der Pfeiltasten. Wenn du die Zeit gesetzt hast, lade die Seite neu, um sicherzustellen, dass der neue Wert angezeigt wird.", "misc": "Verschiedenes", "showHeader": "Header anzeigen", "changePass": "Passwort ändern", @@ -74,7 +74,7 @@ "usernameSuccess": "Dein Login Name wurde erfolgreich geändert!", "emailSuccess": "Die E-Mail-Adresse wurde erfolgreich geändert", "detachFacebook": "Facebook Registrierung löschen", - "detachedFacebook": "Successfully removed Facebook from your account", + "detachedFacebook": "Facebook erfolgreich von deinem Konto entfernt", "addedLocalAuth": "Successfully added local authentication", "data": "Daten", "exportData": "Daten exportieren", @@ -115,7 +115,7 @@ "couponText": "Manchmal verteilen wir auf Events Coupon-Codes für spezielle Ausrüstung (z.B. an unserem WonderCon-Stand)", "apply": "Anwenden", "resubscribe": "Wieder abonnieren", - "promoCode": "Promo Code", + "promoCode": "Aktionscode", "promoCodeApplied": "Promo Code aktiviert! Überprüfe dein Inventar", "promoPlaceholder": "Promo Code eingeben", "displayInviteToPartyWhenPartyIs1": "Zeige \"In Gruppe einladen\"-Schaltfläche an, wenn die Gruppe nur 1 Mitglied hat." diff --git a/common/locales/de/tasks.json b/common/locales/de/tasks.json index bd1c782a41..0b1d156ec0 100644 --- a/common/locales/de/tasks.json +++ b/common/locales/de/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Verstärkungstrank", "fortifyPop": "Setzt alle Aufgaben auf den Anfangswert (gelb) zurück und füllt Deine Lebenspunkte wieder auf.", "fortify": "Verstärken", - "fortifyText": "Verstärken wird alle Deine Aufgaben auf ihren Anfangswert (gelb) zurücksetzen, so als ob Du sie gerade erst Hinzugefügt hättest und füllt Deine Lebenspunkte wieder auf. Sieh' das als letzten Ausweg! Rote Aufgaben bieten einen guten Anreiz sich zu bessern. Aber wenn zu viel Rot Dich zur Verzweiflung treibt, und jeder Tag tödlich endet, dann investiere Deine Edelsteine hier und hol' erstmal Luft!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Bist Du sicher, dass Du diese Aufgabe löschen möchtest?", "streakCoins": "Strähnen Bonus!", "pushTaskToTop": "Aufgabe nach oben verschieben", diff --git a/common/locales/en@pirate/limited.json b/common/locales/en@pirate/limited.json index 03e0a47cdf..d708f4b7bd 100644 --- a/common/locales/en@pirate/limited.json +++ b/common/locales/en@pirate/limited.json @@ -12,10 +12,10 @@ "aquaticFriendsText": "Got splashed <%= seafoam %> times by crew members.", "valentineCard": "Valentine's Day Card", "valentineCardNotes": "Send a Valentine's Day card to a party member.", - "valentine0": "\"Roses are red\n\nMy Dailies are blue\n\nI'm happy that I'm\n\nIn a Party with you!\"", - "valentine1": "\"Roses are red\n\nViolets are nice\n\nLet's get together\n\nAnd fight against Vice!\"", - "valentine2": "\"Roses are red\n\nThis poem style is old\n\nI hope that you like this\n\n'Cause it cost ten Gold.\"", - "valentine3": "\"Roses are red\n\nIce Drakes are blue\n\nNo treasure is better\n\nThan time spent with you!\"", + "valentine0": "\"Roses be red\n\nMy Dailies be blue\n\nI'm happy that I'm\n\nIn a Crew wit' ye!\"", + "valentine1": "\"Roses be red\n\nViolets be nice\n\nLet's get together\n\nAn' fight against Vice!\"", + "valentine2": "\"Roses be red\n\nThis poem style be old\n\nI hope that ye like this\n\n'Cause it cost ten Gold.\"", + "valentine3": "\"Roses be red\n\nIce Drakes be blue\n\nNo treasure be better\n\nThan time spent with' ye!\"", "adoringFriends": "Adorin' Mates", "adoringFriendsText": "Avast; ye an' yer mate must really care 'bout each other! Sent er received <%= cards %> Valentine's Day cards.", "polarBear": "Polar Bear", @@ -25,7 +25,7 @@ "seasonalShop": "Seasonal Shop", "seasonalShopClosedTitle": "<%= linkStart %>Siena Leslie<%= linkEnd %>", "seasonalShopTitle": "<%= linkStart %>Seasonal Sorceress<%= linkEnd %>", - "seasonalShopClosedText": "The Seasonal Shop is currently closed!! I don't know where the Seasonal Sorceress is now, but I bet she'll be back during the next Grand Gala!", + "seasonalShopClosedText": "The Seasonal Shop currently be closed!! I don't know where th' Seasonal Sorceress be now, but I bet she'll be back during th' next Grand Gala!", "seasonalShopText": "Welcome t' th' Seasonal Shop!! We're stockin' springtime Seasonal Edition goodies at th' moment. Everything here will be available t' purchase durin' th' Spring Fling event each year, but we're only open until April 30th, so be sure t' stock up now, or you'll have t' wait a year t' buy these items again!", "seasonalShopSummerText": "Welcome t' th' Seasonal Shop!! We be stockin' summertime Seasonal Edition goodies at th' moment. Everything here will be available t' purchase during th' Summer Splash event each year, but we're only open until July 31st, so be sure t' stock up now, or you'll have t' wait a year t' buy these items again!", "seasonalShopRebirth": "If ye've used th' Orb o' Rebirth, ye can buy this gear in th' Loot Column after ye've unlocked the Item Shop. At first, ye'll only be able to buy the items fer yer current class (Mercenary by default), but remain stout o' heart, ye can have the other classes' stuff if ye switch to that class.", diff --git a/common/locales/en@pirate/tasks.json b/common/locales/en@pirate/tasks.json index 7e8ac25410..1701e809ac 100644 --- a/common/locales/en@pirate/tasks.json +++ b/common/locales/en@pirate/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Fortify Potion", "fortifyPop": "Return all tasks t' neutral value (yellow color), 'n restore all lost Health.", "fortify": "Fortify", - "fortifyText": "Fortify gunna return all ye tasks to a neutral (yellow) state, as if ye'd just added them, 'n top ye Health off to full. Consider 'tis an option 'o last resort! Red tasks provide jolly incentive to improve. But if all that red fills ye wit' despair, 'n th' beginnin' 'o each new day proves lethal, spend th' Gems 'n catch a reprieve!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Arrr ye sure ye want t' delete this task?", "streakCoins": "Streak Bonus!", "pushTaskToTop": "Push task to top", diff --git a/common/locales/en_GB/tasks.json b/common/locales/en_GB/tasks.json index 02aa3591fa..1c5a4cee2d 100644 --- a/common/locales/en_GB/tasks.json +++ b/common/locales/en_GB/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Fortify Potion", "fortifyPop": "Return all tasks to neutral value (yellow colour), and restore all lost Health.", "fortify": "Fortify", - "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. Consider this an option of last resort! Red tasks provide good incentive to improve. But if all that red fills you with despair, and the beginning of each new day proves lethal, spend the Gems and catch a reprieve!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Are you sure you want to delete this task?", "streakCoins": "Streak Bonus!", "pushTaskToTop": "Push task to top", diff --git a/common/locales/es/tasks.json b/common/locales/es/tasks.json index 18e8700c94..3aec9d93d7 100644 --- a/common/locales/es/tasks.json +++ b/common/locales/es/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Poción de Fortalecimiento.", "fortifyPop": "Devuelve todas sus tareas a un valor neutral (amarillo), y recupera toda la salud perdida.", "fortify": "Fortalecer", - "fortifyText": "Fortalecer devuelve todas tus tareas a un valor neutral (amarillo), como si las acabaras de añadir, y pone a tope tu salud. ¡Considera esto como tu última opción! Las tareas rojas proporcionan un incentivo para mejorar. Si tanto rojo te llena de deseperación y el comienzo de cada día se vuelve mortal, gasta las gemas y tomate un suspiro.", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "¿Estás seguro de que quieres eliminar esta tarea?", "streakCoins": "¡Bonus de Racha!", "pushTaskToTop": "Desplazar tarea al inicio", diff --git a/common/locales/es_419/tasks.json b/common/locales/es_419/tasks.json index 3d9ef1ce5e..8d4c1f5efa 100644 --- a/common/locales/es_419/tasks.json +++ b/common/locales/es_419/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Poción de fortalecimiento.", "fortifyPop": "Devuelve todas tus tareas a un valor neutral (amarillo), y recupera toda la salud perdida.", "fortify": "Fortalecer", - "fortifyText": "Fortalecer devuelve todas tus tareas a un valor neutral (amarillo), como si las acabaras de añadir, y llena a tope tu salud. ¡Considera esto como tu última opción! Las tareas rojas proporcionan un incentivo para mejorar. ¡Si tanto rojo te llena de desesperación y el comienzo de cada día resulta fatal, gasta las gemas y tómate un suspiro!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "¿Estás seguro de que quieres eliminar esta tarea?", "streakCoins": "¡Bonus de racha!", "pushTaskToTop": "Enviar tarea al tope", diff --git a/common/locales/fr/front.json b/common/locales/fr/front.json index 9606b34d78..9deda36548 100644 --- a/common/locales/fr/front.json +++ b/common/locales/fr/front.json @@ -34,7 +34,7 @@ "companyVideos": "Vidéos", "contribUse": "Utilisation exclusive aux contributeurs Habitica", "dragonsilverQuote": "Je ne peux vous dire combien d'outils de gestion du temps et des tâches j'ai essayé au cours des années ... [Habitica] est le seul outil que j'utilise qui m'a aidé à atteindre mes objectifs au lieu de simplement les lister.", - "dreimQuote": "Quand j'ai découvert [Habitica] le printemps dernier, je venais juste de rater la moitié de mes examens. Grâce aux Quotidiennes… j'ai réussi à m'organiser et à me discipliner, et j'ai finalement passé mes examens avec de bons résultats il y a un mois.", + "dreimQuote": "Quand j'ai découvert [Habitica] l'été dernier, je venais juste de rater la moitié de mes examens. Grâce aux Quotidiennes… j'ai réussi à m'organiser et à me discipliner, et, il y a un mois, j'ai finalement passé mes examens avec de bons résultats.", "elmiQuote": "Chaque matin, je me réjouis de me lever pour aller gagner des pièces d'or!", "email": "E-mail", "emailNewPass": "Envoyer un nouveau mot de passe par e-mail", @@ -55,7 +55,7 @@ "footerMobile": "Mobile", "footerSocial": "Social", "forgotPass": "Mot de passe oublié", - "frabjabulousQuote": "[Habitica] est la pour laquelle j'ai eu un boulot très bien rémunéré ... et encore plus fort, j'utilise du fil dentaire tous les jours !", + "frabjabulousQuote": "[Habitica] est la raison pour laquelle j'ai eu un boulot très bien rémunéré ... et encore plus fort, j'utilise du fil dentaire tous les jours !", "free": "Rejoindre gratuitement", "gamifyButton": "Jouez le jeu de votre vie dès aujourd'hui!", "goalSample1": "S'exercer au piano 1h", diff --git a/common/locales/fr/tasks.json b/common/locales/fr/tasks.json index 1952344e4c..fd7e770f2a 100644 --- a/common/locales/fr/tasks.json +++ b/common/locales/fr/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Potion de Fortification", "fortifyPop": "Fait revenir toutes les tâches à une valeur neutre (couleur jaune) et restaure tous les points de santé que vous aviez perdus.", "fortify": "Fortification", - "fortifyText": "La potion de fortification ramènera toutes vos tâches à un niveau neutre (jaune), comme si vous veniez de les ajouter, et remplira votre barre de santé. N'utilisez cette option qu'en dernier ressort ! Les tâches de couleur rouge sont une bonne invitation à s'améliorer. Mais si voir tout ce rouge vous remplit de désespoir et que chaque nouveau jour vous semble un danger mortel, dépenser vos gemmes et accordez vous un sursis !", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Êtes-vous sûr de vouloir supprimer cette tâche ?", "streakCoins": "Bonus de combo !", "pushTaskToTop": "Déplacer la tâche en tête de liste", diff --git a/common/locales/he/tasks.json b/common/locales/he/tasks.json index 73ce621f03..14c3632049 100644 --- a/common/locales/he/tasks.json +++ b/common/locales/he/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "שיקוי תגבור", "fortifyPop": "מחזיר את כל המשימות לערכן ההתחלתי (צבע צהוב) ומחזיר את כל הבריאות שאיבדת.", "fortify": "תגבור", - "fortifyText": "תגבור יחזיר את כל המשימות שלך למצבן הטבעי (צהוב), כאילו הוספת אותן עכשיו, וימלא את הבריאות שלך עד הסוף. חשוב/חשבי על זה כעל מוצא אחרון! משימות אדומות מספקות תמריץ טוב להשתפר. במקרה חמור, בו כל הצבע האדום הזה ממלא את ליבך ביאוש ויגון, ותחילתו של כל יום מהווה מכה קטלנית עבורך, שלם/י את אבני החן וקבל/י קצת אוויר לנשימה!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "בטוח/ה שיש צורך למחוק את המשימה הזו?", "streakCoins": "בונוס התמדה!", "pushTaskToTop": "דחיפת המשימה למעלה", diff --git a/common/locales/hu/tasks.json b/common/locales/hu/tasks.json index 8d38dbd267..39386b32de 100644 --- a/common/locales/hu/tasks.json +++ b/common/locales/hu/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Erősítőfőzet", "fortifyPop": "Visszaállít minden feladatot semleges értékűre (sárga színű), és feltölti az életerőt.", "fortify": "Megerősít", - "fortifyText": "Az Erősítés visszaállítja minden feladatodat semleges (sárga) állapotba, mintha csak most adtad volna őket hozzá, és feltölti az életerődet. Vedd úgy, hogy ez az utolsó lehetőség, amit végveszélyben használhatsz. A vörös feladatok arra bíztatnak, hogy fejleszd őket, de ha minden vörös feladat kétségbeeséssel tölt el és minden új nap halálosnak bizonyul, akkor költsd el a Drágaköveket és függeszd fel a halálbűntetést!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Biztos vagy benne, hogy törölni akarod ezt a feladatot?", "streakCoins": "Széria bónusz!", "pushTaskToTop": "Tetejére", diff --git a/common/locales/it/tasks.json b/common/locales/it/tasks.json index 6336c007a4..4dd8eac8f3 100644 --- a/common/locales/it/tasks.json +++ b/common/locales/it/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Pozione di Fortificazione", "fortifyPop": "Fa tornare tutte le attività al valore neutro (colore giallo) e ripristina tutti i punti vita persi.", "fortify": "Fortifica", - "fortifyText": "La fortificazione farà tornare tutte le attività allo stato neutro (colore giallo), proprio come se le avessi appena create, e riempirà la tua barra della vita. Considerala come ultima risorsa se la situazione si fa difficile! Le attività in rosso sono un buon incentivo per migliorare; tuttavia, se tutto quel rosso comincia a preoccuparti e l'inizio di ogni nuovo giorno rischia di essere fatale, spendi qualche gemma e datti un'altra opportunità!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Vuoi davvero eliminare questa attività?", "streakCoins": "Bonus serie!", "pushTaskToTop": "Metti in cima alla lista", diff --git a/common/locales/ja/tasks.json b/common/locales/ja/tasks.json index 8589cf0d8e..3a39fa13b9 100644 --- a/common/locales/ja/tasks.json +++ b/common/locales/ja/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "強化ポーション", "fortifyPop": "全てのタスクを通常の状態 (黄色)に戻します。加えて全ての体力を回復させます。", "fortify": "強化", - "fortifyText": "この強化は今追加したかのように、全てのタスクを中立(黄色)の状態に戻します。さらにあなたのHealthを全回復させます。このオプションは最後の手段だと考えてください!赤いタスクは成長のための良い動機を与えてくれます。しかし全ての赤いタスクがあなたを絶望でいっぱいにしてしまい、毎日の始まりが死に至るほどの苦しみであるならば、ジェムを支払って救済を得ましょう!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "本当にこのタスクを削除しても良いですか?", "streakCoins": "連続実行ボーナス!", "pushTaskToTop": "タスクを一番上に上げる", diff --git a/common/locales/nl/limited.json b/common/locales/nl/limited.json index edf468c82e..79c14f4221 100644 --- a/common/locales/nl/limited.json +++ b/common/locales/nl/limited.json @@ -12,10 +12,10 @@ "aquaticFriendsText": "Is <%= seafoam %> keer natgespetterd door groepsleden.", "valentineCard": "Valentijnskaart", "valentineCardNotes": "Stuur een Valentijnskaart naar een groepsgenoot.", - "valentine0": "\"Roses are red\n\nMy Dailies are blue\n\nI'm happy that I'm\n\nIn a Party with you!\"", - "valentine1": "\"Roses are red\n\nViolets are nice\n\nLet's get together\n\nAnd fight against Vice!\"", - "valentine2": "\"Roses are red\n\nThis poem style is old\n\nI hope that you like this\n\n'Cause it cost ten Gold.\"", - "valentine3": "\"Roses are red\n\nIce Drakes are blue\n\nNo treasure is better\n\nThan time spent with you!\"", + "valentine0": "\"Rozen zijn rood\nTaken zijn blauw\nIk ben blij dat ik in\nEen groep zit met jou!\"", + "valentine1": "\"Rozen zijn rood\nTakken zijn stijf\nSamen gaan wij\nOndeugd te lijf!\"", + "valentine2": "\"Rozen zijn rood\nDie dichtstijl is oud\nIk hoop dat je 't leuk vindt\nHet kostte 10 goud.\"", + "valentine3": "\"Rozen zijn rood\nEn ijsdraken blauw\nGeen schat is me liever\nDan mijn tijd met jou!\"", "adoringFriends": "Liefhebbende vrienden", "adoringFriendsText": "Aww, jij en je vriend moeten wel heel erg veel om elkaar geven! Heeft <%= cards %> Valentijnskaarten verzonden of ontvangen.", "polarBear": "IJsbeer", diff --git a/common/locales/nl/tasks.json b/common/locales/nl/tasks.json index 1fe3c713cd..a1471870da 100644 --- a/common/locales/nl/tasks.json +++ b/common/locales/nl/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Versterkingsdrankje", "fortifyPop": "Geeft alle taken een neutrale waarde (gele kleur), en herstelt alle verloren gezondheidspunten.", "fortify": "Versterk", - "fortifyText": "Versterken brengt al je taken terug tot een neutrale (gele) staat, alsof je ze net toegevoegd hebt, en tevens wordt je gezondheidsbalk weer helemaal gevuld. Beschouw dit als een laatste redmiddel! Rode taken zijn een goede motivatie om beter je best te doen. Maar als al dat rood je wanhopig maakt en het begin van elke dag dodelijk lijkt, geef dan een paar edelstenen uit aan een uitstel van executie!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Weet je zeker dat je deze taak wilt verwijderen?", "streakCoins": "seriebonus!", "pushTaskToTop": "Taak bovenaan zetten", diff --git a/common/locales/pl/tasks.json b/common/locales/pl/tasks.json index 9a61d25b02..e99f752e18 100644 --- a/common/locales/pl/tasks.json +++ b/common/locales/pl/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Mikstura wzmocnienia", "fortifyPop": "Przywraca wszystkie zadania do neutralnej wartości (żółty kolor), oraz uzdrawia całe stracone Zdrowie.", "fortify": "Wzmocnij", - "fortifyText": "Wzmocnienie przywróci wszystkie zadania do wartości neutralnej (żółty kolor), tak jakbyś dopiero co je dodał, a w dodatku uzdrowi cię do pełna. Traktuj tą opcję jako ostatnią deskę ratunku! Czerwone zadania zapewniają dobrą motywację do poprawienia się. Jednak jeśli te wszystkie czerwone zadania przyprawiają cię o rozpacz, a rozpoczęcie każdego nowego dnia jest śmiertelnie niebezpieczne, poświęć Klejnoty i poczuj ulgę!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Jesteś pewien, że chcesz usunąć to zadanie?", "streakCoins": "Premia za serię!", "pushTaskToTop": "Prześlij zadanie na górę", diff --git a/common/locales/pt/tasks.json b/common/locales/pt/tasks.json index f049ed7f55..f99fb7e80b 100644 --- a/common/locales/pt/tasks.json +++ b/common/locales/pt/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Poção de Fortificação", "fortifyPop": "Reverte todas tarefas para o valor neutro (cor amarela), e recupera toda Vida perdida.", "fortify": "Fortificar", - "fortifyText": "Fortificar reverterá todas suas tarefas para o valor neutro (amarelo), como se tivesse acabado de adicioná-las, e completará sua vida até estar cheia. Considere essa opção como último recurso! Tarefas vermelhas oferecem um grande incentivo para melhorar. Mas se todo vermelho o encher de desespero, e o começo de cada dia provar ser letal, gaste as Gemas e pegue um adiantamento!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Tem certeza de que deseja deletar essa tarefa?", "streakCoins": "Bônus de Combo!", "pushTaskToTop": "Enviar tarefa para o topo", diff --git a/common/locales/ro/tasks.json b/common/locales/ro/tasks.json index cd77b2af4a..be75d67fa0 100644 --- a/common/locales/ro/tasks.json +++ b/common/locales/ro/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Poțiune fortifiantă", "fortifyPop": "Readu toate țelurile la valoarea neutră (culoarea galbenă) și refă toată Sănătatea pierdută.", "fortify": "Fortifică", - "fortifyText": "Fortifierea va readuce toate țelurile la valoarea neutră (galben), ca și cum abia le-ai fi adăugat, și va reface Sănătatea la maxim. Consideră asta o opțiune de caz extrem! Sarcinile roșii furnizează un bun imbold pentru a progresa. Dar dacă tot roșul ăsta te umple cu disperare, și începutul fiecărei zile se dovedește letal, cheltuie Nestematele și ia o pauză!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Ești sigur că vrei să ștergi acest țel?", "streakCoins": "Bonus de realizare în șir!", "pushTaskToTop": "Urcă sarcina în vârf", diff --git a/common/locales/ru/gear.json b/common/locales/ru/gear.json index aaf135299c..2f06157076 100644 --- a/common/locales/ru/gear.json +++ b/common/locales/ru/gear.json @@ -443,7 +443,7 @@ "headArmoireBlueHairbowText": "Синий бант", "headArmoireBlueHairbowNotes": "Станьте восприимчивым, стойким и находчивым, надев этот превосходный синий бант! Увеличивает восприятие на <%= per %>, телосложение на <%= con %> и интеллект на <%= int %>. Волшебный сундук: независимый предмет.", "headArmoireRoyalCrownText": "Королевская корона", - "headArmoireRoyalCrownNotes": "Да здравствует правитель, могучий и сильный!Увеличивает силу на <%= str %>. Волшебный сундук: независимый предмет.", + "headArmoireRoyalCrownNotes": "Да здравствует правитель, могучий и сильный! Увеличивает силу на <%= str %>. Волшебный сундук: независимый предмет.", "headArmoireGoldenLaurelsText": "Золотые лавры", "headArmoireGoldenLaurelsNotes": "These golden laurels reward those who have conquered bad habits. Increases Perception and Constitution by <%= attrs %> each. Enchanted Armoire: Golden Toga Set (Item 2 of 3).", "headArmoireHornedIronHelmText": "Шлем Рогатого железа", diff --git a/common/locales/ru/limited.json b/common/locales/ru/limited.json index 3eaf4c751f..e0ca20777b 100644 --- a/common/locales/ru/limited.json +++ b/common/locales/ru/limited.json @@ -13,7 +13,7 @@ "valentineCard": "Валентинка", "valentineCardNotes": "Отправьте валентинку члену команды.", "valentine0": "\"Roses are red\n\nMy Dailies are blue\n\nI'm happy that I'm\n\nIn a Party with you!\"", - "valentine1": "\"Roses are red\n\nViolets are nice\n\nLet's get together\n\nAnd fight against Vice!\"", + "valentine1": "«Розы алеют,\n\nБелеет сирень,\n\nВместе поборем\n\nПороки и лень!»", "valentine2": "\"Roses are red\n\nThis poem style is old\n\nI hope that you like this\n\n'Cause it cost ten Gold.\"", "valentine3": "\"Roses are red\n\nIce Drakes are blue\n\nNo treasure is better\n\nThan time spent with you!\"", "adoringFriends": "Любимые друзья", diff --git a/common/locales/ru/settings.json b/common/locales/ru/settings.json index 8d1458a001..0c59d582ec 100644 --- a/common/locales/ru/settings.json +++ b/common/locales/ru/settings.json @@ -74,8 +74,8 @@ "usernameSuccess": "Имя пользователя успешно изменено", "emailSuccess": "Адрес электронной почты успешно изменен", "detachFacebook": "Восстановить регистрацию Facebook", - "detachedFacebook": "Successfully removed Facebook from your account", - "addedLocalAuth": "Successfully added local authentication", + "detachedFacebook": "Facebook успешно отсоединен вашего аккаунта", + "addedLocalAuth": "Локальная идентификация успешно добавлена", "data": "Данные", "exportData": "Экспорт данных", "emailChange1": "Чтобы изменить ваш email, пожалуйста, отправьте email на", diff --git a/common/locales/ru/tasks.json b/common/locales/ru/tasks.json index 767cd7e9e1..be78de81cb 100644 --- a/common/locales/ru/tasks.json +++ b/common/locales/ru/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Эликсир укрепления", "fortifyPop": "Вернуть все задания в нейтральное состояние (желтый цвет) и восстановить всё здоровье.", "fortify": "Укрепление", - "fortifyText": "Укрепление вернет все задания в нейтральное (желтое) состояние, как если бы вы только что добавили их, и восстановит здоровье до максимума. Считайте это крайней мерой! Красные задания дают хороший стимул для улучшения. Но если вы чувствуете, что вся эта краснота вселяет в вас безысходность, а начало каждого нового дня угрожает смертью, вы можете купить передышку за самоцветы!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Вы уверены, что хотите удалить эту задачу?", "streakCoins": "Бонус за серию!", "pushTaskToTop": "Переместить задание наверх", diff --git a/common/locales/sk/tasks.json b/common/locales/sk/tasks.json index 3c82146a92..819336c83c 100644 --- a/common/locales/sk/tasks.json +++ b/common/locales/sk/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Siloxír", "fortifyPop": "Vráť všetky úlohy do neutrálneho stavu (žltá farba) a navráť všetko stratené zdravie.", "fortify": "Posilniť", - "fortifyText": "Siloxír vráti všetky tvoje úlohy do neutrálneho (žltého) stavu, akoby si ich len teraz pridal a úplne ti doplní zdravie. Ber to ako poslednú možnosť! Červené úlohy dobre povzbudzujú k zlepšeniu. Ale ak ťa veľa červenej napĺňa zúfalstvom a začiatok každého dňa je pre teba smrtiaci, obetuj zopár drahokamov a získaj milosť.", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Si si istý, že chceš zmazať túto úlohu?", "streakCoins": "Bonus za sériu!", "pushTaskToTop": "Presuň úlohu navrch", diff --git a/common/locales/sr/tasks.json b/common/locales/sr/tasks.json index 81042736f2..6a26bd0af0 100644 --- a/common/locales/sr/tasks.json +++ b/common/locales/sr/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Napitak okrepljenja", "fortifyPop": "Vraća sve zadatke na početnu vrednost (žuta boja), i obnavlja izgubljeno zdravlje.", "fortify": "Okrepljenje", - "fortifyText": "Okrepljenje vraća sve zadatke u početno (žuto) stanje, kao da su tek napravljeni, i podiže zdravlje na maksimum. Smatrajte ovo krajnjom merom! Crveni zadaci mogu biti dobra motivacija da više potrudite. Međutim, ako vas crveno baca u očaj i smrt vam preti na početku svakog dana, draguljima možete kupiti odušak.", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Jeste li sigurni da želite da obrišete ovaj zadatak?", "streakCoins": "Bonus zbog redovnog izvršavanja zadataka!", "pushTaskToTop": "Premesti zadatak na vrh", diff --git a/common/locales/sv/tasks.json b/common/locales/sv/tasks.json index 538b6f04ca..8c090d0488 100644 --- a/common/locales/sv/tasks.json +++ b/common/locales/sv/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Stärkande Dryck", "fortifyPop": "Återställ alla uppgifter till neutralt värde (gul färg) och återställ all förlorad Hälsa.", "fortify": "Stärk", - "fortifyText": "Den Stärkande Drycken återställer alla uppgifter till ett neutralt (gult) värde, som om du nyss lagt till dem, och återställer all förlorad Hälsa. Se det här som en sista utväg! Röda uppgifter ger uppmuntran att bättra sig. Men om allt det röda fyller dig med förtvivlan och början av varje dag känns hemsk, spendera Juvelerna och bli benådad.", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Är du säker att du vill ta bort denna uppgift?", "streakCoins": "Följdbonus!", "pushTaskToTop": "Förflytta uppgift till toppen", diff --git a/common/locales/uk/tasks.json b/common/locales/uk/tasks.json index f500eb84ef..c729f4adb7 100644 --- a/common/locales/uk/tasks.json +++ b/common/locales/uk/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "Зілля підсилення", "fortifyPop": "Повернути завдання до нейтрального стану (жовтого кольору) та відновити все здоров'я.", "fortify": "Підсилитися", - "fortifyText": "Підсилення поверне всі завдання до нейтрального (жовтого) стану, так, наче Ви щойно їх створили, а здоров'я повністю відновиться. Уважайте це крайнім заходом! Червоні завдання дають добрий стимул для самовдосконалення. Але, якщо все червоне вселяє у Вас безвихідь, а кожний новий день може стати останнім, тоді Ви можете придбати собі відтермінування за самоцвіти!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "Ви справді бажаєте вилучити це завдання?", "streakCoins": "Бонус за серію!", "pushTaskToTop": "Перемістити завдання вгору", diff --git a/common/locales/zh/tasks.json b/common/locales/zh/tasks.json index 2038d784a5..ed006aaf79 100644 --- a/common/locales/zh/tasks.json +++ b/common/locales/zh/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "稳固药剂", "fortifyPop": "将所有任务恢复至中性状态(黄色),并补充所有损失的生命值。", "fortify": "稳固", - "fortifyText": "稳固会将所有的任务重置(黄色)状态,就像刚刚添加他们一样;还会回满生命值。将这个选项作为最后的方案!红色任务会为进步提供很好的动力。但是如果所有任务都变红了让你感到绝望,并且每天的伤害对你是致命的,那么花费宝石来缓解一下吧!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "你确定要删除这个任务吗?", "streakCoins": "连击奖励!", "pushTaskToTop": "将任务置于顶部", diff --git a/common/locales/zh_TW/tasks.json b/common/locales/zh_TW/tasks.json index 36058713b1..ad38bb5504 100644 --- a/common/locales/zh_TW/tasks.json +++ b/common/locales/zh_TW/tasks.json @@ -85,7 +85,7 @@ "fortifyName": "穩固藥水", "fortifyPop": "將所有任務調回中性 ( 黃色 ),並將 HP 補滿。", "fortify": "穩固", - "fortifyText": "穩固會將你的任務回復到中性狀態 ( 黃色 ,如同剛新增時),並把你的生命值補滿。把它當成無計可施時的最後王牌!紅色會為進步提供良好的動力,但如果滿目紅色讓你難過,且每天開始時都對你致命,那麼花費寶石來喘口氣吧!", + "fortifyText": "Fortify will return all your tasks to a neutral (yellow) state, as if you'd just added them, and top your Health off to full. This is great if all your red tasks are making the game too hard, or all your blue tasks are making the game too easy. If starting fresh sounds much more motivating, spend the Gems and catch a reprieve!", "sureDelete": "你確定要刪除這個任務嗎?", "streakCoins": "連擊獎勵", "pushTaskToTop": "置頂", From 619b33795ac88af49a49d667fe91dee90a4e03df Mon Sep 17 00:00:00 2001 From: Alys Date: Thu, 13 Aug 2015 16:46:02 +1000 Subject: [PATCH 33/56] remove mention of ads from locale strings, delete ads strings that are no longer used - fixes https://github.com/HabitRPG/habitrpg/issues/5765 --- common/locales/en/contrib.json | 6 ------ common/locales/en/subscriber.json | 6 +----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/common/locales/en/contrib.json b/common/locales/en/contrib.json index b84da52d98..dff045d2d0 100644 --- a/common/locales/en/contrib.json +++ b/common/locales/en/contrib.json @@ -43,7 +43,6 @@ "contributions": "Contributions", "admin": "Admin", "notGems": "is in USD, not in Gems. Aka, if this number is 1, it means 4 gems. Only use this option when manually granting gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add gems.", - "hideAds": "Hide Ads", "gamemaster": "Game Master (staff/moderator)", "backerTier": "Backer Tier", "balance": "Balance", @@ -53,11 +52,6 @@ "visitHeroes": "Visit the Hall of Heroes (contributors and backers)", "conLearn": "Learn more about contributor rewards", "conLearnHow": "Learn how to contribute to Habitica", - "removeAds": "Subscribe to remove ads", - "whyAds": "Why Ads?", - "whyAdsContent1": "Habit is an open source project, and can use all the help it can get - consider this a donation to the contributors. You also get 20 Gems from the purchase, which you can use to buy special items.", - "whyAdsContent2": "'Hey, I backed the Kickstarter!' - follow", - "whyAdsContent3": "these instructions", "surveysSingle": "Helped Habitica grow by filling out a survey. There are no active surveys.", "surveysMultiple": "Helped Habitica grow by filling out <%= surveys %> surveys. There are no active surveys.", "currentSurvey": "Current Survey", diff --git a/common/locales/en/subscriber.json b/common/locales/en/subscriber.json index 0c01e4074c..c448afe75f 100644 --- a/common/locales/en/subscriber.json +++ b/common/locales/en/subscriber.json @@ -1,9 +1,7 @@ { "subscription": "Subscription", "subscriptions": "Subscriptions", - "subDescription": "Disable ads, buy gems with gold, monthly mystery item, retain progress history, double daily drop-caps, supports the devs. Click for more info.", - "disableAds": "Disable ads", - "disableAdsText": "Ads are disabled while you have an active subscription (original donors are grandfathered).", + "subDescription": "Buy gems with gold, get monthly mystery items, retain progress history, double daily drop-caps, support the devs. Click for more info.", "buyGemsGold": "Buy Gems with Gold", "buyGemsGoldText": "Alexander the Merchant will sell you gems at a cost of <%= gemCost %> gold per gem. His monthly shipments are initially capped at <%= gemLimit %> gems per month, but this cap increases by 5 gems for every three months of consecutive subscription, up to a maximum of 50 gems per month!", "retainHistory": "Retain full history entries", @@ -47,7 +45,6 @@ "timeSupport": "Support Hours / Month", "timeSupportText": "We will provide support for training, bugs, installation, and feature requests.", "gameFeatures": "Game features", - "gameNoAds": "Ads disabled for members", "gold2Gem": "Gems purchasable with gold", "gold2GemText": "Members will be able to purchase gems with gold, meaning none of your participants need to buy anything with real money.", "infiniteGem": "Infinite leader gems", @@ -55,7 +52,6 @@ "notYetPlan": "Plan not yet available, but click to contact us and we'll keep you updated.", "contactUs": "Contact Us", "checkout": "Checkout", - "buySubsText": "Buy gems with Gold, No Ads, Support the Devs", "sureCancelSub": "Are you sure you want to cancel your subscription?", "subCanceled": "Subscription will become inactive on", "subGemPop": "Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold. You can see how many Gems are available to buy at the corner of the Gem icon.", From 4993d67f2fe02076385d7ce2c277dcc14c716428 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 13 Aug 2015 14:12:32 +0200 Subject: [PATCH 34/56] export avatars to separate folder in s3 bucket --- 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 8a48ee1638..6439408327 100644 --- a/website/src/controllers/dataexport.js +++ b/website/src/controllers/dataexport.js @@ -108,7 +108,7 @@ dataexport.avatarPage = function(req, res) { }; dataexport.avatarImage = function(req, res, next) { - var filename = 'avatar-'+req.params.uuid+'.png'; + var filename = 'avatars/'+req.params.uuid+'.png'; request.head('https://'+bucket+'.s3.amazonaws.com/'+filename, function(err,response,body) { // cache images for 10 minutes on aws, else upload a new one if (response.statusCode==200 && moment().diff(response.headers['last-modified'], 'minutes') < 10) From 61cd8f58af5aa955f24a4c42d3ecdd2b93095702 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 13 Aug 2015 17:16:24 +0200 Subject: [PATCH 35/56] start using cloudfront for frontpage assets --- website/views/static/front.jade | 106 ++++++++++++++++---------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/website/views/static/front.jade b/website/views/static/front.jade index e2128e3f4c..9812a9f613 100644 --- a/website/views/static/front.jade +++ b/website/views/static/front.jade @@ -51,7 +51,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') span.icon-bar span.icon-bar a.navbar-brand(href='#') - img(src='https://s3.amazonaws.com/habitica-assets/assets/habitica_lockup2_desat.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/assets/habitica_lockup2_desat.png') // Collect the nav links, forms, and other content for toggling #bs-example-navbar-collapse-1.collapse.navbar-collapse ul.nav.navbar-nav.navbar-right @@ -69,7 +69,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') button#header-play-button.btn.btn-primary.navbar-btn.navbar-right(ng-click='playButtonClick()')= env.t('playButtonFull') #intro h1=env.t('motivate1') - img.center-block.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/intro.png') + img.center-block.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/intro.png') // insert intro images .introcall.bg-success h4= env.t('joinOthers') @@ -78,13 +78,13 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .presslogos.text-center = env.t('featuredIn') br - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/lifehacker.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/nyt-logo.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/makeuseof.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/Forbes_logo.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/Cnetlogo.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/Fast-Company-logo.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/kickstarter-logo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/lifehacker.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/nyt-logo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/makeuseof.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Forbes_logo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Cnetlogo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Fast-Company-logo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/kickstarter-logo.png') #intro-text .container-fluid .row @@ -96,20 +96,20 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .row .col-md-3.col-md-offset-1 h2= env.t('testimonialHeading') - img.img-say.img-responsive.visible-lg-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/publicSpaces.png') + img.img-say.img-responsive.visible-lg-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/publicSpaces.png') // Testimonials .col-md-8.col-sm-10.col-sx-10 #quote-carousel.carousel.slide(data-interval='10000', data-ride='carousel') // Bottom Carousel Indicators ol.carousel-indicators li.active(data-target='#quote-carousel', data-slide-to='0') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Drag0nsilver.png', alt='') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Drag0nsilver.png', alt='') li(data-target='#quote-carousel', data-slide-to='1') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/frabjabulous.png', alt='') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/frabjabulous.png', alt='') li(data-target='#quote-carousel', data-slide-to='2') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/AndeeLiao.png', alt='') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/AndeeLiao.png', alt='') li(data-target='#quote-carousel', data-slide-to='3') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/AlexandraSo.png', alt='') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/AlexandraSo.png', alt='') // Carousel Slides / Quotes .carousel-inner.text-center // Quote 1 @@ -201,16 +201,16 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(220, 93, 93); border-right: 1px solid rgba(0, 0, 0, 0.25);') + .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(220, 93, 93); border-right: 0px none;') - .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('businessSample5') - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/coding.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/coding.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='frabjabulous', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/frabjabulous.png') + img(data-toggle='tooltip', data-placement='top', title='frabjabulous', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/frabjabulous.png') .usetweet.tweet.popover.right .arrow .popover-content = env.t('frabjabulousQuote') .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='_AlexandraSo_', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/AlexandraSo.png') + img(data-toggle='tooltip', data-placement='top', title='_AlexandraSo_', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/AlexandraSo.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -245,16 +245,16 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);') + |   .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('healthSample5') - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/clipart-rosemonkeyct-meditation.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/clipart-rosemonkeyct-meditation.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='EvaGantz', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/EvaGantz.png') + img(data-toggle='tooltip', data-placement='top', title='EvaGantz', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/EvaGantz.png') .usetweet.tweet.popover.right .arrow .popover-content = env.t('evagantzQuote') .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='supermouse35', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/supermouse35.png') + img(data-toggle='tooltip', data-placement='top', title='supermouse35', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/supermouse35.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -283,10 +283,10 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') |   .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('teamSample3') br - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/publicSpaces.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/publicSpaces.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='Althaire', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Althaire.png') + img(data-toggle='tooltip', data-placement='top', title='Althaire', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Althaire.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -321,15 +321,15 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);') + .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(90, 98, 223); border-right: 0px none;') - .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('schoolSample5') - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/reading.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/reading.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='InfH', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/InfH.png') + img(data-toggle='tooltip', data-placement='top', title='InfH', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/InfH.png') .usetweet.tweet.popover.right .arrow .popover-content= env.t('infhQuote') .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='Drei-M', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Drei-M.png') + img(data-toggle='tooltip', data-placement='top', title='Drei-M', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Drei-M.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -364,10 +364,10 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);') + |   .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('goalSample5') - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/gaining_an_achievement_by_cosmic_caterpillar-d7uyv5z.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/gaining_an_achievement_by_cosmic_caterpillar-d7uyv5z.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='Kazui', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Kazui.png') + img(data-toggle='tooltip', data-placement='top', title='Kazui', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Kazui.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -402,15 +402,15 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .task-btn(style='display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);') + |   .task-desc(style='display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; letter-spacing: normal; float:left; word-wrap: break-word;')= env.t('choreSample5') - img.sample-img.visible-lg-inline-block(src='https://s3.amazonaws.com/habitrpg-assets/front/images/uses/dusting_by_leephon.png') + img.sample-img.visible-lg-inline-block(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/uses/dusting_by_leephon.png') .usetweet-groups.col-lg-5.col-md-6.visible-lg-inline-block.visible-md-inline-block .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='autumnesquirrel', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/autumnesquirrel.png') + img(data-toggle='tooltip', data-placement='top', title='autumnesquirrel', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/autumnesquirrel.png') .usetweet.tweet.popover.right .arrow .popover-content= env.t('autumnesquirrelQuote') .usetweet-group - img(data-toggle='tooltip', data-placement='top', title='irishfeet123', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/irishfeet123.png') + img(data-toggle='tooltip', data-placement='top', title='irishfeet123', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/irishfeet123.png') .usetweet.tweet.popover.right .arrow .popover-content @@ -430,7 +430,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') br = env.t('rewardByline2') .scrolltweet.hidden-xs.hidden-sm - img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='Elmi', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Elmi.png') + img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='Elmi', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Elmi.png') .tweet.popover.right.pull-right .arrow .popover-content= env.t('elmiQuote') @@ -440,12 +440,12 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') span.glyphicon.glyphicon-check h2 span.glyphicon.glyphicon-arrow-down - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/misc/shop_gold.png') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/misc/shop_gold.png') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/misc/shop_gold.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/misc/shop_gold.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/misc/shop_gold.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/misc/shop_gold.png') h2 span.glyphicon.glyphicon-arrow-down - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/TVreward.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/TVreward.png') button.btn.btn-primary.btn-lg.fixedcta.gamifybutton(ng-click='playButtonClick()')= env.t('gamifyButton') section#levels.container-fluid .row @@ -459,17 +459,17 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') br = env.t('unlockByline2') .scrolltweet.hidden-xs.hidden-sm - img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='16bitFil', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/16bitFil.png') + img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='16bitFil', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/16bitFil.png') .tweet.popover.right.pull-right .arrow .popover-content = env.t('sixteenBitFilQuote') .col-lg-4.col-md-4.col-lg-offset-1.col-sm-8.well.col-xs-8.col-xs-offset-2.col-sm-offset-2 .avatarscroll - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/avatar/avatarstatic.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/avatar/avatarstatic.png') h2 span.glyphicon.glyphicon-arrow-down - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/SAMPLEadventurers.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/SAMPLEadventurers.png') button.btn.btn-primary.btn-lg.fixedcta.gamifybutton(ng-click='playButtonClick()')= env.t('gamifyButton') section#health.bg-danger.container-fluid .row @@ -480,7 +480,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') h2= env.t('punishHeading2') p.sectioninfo= env.t('punishByline') .scrolltweet.hidden-xs.hidden-sm - img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='Zelah Meyer', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/Zelah_Meyer.png') + img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='Zelah Meyer', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/Zelah_Meyer.png') .tweet.popover.right.pull-right .arrow .popover-content @@ -515,13 +515,13 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') br = env.t('questByline2') .scrolltweet.hidden-xs.hidden-sm - img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='skysailor', src='https://s3.amazonaws.com/habitrpg-assets/front/images/testimonials/skysailor.png') + img.scrolltweet-image(data-toggle='tooltip', data-placement='top', title='skysailor', src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/testimonials/skysailor.png') .tweet.popover.right.pull-right .arrow .popover-content = env.t('skysailorQuote') .col-lg-4.col-md-6.col-md-offset-1.col-lg-offset-1.col-sm-10.well.col-xs-10.col-xs-offset-1.col-sm-offset-1.well-lg - img.clearfix.img-responsive.center-block(style='padding-bottom:30px;', src="https://s3.amazonaws.com/habitrpg-assets/front/images/Quest_dilatory_drag'onSmall.png") + img.clearfix.img-responsive.center-block(style='padding-bottom:30px;', src="https://d2afqr2xdmyzvu.cloudfront.net/front/images/Quest_dilatory_drag'onSmall.png") .row .col-lg-5.col-md-5.col-sm-5.col-sm-offset-0.col-xs-5.col-xs-offset-0 .health-progress @@ -531,7 +531,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .bar div(style='width:20%;')   .quest-friend-img - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/party/AnnaCosplay.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/party/AnnaCosplay.png') .col-md-1.col-sm-1.col-xs-1 h2 span.glyphicon.glyphicon-arrow-right @@ -543,7 +543,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .bar div(style='width:0%;')   .quest-friend-img - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/party/GrimReaper.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/party/GrimReaper.png') button.btn.btn-primary.btn-lg.fixedcta.gamifybutton(ng-click='playButtonClick()')= env.t('gamifyButton') section#features.bg-info.container-fluid .row @@ -551,29 +551,29 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .row .col-md-4.col-md-offset-2.col-sm-6 .feature-img - img.center-block.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/Mount.png') + img.center-block.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/Mount.png') .featuretext h4= env.t('featurePetHeading') p = env.t('featurePetByline') .col-md-4.col-sm-6 .feature-img.center-block - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/achievement-triadbingo.png') - img(src='https://s3.amazonaws.com/habitrpg-assets/front/images/achievement-perfect.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/achievement-triadbingo.png') + img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/achievement-perfect.png') .featuretext h4= env.t('featureAchievementHeading') p= env.t('featureAchievementByline') .row .col-md-4.col-md-offset-2.col-sm-6 .feature-img - img.center-block.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/Promo_springclasses2015.png') + img.center-block.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/Promo_springclasses2015.png') .featuretext h4= env.t('featureEquipHeading') p = env.t('featureEquipByline') .col-md-4.col-sm-6 .feature-img - img.center-block.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/Party-Header.png') + img.center-block.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/Party-Header.png') .featuretext h4= env.t('featureSocialHeading') p @@ -593,19 +593,19 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .row .col-lg-2.col-md-2.col-md-offset-1.col-sm-4.col-sm-offset-1.col-xs-6.col-xs-offset-1 a(href='http://ionicframework.com/') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/ionic-logo-horizontal-transparent.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/ionic-logo-horizontal-transparent.png') .col-lg-2.col-lg-offset-0.col-md-2.col-md-offset-0.col-sm-4.col-sm-offset-1.col-xs-6.col-xs-offset-1 a(href='https://www.jetbrains.com/webstorm/') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/logo_webstorm.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/logo_webstorm.png') .col-lg-2.col-lg-offset-0.col-md-2.col-md-offset-0.col-sm-4.col-sm-offset-1.col-xs-6.col-xs-offset-1 a(href='http://github.com/') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/GitHub_Logo.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/GitHub_Logo.png') .col-lg-2.col-lg-offset-0.col-md-2.col-md-offset-0.col-sm-4.col-sm-offset-1.col-xs-6.col-xs-offset-1 a(href='https://trello.com/') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/trello-logo-blue.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/trello-logo-blue.png') .col-lg-2.col-lg-offset-0.col-md-2.col-md-offset-0.col-sm-4.col-sm-offset-1.col-xs-6.col-xs-offset-1 a(href='https://slack.com/') - img.img-responsive(src='https://s3.amazonaws.com/habitrpg-assets/front/images/presslogos/landing_slack_hash_wordmark_logo.png') + img.img-responsive(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/landing_slack_hash_wordmark_logo.png') .row.footer-content include ../shared/footer From f750c53ccc94d67cdd723ce849f267b0d1d36e6d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 13 Aug 2015 17:52:38 +0200 Subject: [PATCH 36/56] remove quote from filename --- website/views/static/front.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views/static/front.jade b/website/views/static/front.jade index 9812a9f613..490e6fd01c 100644 --- a/website/views/static/front.jade +++ b/website/views/static/front.jade @@ -521,7 +521,7 @@ html(ng-app='habitrpg', ng-controller='RootCtrl') .popover-content = env.t('skysailorQuote') .col-lg-4.col-md-6.col-md-offset-1.col-lg-offset-1.col-sm-10.well.col-xs-10.col-xs-offset-1.col-sm-offset-1.well-lg - img.clearfix.img-responsive.center-block(style='padding-bottom:30px;', src="https://d2afqr2xdmyzvu.cloudfront.net/front/images/Quest_dilatory_drag'onSmall.png") + img.clearfix.img-responsive.center-block(style='padding-bottom:30px;', src="https://d2afqr2xdmyzvu.cloudfront.net/front/images/Quest_dilatory_dragonSmall.png") .row .col-lg-5.col-md-5.col-sm-5.col-sm-offset-0.col-xs-5.col-xs-offset-0 .health-progress From b1b4522b4b5ee6b9a3613edb9950d479f22edf15 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Thu, 13 Aug 2015 19:40:25 -0500 Subject: [PATCH 37/56] Fix test --- test/spec/services/analyticsServicesSpec.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index 1c7de0034b..f1767df1ac 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -184,6 +184,12 @@ describe('Analytics Service', function () { expectedProperties.Level = 24; expectedProperties.Mana = 41; expectedProperties.tutorialComplete = false; + expectedProperties["Number Of Tasks"] = { + habits: 1, + dailys: 1, + todos: 1, + rewards: 1 + }; beforeEach(function() { user._id = 'unique-user-id'; @@ -194,6 +200,10 @@ describe('Analytics Service', function () { user.stats.lvl = 24; user.stats.mp = 41; user.flags.tour.intro = 3; + user.habits = [{_id: 'habit'}]; + user.dailys = [{_id: 'daily'}]; + user.todos = [{_id: 'todo'}]; + user.rewards = [{_id: 'reward'}]; analytics.updateUser(properties); clock.tick(); From 078ea4768a747b13f8f77aabbb88cdda40b4a7f0 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 10:58:19 +0200 Subject: [PATCH 38/56] upgrade jade version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b387c0f638..aecc268ec3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "icalendar": "lefnire/node-icalendar#e06da0e55901f0ba940dfadc42c158ed0b1fead9", "image-size": "~0.3.2", "in-app-purchase": "^0.2.0", - "jade": "~1.7.0", + "jade": "~1.11.0", "js2xmlparser": "~0.1.2", "lodash": "~2.4.1", "loggly": "~1.0.8", From 47f6f2febecb3aea2b805ba77a0c8e1c8b095389 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 11:50:09 +0200 Subject: [PATCH 39/56] refactor middlewares in their own folder, move buildFiles to libs/buildFiles --- config.json.example | 1 - website/src/i18n.js | 2 +- website/src/libs/buildManifest.js | 62 ++++++ website/src/middleware.js | 249 ------------------------ website/src/middlewares/apiThrottle.js | 21 ++ website/src/middlewares/cors.js | 7 + website/src/middlewares/domain.js | 39 ++++ website/src/middlewares/errorHandler.js | 24 +++ website/src/middlewares/forceRefresh.js | 9 + website/src/middlewares/locals.js | 51 +++++ website/src/middlewares/redirects.js | 43 ++++ website/src/routes/apiv1.js | 4 +- website/src/routes/apiv2.coffee | 5 +- website/src/routes/dataexport.js | 6 +- website/src/routes/pages.js | 6 +- website/src/server.js | 16 +- 16 files changed, 275 insertions(+), 270 deletions(-) create mode 100644 website/src/libs/buildManifest.js delete mode 100644 website/src/middleware.js create mode 100644 website/src/middlewares/apiThrottle.js create mode 100644 website/src/middlewares/cors.js create mode 100644 website/src/middlewares/domain.js create mode 100644 website/src/middlewares/errorHandler.js create mode 100644 website/src/middlewares/forceRefresh.js create mode 100644 website/src/middlewares/locals.js create mode 100644 website/src/middlewares/redirects.js diff --git a/config.json.example b/config.json.example index 55adbe801f..793dcc1f14 100644 --- a/config.json.example +++ b/config.json.example @@ -21,7 +21,6 @@ "NEW_RELIC_APPLICATION_ID":"NEW_RELIC_APPLICATION_ID", "NEW_RELIC_API_KEY":"NEW_RELIC_API_KEY", "GA_ID": "GA_ID", - "MIXPANEL_TOKEN": "MIXPANEL_TOKEN", "AMPLITUDE_KEY": "AMPLITUDE_KEY", "AMAZON_PAYMENTS": { "SELLER_ID": "SELLER_ID", diff --git a/website/src/i18n.js b/website/src/i18n.js index 82967213b9..2f0f14eeb6 100644 --- a/website/src/i18n.js +++ b/website/src/i18n.js @@ -148,7 +148,7 @@ module.exports = { // Export en strings only, temporary solution for mobile -// This is copied from middleware.js#module.exports.locals#t() +// This is copied from middlewares/locals#t() module.exports.enTranslations = function(){ // stringName and vars are the allowed parameters var language = _.find(avalaibleLanguages, {code: 'en'}); //language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined); diff --git a/website/src/libs/buildManifest.js b/website/src/libs/buildManifest.js new file mode 100644 index 0000000000..ac4c35d19b --- /dev/null +++ b/website/src/libs/buildManifest.js @@ -0,0 +1,62 @@ +var fs = require('fs'); +var path = require('path'); +var nconf = require('nconf'); +var _ = require('lodash'); +var manifestFiles = require("../../public/manifest.json"); + +var IS_PROD = nconf.get('NODE_ENV') === 'production'; +var buildFiles = []; + +var walk = function(folder){ + var res = fs.readdirSync(folder); + var files = []; + + res.forEach(function(fileName){ + file = folder + '/' + fileName; + if(fs.statSync(file).isDirectory()){ + walk(file); + }else{ + var relFolder = path.relative(path.join(__dirname, "/../../build"), folder); + var old = fileName.replace(/-.{8}(\.[\d\w]+)$/, '$1'); + + if(relFolder){ + old = relFolder + '/' + old; + fileName = relFolder + '/' + fileName; + } + + buildFiles[old] = fileName + } + }); + + return files; +} + +walk(path.join(__dirname, "/../../build")); + +var getBuildUrl = module.exports.getBuildUrl = function(url){ + if(buildFiles[url]) return '/' + buildFiles[url]; + + return '/' + url; +} + +module.exports.getManifestFiles = function(page){ + var files = manifestFiles[page]; + + if(!files) throw new Error("Page not found!"); + + var code = ''; + + if(IS_PROD){ + code += ''; + code += ''; + }else{ + _.each(files.css, function(file){ + code += ''; + }); + _.each(files.js, function(file){ + code += ''; + }); + } + + return code; +} diff --git a/website/src/middleware.js b/website/src/middleware.js deleted file mode 100644 index d0e1579d6e..0000000000 --- a/website/src/middleware.js +++ /dev/null @@ -1,249 +0,0 @@ -var nconf = require('nconf'); -var _ = require('lodash'); -var fs = require('fs'); -var path = require('path'); -var User = require('./models/user').model -var limiter = require('connect-ratelimit'); -var logging = require('./logging'); -var domainMiddleware = require('domain-middleware'); -var cluster = require('cluster'); -var i18n = require('./i18n.js'); -var shared = require('../../common'); -var request = require('request'); -var os = require('os'); -var moment = require('moment'); -var utils = require('./utils'); - -var IS_PROD = nconf.get('NODE_ENV') === 'production'; -var BASE_URL = nconf.get("BASE_URL"); - -module.exports.apiThrottle = function(app) { - if (!IS_PROD) return; - app.use(limiter({ - end:false, - catagories:{ - normal: { - // 2 req/s, but split as minutes - totalRequests: 80, - every: 60000 - } - } - })).use(function(req,res,next){ - //logging.info(res.ratelimit); - if (res.ratelimit.exceeded) return res.json(429,{err:'Rate limit exceeded'}); - next(); - }); -} - -module.exports.domainMiddleware = function(server,mongoose) { - if (IS_PROD) { - var mins = 3, // how often to run this check - useAvg = false, // use average over 3 minutes, or simply the last minute's report - url = 'https://api.newrelic.com/v2/applications/'+nconf.get('NEW_RELIC_APPLICATION_ID')+'/metrics/data.json?names[]=Apdex&values[]=score'; - setInterval(function(){ - // see https://docs.newrelic.com/docs/apm/apis/api-v2-examples/average-response-time-examples-api-v2, https://rpm.newrelic.com/api/explore/applications/data - request({ - url: useAvg ? url+'&from='+moment().subtract({minutes:mins}).utc().format()+'&to='+moment().utc().format()+'&summarize=true' : url, - headers: {'X-Api-Key': nconf.get('NEW_RELIC_API_KEY')} - }, function(err, response, body){ - var ts = JSON.parse(body).metric_data.metrics[0].timeslices, - score = ts[ts.length-1].values.score, - apdexBad = score < .75 || score == 1, - memory = os.freemem() / os.totalmem(), - memoryHigh = memory < 0.1; - if (/*apdexBad || */memoryHigh) throw "[Memory Leak] Apdex="+score+" Memory="+parseFloat(memory).toFixed(3)+" Time="+moment().format(); - }) - }, mins*60*1000); - } - - return domainMiddleware({ - server: { - close:function(){ - server.close(); - mongoose.connection.close(); - } - }, - killTimeout: 10000 - }); -} - -module.exports.errorHandler = function(err, req, res, next) { - //res.locals.domain.emit('error', err); - // when we hit an error, send it to admin as an email. If no ADMIN_EMAIL is present, just send it to yourself (SMTP_USER) - var stack = (err.stack ? err.stack : err.message ? err.message : err) + - "\n ----------------------------\n" + - "\n\noriginalUrl: " + req.originalUrl + - "\n\nauth: " + req.headers['x-api-user'] + ' | ' + req.headers['x-api-key'] + - "\n\nheaders: " + JSON.stringify(req.headers) + - "\n\nbody: " + JSON.stringify(req.body) + - (res.locals.ops ? "\n\ncompleted ops: " + JSON.stringify(res.locals.ops) : ""); - logging.error(stack); - /*logging.loggly({ - error: "Uncaught error", - stack: (err.stack || err.message || err), - body: req.body, headers: req.header, - auth: req.headers['x-api-user'], - originalUrl: req.originalUrl - });*/ - var message = err.message ? err.message : err; - message = (message.length < 200) ? message : message.substring(0,100) + message.substring(message.length-100,message.length); - res.json(500,{err:message}); //res.end(err.message); -} - -function isHTTP(req) { - return ( - req.headers['x-forwarded-proto'] && - req.headers['x-forwarded-proto'] !== 'https' && - IS_PROD && - BASE_URL.indexOf('https') === 0 - ); -} - -function isProxied(req) { - return ( - req.headers['x-habitica-lb'] && - req.headers['x-habitica-lb'] === 'Yes' - ); -} - -module.exports.forceSSL = function(req, res, next){ - if(isHTTP(req) && !isProxied(req)) { - return res.redirect(BASE_URL + req.url); - } - - next(); -} - -// Redirect to habitica for non-api urls -// NOTE: Currently using a static 'habitica.com' string, rather than BASE_URL, -// to make rollback easy. Eventually, BASE_URL should be migrated. - -function nonApiUrl(req) { - return req.url.search(/\/api\//) === -1; -} - -module.exports.forceHabitica = function(req, res, next) { - var ignoreRedirect = nconf.get('IGNORE_REDIRECT'); - - if (IS_PROD && !ignoreRedirect && !isProxied(req) && nonApiUrl(req)) { - return res.redirect('https://habitica.com' + req.url); - } - next(); -}; - -module.exports.cors = function(req, res, next) { - res.header("Access-Control-Allow-Origin", req.headers.origin || "*"); - res.header("Access-Control-Allow-Methods", "OPTIONS,GET,POST,PUT,HEAD,DELETE"); - res.header("Access-Control-Allow-Headers", "Content-Type,Accept,Content-Encoding,X-Requested-With,x-api-user,x-api-key"); - if (req.method === 'OPTIONS') return res.send(200); - return next(); -}; - -var siteVersion = 1; - -module.exports.forceRefresh = function(req, res, next){ - if(req.query.siteVersion && req.query.siteVersion != siteVersion){ - return res.json(400, {needRefresh: true}); - } - - return next(); -}; - -var buildFiles = []; - -var walk = function(folder){ - var res = fs.readdirSync(folder); - - res.forEach(function(fileName){ - file = folder + '/' + fileName; - if(fs.statSync(file).isDirectory()){ - walk(file); - }else{ - var relFolder = path.relative(path.join(__dirname, "/../build"), folder); - var old = fileName.replace(/-.{8}(\.[\d\w]+)$/, '$1'); - - if(relFolder){ - old = relFolder + '/' + old; - fileName = relFolder + '/' + fileName; - } - - buildFiles[old] = fileName - } - }); -} - -walk(path.join(__dirname, "/../build")); - -var getBuildUrl = function(url){ - if(buildFiles[url]) return '/' + buildFiles[url]; - - return '/' + url; -} - -var manifestFiles = require("../public/manifest.json"); - -var getManifestFiles = function(page){ - var files = manifestFiles[page]; - - if(!files) throw new Error("Page not found!"); - - var code = ''; - - if(IS_PROD){ - code += ''; - code += ''; - }else{ - _.each(files.css, function(file){ - code += ''; - }); - _.each(files.js, function(file){ - code += ''; - }); - } - - return code; -} - -module.exports.locals = function(req, res, next) { - var language = _.find(i18n.avalaibleLanguages, {code: req.language}); - var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/' - - // 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')), - getManifestFiles: getManifestFiles, - getBuildUrl: getBuildUrl, - avalaibleLanguages: i18n.avalaibleLanguages, - language: language, - isStaticPage: isStaticPage, - translations: i18n.translations[language.code], - t: function(){ // stringName and vars are the allowed parameters - var args = Array.prototype.slice.call(arguments, 0); - args.push(language.code); - return shared.i18n.t.apply(null, args); - }, - siteVersion: siteVersion, - Content: shared.content, - mods: require('./models/user').mods, - tavern: tavern, // for world boss - worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {}, - _: _, - MP_ID: nconf.get('MP_ID'), - 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){} - - next(); -} diff --git a/website/src/middlewares/apiThrottle.js b/website/src/middlewares/apiThrottle.js new file mode 100644 index 0000000000..44acad4fa2 --- /dev/null +++ b/website/src/middlewares/apiThrottle.js @@ -0,0 +1,21 @@ +var nconf = require('nconf'); + +var IS_PROD = nconf.get('NODE_ENV') === 'production'; + +module.exports = function(app) { + if (!IS_PROD) return; + app.use(limiter({ + end:false, + catagories:{ + normal: { + // 2 req/s, but split as minutes + totalRequests: 80, + every: 60000 + } + } + })).use(function(req,res,next){ + //logging.info(res.ratelimit); + if (res.ratelimit.exceeded) return res.json(429,{err:'Rate limit exceeded'}); + next(); + }); +} diff --git a/website/src/middlewares/cors.js b/website/src/middlewares/cors.js new file mode 100644 index 0000000000..b694aff2af --- /dev/null +++ b/website/src/middlewares/cors.js @@ -0,0 +1,7 @@ +module.exports = function(req, res, next) { + res.header("Access-Control-Allow-Origin", req.headers.origin || "*"); + res.header("Access-Control-Allow-Methods", "OPTIONS,GET,POST,PUT,HEAD,DELETE"); + res.header("Access-Control-Allow-Headers", "Content-Type,Accept,Content-Encoding,X-Requested-With,x-api-user,x-api-key"); + if (req.method === 'OPTIONS') return res.send(200); + return next(); +}; diff --git a/website/src/middlewares/domain.js b/website/src/middlewares/domain.js new file mode 100644 index 0000000000..3178dc6188 --- /dev/null +++ b/website/src/middlewares/domain.js @@ -0,0 +1,39 @@ +var nconf = require('nconf'); +var moment = require('moment'); +var domainMiddleware = require('domain-middleware'); +var os = require('os'); +var request = require('request'); + +var IS_PROD = nconf.get('NODE_ENV') === 'production'; + +module.exports = function(server,mongoose) { + if (IS_PROD) { + var mins = 3, // how often to run this check + useAvg = false, // use average over 3 minutes, or simply the last minute's report + url = 'https://api.newrelic.com/v2/applications/'+nconf.get('NEW_RELIC_APPLICATION_ID')+'/metrics/data.json?names[]=Apdex&values[]=score'; + setInterval(function(){ + // see https://docs.newrelic.com/docs/apm/apis/api-v2-examples/average-response-time-examples-api-v2, https://rpm.newrelic.com/api/explore/applications/data + request({ + url: useAvg ? url+'&from='+moment().subtract({minutes:mins}).utc().format()+'&to='+moment().utc().format()+'&summarize=true' : url, + headers: {'X-Api-Key': nconf.get('NEW_RELIC_API_KEY')} + }, function(err, response, body){ + var ts = JSON.parse(body).metric_data.metrics[0].timeslices, + score = ts[ts.length-1].values.score, + apdexBad = score < .75 || score == 1, + memory = os.freemem() / os.totalmem(), + memoryHigh = memory < 0.1; + if (/*apdexBad || */memoryHigh) throw "[Memory Leak] Apdex="+score+" Memory="+parseFloat(memory).toFixed(3)+" Time="+moment().format(); + }) + }, mins*60*1000); + } + + return domainMiddleware({ + server: { + close:function(){ + server.close(); + mongoose.connection.close(); + } + }, + killTimeout: 10000 + }); +} diff --git a/website/src/middlewares/errorHandler.js b/website/src/middlewares/errorHandler.js new file mode 100644 index 0000000000..d07476e76f --- /dev/null +++ b/website/src/middlewares/errorHandler.js @@ -0,0 +1,24 @@ +var logging = require('../logging'); + +module.exports = function(err, req, res, next) { + //res.locals.domain.emit('error', err); + // when we hit an error, send it to admin as an email. If no ADMIN_EMAIL is present, just send it to yourself (SMTP_USER) + var stack = (err.stack ? err.stack : err.message ? err.message : err) + + "\n ----------------------------\n" + + "\n\noriginalUrl: " + req.originalUrl + + "\n\nauth: " + req.headers['x-api-user'] + ' | ' + req.headers['x-api-key'] + + "\n\nheaders: " + JSON.stringify(req.headers) + + "\n\nbody: " + JSON.stringify(req.body) + + (res.locals.ops ? "\n\ncompleted ops: " + JSON.stringify(res.locals.ops) : ""); + logging.error(stack); + /*logging.loggly({ + error: "Uncaught error", + stack: (err.stack || err.message || err), + body: req.body, headers: req.header, + auth: req.headers['x-api-user'], + originalUrl: req.originalUrl + });*/ + var message = err.message ? err.message : err; + message = (message.length < 200) ? message : message.substring(0,100) + message.substring(message.length-100,message.length); + res.json(500,{err:message}); //res.end(err.message); +} diff --git a/website/src/middlewares/forceRefresh.js b/website/src/middlewares/forceRefresh.js new file mode 100644 index 0000000000..e022aed2f6 --- /dev/null +++ b/website/src/middlewares/forceRefresh.js @@ -0,0 +1,9 @@ +module.exports.siteVersion = 1; + +module.exports.middleware = function(req, res, next){ + if(req.query.siteVersion && req.query.siteVersion != module.exports.siteVersion){ + return res.json(400, {needRefresh: true}); + } + + return next(); +}; diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js new file mode 100644 index 0000000000..c77fe6cd90 --- /dev/null +++ b/website/src/middlewares/locals.js @@ -0,0 +1,51 @@ +var nconf = require('nconf'); +var _ = require('lodash'); +var utils = require('../utils'); +var shared = require('../../../common'); +var i18n = require('../i18n.js'); +var buildManifest = require('../libs/buildManifest'); +var shared = require('../../../common'); +var forceRefresh = require('./forceRefresh'); + +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/' + + // 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')), + getManifestFiles: buildManifest.getManifestFiles, + getBuildUrl: buildManifest.getBuildUrl, + avalaibleLanguages: i18n.avalaibleLanguages, + language: language, + isStaticPage: isStaticPage, + translations: i18n.translations[language.code], + t: function(){ // stringName and vars are the allowed parameters + var args = Array.prototype.slice.call(arguments, 0); + args.push(language.code); + return shared.i18n.t.apply(null, args); + }, + siteVersion: forceRefresh.siteVersion, + Content: shared.content, + mods: require('../models/user').mods, + tavern: tavern, // for world boss + 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){} + + next(); +} diff --git a/website/src/middlewares/redirects.js b/website/src/middlewares/redirects.js new file mode 100644 index 0000000000..8a334c7401 --- /dev/null +++ b/website/src/middlewares/redirects.js @@ -0,0 +1,43 @@ +var nconf = require('nconf'); +var IS_PROD = nconf.get('NODE_ENV') === 'production'; +var ignoreRedirect = nconf.get('IGNORE_REDIRECT'); +var BASE_URL = nconf.get("BASE_URL"); + +function isHTTP(req) { + return ( + req.headers['x-forwarded-proto'] && + req.headers['x-forwarded-proto'] !== 'https' && + IS_PROD && + BASE_URL.indexOf('https') === 0 + ); +} + +function isProxied(req) { + return ( + req.headers['x-habitica-lb'] && + req.headers['x-habitica-lb'] === 'Yes' + ); +} + +module.exports.forceSSL = function(req, res, next){ + if(isHTTP(req) && !isProxied(req)) { + return res.redirect(BASE_URL + req.url); + } + + next(); +} + +// Redirect to habitica for non-api urls +// NOTE: Currently using a static 'habitica.com' string, rather than BASE_URL, +// to make rollback easy. Eventually, BASE_URL should be migrated. + +function nonApiUrl(req) { + return req.url.search(/\/api\//) === -1; +} + +module.exports.forceHabitica = function(req, res, next) { + if (IS_PROD && !ignoreRedirect && !isProxied(req) && nonApiUrl(req)) { + return res.redirect('https://habitica.com' + req.url); + } + next(); +}; diff --git a/website/src/routes/apiv1.js b/website/src/routes/apiv1.js index f37619f195..5a28ef8f3b 100644 --- a/website/src/routes/apiv1.js +++ b/website/src/routes/apiv1.js @@ -5,9 +5,9 @@ var async = require('async'); var icalendar = require('icalendar'); var api = require('./../controllers/user'); var auth = require('./../controllers/auth'); -var middleware = require('../middleware'); var logging = require('./../logging'); var i18n = require('./../i18n'); +var forceRefresh = require('../middlewares/forceRefresh').middleware; /* ---------- Deprecated API ------------*/ @@ -161,7 +161,7 @@ router.post('/user/task', auth.auth, i18n.getUserLanguage, cron, api.addTask); // User router.get('/user', auth.auth, i18n.getUserLanguage, cron, api.getUser); router.post('/user/revive', auth.auth, i18n.getUserLanguage, cron, api.revive); -router.post('/user/batch-update', middleware.forceRefresh, auth.auth, i18n.getUserLanguage, cron, batchUpdate); +router.post('/user/batch-update', forceRefresh, auth.auth, i18n.getUserLanguage, cron, batchUpdate); function deprecated(req, res) { res.json(404, {err:'API v1 is no longer supported, please use API v2 instead (https://github.com/HabitRPG/habitrpg/blob/develop/API.md)'}); diff --git a/website/src/routes/apiv2.coffee b/website/src/routes/apiv2.coffee index 947979c8c2..082db2efa6 100644 --- a/website/src/routes/apiv2.coffee +++ b/website/src/routes/apiv2.coffee @@ -16,12 +16,11 @@ hall = require("../controllers/hall") challenges = require("../controllers/challenges") dataexport = require("../controllers/dataexport") nconf = require("nconf") -middleware = require("../middleware") cron = user.cron _ = require('lodash') content = require('../../../common').content i18n = require('../i18n') - +forceRefresh = require('../middlewares/forceRefresh').middleware module.exports = (swagger, v2) -> [path,body,query] = [swagger.pathParam, swagger.bodyParam, swagger.queryParam] @@ -326,7 +325,7 @@ module.exports = (swagger, v2) -> parameters:[ body '','The array of batch-operations to perform','object' ] - middleware: [middleware.forceRefresh, auth.auth, i18n.getUserLanguage, cron, user.sessionPartyInvite] + middleware: [forceRefresh, auth.auth, i18n.getUserLanguage, cron, user.sessionPartyInvite] action: user.batchUpdate # Tags diff --git a/website/src/routes/dataexport.js b/website/src/routes/dataexport.js index ba27957124..9fc2ded323 100644 --- a/website/src/routes/dataexport.js +++ b/website/src/routes/dataexport.js @@ -4,13 +4,13 @@ var dataexport = require('../controllers/dataexport'); var auth = require('../controllers/auth'); var nconf = require('nconf'); var i18n = require('../i18n'); -var middleware = require('../middleware.js'); +var locals = require('../middlewares/locals'); /* Data export */ router.get('/history.csv',auth.authWithSession,i18n.getUserLanguage,dataexport.history); //[todo] encode data output options in the data controller and use these to build routes router.get('/userdata.xml',auth.authWithSession,i18n.getUserLanguage,dataexport.leanuser,dataexport.userdata.xml); router.get('/userdata.json',auth.authWithSession,i18n.getUserLanguage,dataexport.leanuser,dataexport.userdata.json); -router.get('/avatar-:uuid.html', i18n.getUserLanguage, middleware.locals, dataexport.avatarPage); -router.get('/avatar-:uuid.png', i18n.getUserLanguage, middleware.locals, dataexport.avatarImage); +router.get('/avatar-:uuid.html', i18n.getUserLanguage, locals, dataexport.avatarPage); +router.get('/avatar-:uuid.png', i18n.getUserLanguage, locals, dataexport.avatarImage); module.exports = router; diff --git a/website/src/routes/pages.js b/website/src/routes/pages.js index 4d72ad52ee..f3f59e3b9a 100644 --- a/website/src/routes/pages.js +++ b/website/src/routes/pages.js @@ -2,13 +2,13 @@ var nconf = require('nconf'); var express = require('express'); var router = new express.Router(); var _ = require('lodash'); -var middleware = require('../middleware'); +var locals = require('../middlewares/locals'); var user = require('../controllers/user'); var auth = require('../controllers/auth'); var i18n = require('../i18n'); // -------- App -------- -router.get('/', i18n.getUserLanguage, middleware.locals, function(req, res) { +router.get('/', i18n.getUserLanguage, locals, function(req, res) { if (!req.headers['x-api-user'] && !req.headers['x-api-key'] && !(req.session && req.session.userId)) return res.redirect('/static/front') @@ -23,7 +23,7 @@ router.get('/', i18n.getUserLanguage, middleware.locals, function(req, res) { var pages = ['front', 'privacy', 'terms', 'api', 'features', 'videos', 'contact', 'plans', 'new-stuff', 'community-guidelines', 'old-news', 'press-kit']; _.each(pages, function(name){ - router.get('/static/' + name, i18n.getUserLanguage, middleware.locals, function(req, res) { + router.get('/static/' + name, i18n.getUserLanguage, locals, function(req, res) { res.render('static/' + name, {env: res.locals.habitrpg}); }); }) diff --git a/website/src/server.js b/website/src/server.js index b108d13f2f..33bf720dcd 100644 --- a/website/src/server.js +++ b/website/src/server.js @@ -30,8 +30,6 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) { // Setup translations var i18n = require('./i18n'); - var middleware = require('./middleware'); - var TWO_WEEKS = 1000 * 60 * 60 * 24 * 14; var app = express(); var server = http.createServer(); @@ -89,16 +87,18 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) { var publicDir = path.join(__dirname, "/../public"); app.set("port", nconf.get('PORT')); - middleware.apiThrottle(app); - app.use(middleware.domainMiddleware(server,mongoose)); + require('./middlewares/apiThrottle')(app); + app.use(require('./middlewares/domain')(server,mongoose)); if (!isProd) app.use(express.logger("dev")); app.use(express.compress()); app.set("views", __dirname + "/../views"); app.set("view engine", "jade"); app.use(express.favicon(publicDir + '/favicon.ico')); - app.use(middleware.cors); - app.use(middleware.forceHabitica); - app.use(middleware.forceSSL); + app.use(require('./middlewares/cors')); + + var redirects = require('./middlewares/redirects'); + app.use(redirects.forceHabitica); + app.use(redirects.forceSSL); app.use(express.urlencoded()); app.use(express.json()); app.use(require('method-override')()); @@ -134,7 +134,7 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) { app.use('/api/v1', require('./routes/apiv1').middleware); app.use('/export', require('./routes/dataexport').middleware); require('./routes/apiv2.coffee')(swagger, v2); - app.use(middleware.errorHandler); + app.use(require('./middlewares/errorHandler')); server.on('request', app); server.listen(app.get("port"), function() { From 491652d712d7190a78c199a6f33dbd4d295099ae Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 12:00:09 +0200 Subject: [PATCH 40/56] fix several typypos and a missing dep --- website/src/libs/buildManifest.js | 13 +++++-------- website/src/middlewares/apiThrottle.js | 3 ++- website/src/middlewares/domain.js | 4 ++-- website/src/middlewares/errorHandler.js | 2 +- website/src/middlewares/locals.js | 4 ++-- website/src/middlewares/redirects.js | 4 ++-- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/website/src/libs/buildManifest.js b/website/src/libs/buildManifest.js index ac4c35d19b..e2b337860f 100644 --- a/website/src/libs/buildManifest.js +++ b/website/src/libs/buildManifest.js @@ -9,10 +9,9 @@ var buildFiles = []; var walk = function(folder){ var res = fs.readdirSync(folder); - var files = []; res.forEach(function(fileName){ - file = folder + '/' + fileName; + var file = folder + '/' + fileName; if(fs.statSync(file).isDirectory()){ walk(file); }else{ @@ -24,12 +23,10 @@ var walk = function(folder){ fileName = relFolder + '/' + fileName; } - buildFiles[old] = fileName + buildFiles[old] = fileName; } }); - - return files; -} +}; walk(path.join(__dirname, "/../../build")); @@ -37,7 +34,7 @@ var getBuildUrl = module.exports.getBuildUrl = function(url){ if(buildFiles[url]) return '/' + buildFiles[url]; return '/' + url; -} +}; module.exports.getManifestFiles = function(page){ var files = manifestFiles[page]; @@ -59,4 +56,4 @@ module.exports.getManifestFiles = function(page){ } return code; -} +}; \ No newline at end of file diff --git a/website/src/middlewares/apiThrottle.js b/website/src/middlewares/apiThrottle.js index 44acad4fa2..b90f6861ea 100644 --- a/website/src/middlewares/apiThrottle.js +++ b/website/src/middlewares/apiThrottle.js @@ -1,4 +1,5 @@ var nconf = require('nconf'); +var limiter = require('connect-ratelimit'); var IS_PROD = nconf.get('NODE_ENV') === 'production'; @@ -18,4 +19,4 @@ module.exports = function(app) { if (res.ratelimit.exceeded) return res.json(429,{err:'Rate limit exceeded'}); next(); }); -} +}; \ No newline at end of file diff --git a/website/src/middlewares/domain.js b/website/src/middlewares/domain.js index 3178dc6188..e62c478797 100644 --- a/website/src/middlewares/domain.js +++ b/website/src/middlewares/domain.js @@ -23,7 +23,7 @@ module.exports = function(server,mongoose) { memory = os.freemem() / os.totalmem(), memoryHigh = memory < 0.1; if (/*apdexBad || */memoryHigh) throw "[Memory Leak] Apdex="+score+" Memory="+parseFloat(memory).toFixed(3)+" Time="+moment().format(); - }) + }); }, mins*60*1000); } @@ -36,4 +36,4 @@ module.exports = function(server,mongoose) { }, killTimeout: 10000 }); -} +}; diff --git a/website/src/middlewares/errorHandler.js b/website/src/middlewares/errorHandler.js index d07476e76f..eebf25ac6b 100644 --- a/website/src/middlewares/errorHandler.js +++ b/website/src/middlewares/errorHandler.js @@ -21,4 +21,4 @@ module.exports = function(err, req, res, next) { var message = err.message ? err.message : err; message = (message.length < 200) ? message : message.substring(0,100) + message.substring(message.length-100,message.length); res.json(500,{err:message}); //res.end(err.message); -} +}; diff --git a/website/src/middlewares/locals.js b/website/src/middlewares/locals.js index c77fe6cd90..fa693895c1 100644 --- a/website/src/middlewares/locals.js +++ b/website/src/middlewares/locals.js @@ -44,8 +44,8 @@ module.exports = function(req, res, next) { // 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)) + req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)); } catch(e){} next(); -} +}; \ No newline at end of file diff --git a/website/src/middlewares/redirects.js b/website/src/middlewares/redirects.js index 8a334c7401..25b8d44fa9 100644 --- a/website/src/middlewares/redirects.js +++ b/website/src/middlewares/redirects.js @@ -25,7 +25,7 @@ module.exports.forceSSL = function(req, res, next){ } next(); -} +}; // Redirect to habitica for non-api urls // NOTE: Currently using a static 'habitica.com' string, rather than BASE_URL, @@ -40,4 +40,4 @@ module.exports.forceHabitica = function(req, res, next) { return res.redirect('https://habitica.com' + req.url); } next(); -}; +}; \ No newline at end of file From ca457df36a04b50280921deb42af47f1304ae9b8 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 12:23:10 +0200 Subject: [PATCH 41/56] fix typo catatories -> categories --- website/src/middlewares/apiThrottle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/middlewares/apiThrottle.js b/website/src/middlewares/apiThrottle.js index b90f6861ea..5a863c1fb7 100644 --- a/website/src/middlewares/apiThrottle.js +++ b/website/src/middlewares/apiThrottle.js @@ -7,7 +7,7 @@ module.exports = function(app) { if (!IS_PROD) return; app.use(limiter({ end:false, - catagories:{ + categories:{ normal: { // 2 req/s, but split as minutes totalRequests: 80, From 34dd4494ec6fe7a9d98de237769444f71c9d0891 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 13:10:53 +0200 Subject: [PATCH 42/56] 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 576688c15bbddd7e3106211c7bbe52f5fb0768f6 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 14 Aug 2015 06:41:10 -0500 Subject: [PATCH 43/56] Clean up content file --- common/script/content.coffee | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/common/script/content.coffee b/common/script/content.coffee index d99046a770..da39a203a3 100644 --- a/common/script/content.coffee +++ b/common/script/content.coffee @@ -549,8 +549,20 @@ api.timeTravelerStore = (owned) -> --------------------------------------------------------------- ### -api.potion = type: 'potion', text: t('potionText'), notes: t('potionNotes'), value: 25, key: 'potion' -api.armoire = type: 'armoire', text: t('armoireText'), notes: t('armoireNotesEmpty'), value: 100, key: 'armoire', canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true)) +api.potion = + type: 'potion', + text: t('potionText'), + notes: t('potionNotes'), + value: 25, + key: 'potion' + +api.armoire = + type: 'armoire', + text: t('armoireText'), + notes: t('armoireNotesEmpty'), + value: 100, + key: 'armoire', + canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true)) ### --------------------------------------------------------------- @@ -1003,8 +1015,8 @@ api.spells = target.flags.cardReceived = true target.markModified? 'items.special.thankyouReceived' - user.stats.gp -= 10 - + user.stats.gp -= 10 + api.cardTypes = greeting: key: 'greeting' @@ -1958,7 +1970,7 @@ api.quests = gp: 37 exp: 275 unlock: t('questWhaleUnlockText') - + dilatoryDistress1: text: t('questDilatoryDistress1Text') notes: t('questDilatoryDistress1Notes') @@ -2177,7 +2189,7 @@ api.backgrounds = text: t('backgroundSunkenShipText') notes: t('backgroundSunkenShipNotes') backgrounds082015: - pyramids: + pyramids: text: t('backgroundPyramidsText') notes: t('backgroundPyramidsNotes') sunset_savannah: From 6be339fc7716b08f3d41670966cb32670f5c5975 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 14 Aug 2015 06:59:23 -0500 Subject: [PATCH 44/56] Fix bug where armoire notes would not display correctly --- common/script/content.coffee | 5 ++++- website/views/shared/tasks/task_view/static_rewards.jade | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/common/script/content.coffee b/common/script/content.coffee index da39a203a3..7416bd8948 100644 --- a/common/script/content.coffee +++ b/common/script/content.coffee @@ -559,7 +559,10 @@ api.potion = api.armoire = type: 'armoire', text: t('armoireText'), - notes: t('armoireNotesEmpty'), + notes: ((user, count)-> + return t('armoireNotesEmpty')() if (user.flags.armoireEmpty) + return t('armoireNotesFull')() + count + ), value: 100, key: 'armoire', canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true)) diff --git a/website/views/shared/tasks/task_view/static_rewards.jade b/website/views/shared/tasks/task_view/static_rewards.jade index 7fad52176c..3ce7ab78b8 100644 --- a/website/views/shared/tasks/task_view/static_rewards.jade +++ b/website/views/shared/tasks/task_view/static_rewards.jade @@ -19,4 +19,5 @@ mixin reward(item) ul.items.rewards(ng-if='main && list.type=="reward"') +reward('item')(ng-repeat='item in itemStore') +reward('healthPotion') - +reward('armoire')(ng-if='user.flags.armoireEnabled') + +reward('armoire')(ng-if='user.flags.armoireEnabled', + popover='{{armoire.notes(user, armoireCount(user.items.gear.owned))}}') From 998e33681839324ccbc3673a9fbdd8dbcdbee849 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 14 Aug 2015 07:40:07 -0500 Subject: [PATCH 45/56] Remove extraneous white space --- common/script/public/directives.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/script/public/directives.js b/common/script/public/directives.js index fadcbca18b..2af15ff070 100644 --- a/common/script/public/directives.js +++ b/common/script/public/directives.js @@ -124,7 +124,7 @@ if(removeWatch) { - doRemoveWatch(); + doRemoveWatch(); } }; @@ -144,9 +144,9 @@ habitrpg.filter('markdown', function() { return function(input){ var html = md.toHtml(input); - + html = html.replace(' href',' target="_self" href'); - + return html; }; }); From e1620bad2baa7e4033ecbf4f24fad45492caf587 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 14:53:17 +0200 Subject: [PATCH 46/56] 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 47/56] 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 48/56] 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 80ba33bf7cdafb9e3a5de15e6f7b171ac7665cdf Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 14 Aug 2015 08:13:05 -0500 Subject: [PATCH 49/56] Fix issue where card strings required quotes --- website/views/shared/modals/limited.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views/shared/modals/limited.jade b/website/views/shared/modals/limited.jade index b993301ad3..158fd5a647 100644 --- a/website/views/shared/modals/limited.jade +++ b/website/views/shared/modals/limited.jade @@ -6,7 +6,7 @@ script(id='modals/cards.html', type='text/ng-template') .bg-info(style='padding:10px') p {{::env.t('toAndFromCard', { toName: user.profile.name, fromName: user.items.special[cardType + 'Received'][0]})}} hr - markdown(text='{{::cardMessage}}') + markdown(text='::cardMessage') .modal-footer small.pull-left {{::env.t(cardType + 'CardExplanation')}} button.btn.btn-default(ng-click='user.ops.readCard({params: {cardType: cardType}}); $close()')=env.t('ok') From 59d4d9706ad039851a331b4438d7dec8ec7ebb26 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Fri, 14 Aug 2015 08:13:25 -0500 Subject: [PATCH 50/56] Remove quotes from card strings --- common/locales/en/generic.json | 16 ++++++++-------- common/locales/en/limited.json | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/common/locales/en/generic.json b/common/locales/en/generic.json index c0600db04d..10ded61ab5 100644 --- a/common/locales/en/generic.json +++ b/common/locales/en/generic.json @@ -116,19 +116,19 @@ "greetingCard": "Greeting Card", "greetingCardExplanation": "You both receive the Cheery Chum achievement!", "greetingCardNotes": "Send a greeting card to a party member.", - "greeting0": "\"Hi there!\"", - "greeting1": "\"Just saying hello :)\"", - "greeting2": "\"`waves frantically`\"", - "greeting3": "\"Hey you!\"", + "greeting0": "Hi there!", + "greeting1": "Just saying hello :)", + "greeting2": "`waves frantically`", + "greeting3": "Hey you!", "cheeryChum": "Cheery Chum", "cheeryChumText": "Hey! Hi! Hello! Sent or received <%= cards %> greeting cards.", "thankyouCard": "Thank-You Card", "thankyouCardExplanation": "You both receive the Greatly Grateful achievement!", "thankyouCardNotes": "Send a Thank-You card to a party member.", - "thankyou0": "\"Thank you very much!\"", - "thankyou1": "\"Thank you, thank you, thank you!\"", - "thankyou2": "\"Sending you a thousand thanks.\"", - "thankyou3": "\"I'm very grateful - thank you!\"", + "thankyou0": "Thank you very much!", + "thankyou1": "Thank you, thank you, thank you!", + "thankyou2": "Sending you a thousand thanks.", + "thankyou3": "I'm very grateful - thank you!", "greatlyGrateful": "Greatly Grateful", "greatlyGratefulText": "Thanks for being thankful! Sent or received <%= cards %> Thank-You cards." } diff --git a/common/locales/en/limited.json b/common/locales/en/limited.json index 8ebf0b6151..0f84ac8f10 100644 --- a/common/locales/en/limited.json +++ b/common/locales/en/limited.json @@ -41,11 +41,11 @@ "seasonalItems": "Seasonal Items", "auldAcquaintance": "Auld Acquaintance", "auldAcquaintanceText": "Happy New Year! Sent or received <%= cards %> New Year's cards.", - "nye0": "\"Happy New Year! May you slay many a bad Habit.\"", - "nye1": "\"Happy New Year! May you reap many Rewards.\"", - "nye2": "\"Happy New Year! May you earn many a Perfect Day.\"", - "nye3": "\"Happy New Year! May your To-Do list stay short and sweet.\"", - "nye4": "\"Happy New Year! May you not get attacked by a raging Hippogriff.\"", + "nye0": "Happy New Year! May you slay many a bad Habit.", + "nye1": "Happy New Year! May you reap many Rewards.", + "nye2": "Happy New Year! May you earn many a Perfect Day.", + "nye3": "Happy New Year! May your To-Do list stay short and sweet.", + "nye4": "Happy New Year! May you not get attacked by a raging Hippogriff.", "holidayCard": "Received a holiday card!", "mightyBunnySet": "Mighty Bunny (Warrior)", "magicMouseSet": "Magic Mouse (Mage)", From dc4c6fa6e7c08c9d4a3e67be4e7881422a4a6b1d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Aug 2015 15:21:17 +0200 Subject: [PATCH 51/56] 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 52/56] 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 53/56] 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 54/56] 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 55/56] 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 56/56] 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); });