diff --git a/.eslintignore b/.eslintignore index 250640f954..3278600389 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,4 @@ node_modules/ -public/src/nodebb.min.js *.sublime-project *.sublime-workspace .project @@ -10,8 +9,6 @@ logs/ /public/uploads /public/sounds /public/vendor -/public/nodebb.min.js -/public/acp.min.js /public/src/modules/string.js .idea/ .vscode/ @@ -19,3 +16,4 @@ logs/ *.iws /coverage /build +.eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..52211a126d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,128 @@ +{ + "extends": "airbnb-base", + "parserOptions": { + "sourceType": "script" + }, + + "rules": { + // Customized + "handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ], + "comma-dangle": ["error", { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "never" + }], + "no-empty": ["error", { "allowEmptyCatch": true }], + "no-underscore-dangle": "off", + "newline-per-chained-call": "off", + "no-console": "off", + "no-mixed-operators": ["error", { "allowSamePrecedence": true }], + "strict": ["error", "global"], + "consistent-return": "off", + "func-names": "off", + "no-tabs": "off", + "indent": ["error", "tab"], + "no-eq-null": "off", + "camelcase": "off", + "no-new": "off", + "no-shadow": "off", + "no-use-before-define": ["error", "nofunc"], + "no-prototype-builtins": "off", + "new-cap": "off", + "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], + + // ES6 + "prefer-rest-params": "off", + "prefer-spread": "off", + "prefer-arrow-callback": "off", + "prefer-template": "off", + "no-var": "off", + "object-shorthand": "off", + "vars-on-top": "off", + + // TODO + "import/no-unresolved": "off", + "import/no-extraneous-dependencies": "off", + "import/no-dynamic-require": "off", + "import/newline-after-import": "off", + "no-bitwise": "off", + "global-require": "off", + "max-len": "off", + "no-param-reassign": "off", + "no-restricted-syntax": "off", + "no-script-url": "off", + "default-case": "off", + + // "no-multi-assign": "off", + // "linebreak-style": "off", + // "one-var": "off", + // "no-undef": "off", + // "max-nested-callbacks": "off", + // "no-mixed-requires": "off", + // "brace-style": "off", + // "max-statements-per-line": "off", + // "no-unused-vars": "off", + // "no-mixed-spaces-and-tabs": "off", + // "no-useless-concat": "off", + // "require-jsdoc": "off", + // "eqeqeq": "off", + // "no-negated-condition": "off", + // "one-var-declaration-per-line": "off", + // "no-lonely-if": "off", + // "radix": "off", + // "no-else-return": "off", + // "no-useless-escape": "off", + // "block-scoped-var": "off", + // "operator-assignment": "off", + // "yoda": "off", + // "no-loop-func": "off", + // "no-void": "off", + // "valid-jsdoc": "off", + // "no-cond-assign": "off", + // "no-redeclare": "off", + // "no-unreachable": "off", + // "no-nested-ternary": "off", + // "operator-linebreak": "off", + // "guard-for-in": "off", + // "no-unneeded-ternary": "off", + // "no-sequences": "off", + // "no-extend-native": "off", + // "no-shadow-restricted-names": "off", + // "no-extra-boolean-cast": "off", + // "no-path-concat": "off", + // "no-unused-expressions": "off", + // "no-return-assign": "off", + // "no-restricted-modules": "off", + // "object-curly-spacing": "off", + // "indent": "off", + // "padded-blocks": "off", + // "eol-last": "off", + // "lines-around-directive": "off", + // "strict": "off", + // "comma-dangle": "off", + // "no-multi-spaces": "off", + // "quotes": "off", + // "keyword-spacing": "off", + // "no-mixed-operators": "off", + // "comma-spacing": "off", + // "no-trailing-spaces": "off", + // "key-spacing": "off", + // "no-multiple-empty-lines": "off", + // "spaced-comment": "off", + // "space-in-parens": "off", + // "block-spacing": "off", + // "quote-props": "off", + // "space-unary-ops": "off", + // "no-empty": "off", + // "dot-notation": "off", + // "func-call-spacing": "off", + // "array-bracket-spacing": "off", + // "object-property-newline": "off", + // "no-continue": "off", + // "no-extra-semi": "off", + // "no-spaced-func": "off", + // "no-useless-return": "off" + } +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index f64256f73d..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "extends": "airbnb", - - "rules": { - "handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ], - "linebreak-style": "off", - "import/no-unresolved": "off", - "import/no-extraneous-dependencies": "off", - "one-var": "off", - "no-undef": "off", - "max-len": "off", - "no-new": "off", - "max-nested-callbacks": "off", - "no-mixed-requires": "off", - "brace-style": "off", - "max-statements-per-line": "off", - "no-unused-vars": "off", - "no-mixed-spaces-and-tabs": "off", - "no-useless-concat": "off", - "require-jsdoc": "off", - "eqeqeq": "off", - "camelcase": "off", - "no-negated-condition": "off", - "one-var-declaration-per-line": "off", - "new-cap": "off", - "no-lonely-if": "off", - "radix": "off", - "no-else-return": "off", - "no-useless-escape": "off", - "block-scoped-var": "off", - "operator-assignment": "off", - "default-case": "off", - "yoda": "off", - "no-use-before-define": "off", - "no-loop-func": "off", - "no-void": "off", - "valid-jsdoc": "off", - "o-eq-null": "off", - "no-cond-assign": "off", - "no-eq-null": "off", - "no-redeclare": "off", - "no-unreachable": "off", - "no-nested-ternary": "off", - "operator-linebreak": "off", - "guard-for-in": "off", - "no-unneeded-ternary": "off", - "no-sequences": "off", - "no-extend-native": "off", - "no-shadow-restricted-names": "off", - "no-extra-boolean-cast": "off", - "no-script-url": "off", - "no-path-concat": "off", - "no-unused-expressions": "off", - "no-restricted-module": "off", - "no-return-assign": "off", - "no-restricted-modules": "off", - "no-tabs": "off", - "indent": "off", - "func-names": "off", - "prefer-arrow-callback": "off", - "object-curly-spacing": "off", - "no-var": "off", - "no-shadow": "off", - "prefer-template": "off", - "padded-blocks": "off", - "eol-last": "off", - "lines-around-directive": "off", - "no-restricted-syntax": "off", - "vars-on-top": "off", - "no-prototype-builtins": "off", - "object-shorthand": "off", - "no-param-reassign": "off", - "consistent-return": "off", - "strict": "off", - "comma-dangle": "off", - "no-multi-spaces": "off", - "quotes": "off", - "keyword-spacing": "off", - "no-plusplus": "off", - "no-mixed-operators": "off", - "comma-spacing": "off", - "global-require": "off", - "no-trailing-spaces": "off", - "key-spacing": "off", - "import/newline-after-import": "off", - "no-underscore-dangle": "off", - "prefer-spread": "off", - "no-multiple-empty-lines": "off", - "spaced-comment": "off", - "prefer-rest-params": "off", - "space-in-parens": "off", - "block-spacing": "off", - "quote-props": "off", - "no-console": "off", - "space-unary-ops": "off", - "import/no-dynamic-require": "off", - "no-bitwise": "off", - "no-empty": "off", - "array-bracket-spacin": "off", - "dot-notation": "off", - "func-call-spacing": "off", - "newline-per-chained-call": "off", - "newline-per-chained-call": "off", - "array-bracket-spacing": "off", - "object-property-newline": "off", - "no-continue": "off", - "no-extra-semi": "off", - "no-spaced-func": "off", - "no-useless-return": "off" - } -} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5098d7d39a..6d5e4f1201 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,10 @@ # Submitting a Pull Request to NodeBB? -First of all, thank you! Please consider this [style guide](https://docs.nodebb.org/en/latest/contributing/style-guide.html) when submitting your changes. Also, please join our [community](https://community.nodebb.org) to meet other NodeBB developers and designers :) +First of all, thank you! Before submission, please run `npm test` to lint and run the automated NodeBB tests. If everything passes, you're good to go. If you have any errors, please fix them and re-run `npm test` to make sure there aren't any others. + +## Styleguide and linting + +NodeBB mostly conforms to the [AirBnB Javascript style guide](https://github.com/airbnb/javascript#readme). If you're running into a lot of ESlint errors, you may want to install an editor plugin to display them in real time. ## Contributor License Agreement @@ -51,12 +55,13 @@ $ git rev-parse HEAD If you have downloaded the `.zip` or `.tar.gz` packages from GitHub (or elsewhere), please let us know. ## Provide theme versions if issue is related to the theme/display +Use `npm ls` to list the versions of the theme you're using. In this example, we're running the Persona theme, which depends on the Vanilla theme. ``` bash -$ npm ls nodebb-theme-vanilla nodebb-theme-lavender -nodebb@0.7.0-dev /home/julian/Projects/nodebb/forum -├── nodebb-theme-lavender@0.2.13 -└── nodebb-theme-vanilla@0.2.35 +$ npm ls nodebb-theme-vanilla nodebb-theme-persona +nodebb@1.4.3 /path/to/nodebb ++-- nodebb-theme-persona@4.2.4 +`-- nodebb-theme-vanilla@5.2.0 ``` ## Attempt to use `git bisect` diff --git a/.gitignore b/.gitignore index b5ff54d664..dcda0224fc 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,4 @@ tx.exe coverage build +*.log diff --git a/Gruntfile.js b/Gruntfile.js index f3c4f1723e..c97795e743 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,8 +1,10 @@ -"use strict"; +'use strict'; var fork = require('child_process').fork; var env = process.env; -var worker, updateWorker, initWorker; +var worker; +var updateWorker; +var initWorker; var incomplete = []; var running = 0; @@ -44,15 +46,13 @@ module.exports = function (grunt) { if (updateWorker) { updateWorker.kill('SIGKILL'); } - updateWorker = fork('app.js', updateArgs, { - env: env - }); - ++running; + updateWorker = fork('app.js', updateArgs, { env: env }); + running += 1; updateWorker.on('exit', function () { - --running; + running -= 1; if (running === 0) { worker = fork('app.js', args, { - env: env + env: env, }); worker.on('message', function () { if (incomplete.length) { @@ -74,17 +74,17 @@ module.exports = function (grunt) { 'public/*.less', 'node_modules/nodebb-*/*.less', 'node_modules/nodebb-*/**/*.less', '!node_modules/nodebb-*/node_modules/**', - '!node_modules/nodebb-*/.git/**' + '!node_modules/nodebb-*/.git/**', ], options: { - interval: 1000 - } + interval: 1000, + }, }, lessUpdated_Admin: { files: ['public/**/*.less'], options: { - interval: 1000 - } + interval: 1000, + }, }, clientUpdated: { files: [ @@ -92,28 +92,28 @@ module.exports = function (grunt) { 'node_modules/nodebb-*/*.js', 'node_modules/nodebb-*/**/*.js', '!node_modules/nodebb-*/node_modules/**', 'node_modules/templates.js/lib/templates.js', - '!node_modules/nodebb-*/.git/**' + '!node_modules/nodebb-*/.git/**', ], options: { - interval: 1000 - } + interval: 1000, + }, }, serverUpdated: { files: ['*.js', 'install/*.js', 'src/**/*.js'], options: { - interval: 1000 - } + interval: 1000, + }, }, templatesUpdated: { files: [ 'src/views/**/*.tpl', 'node_modules/nodebb-*/*.tpl', 'node_modules/nodebb-*/**/*.tpl', '!node_modules/nodebb-*/node_modules/**', - '!node_modules/nodebb-*/.git/**' + '!node_modules/nodebb-*/.git/**', ], options: { - interval: 1000 - } + interval: 1000, + }, }, langUpdated: { files: [ @@ -127,10 +127,10 @@ module.exports = function (grunt) { '!node_modules/nodebb-*/theme.json', ], options: { - interval: 1000 - } + interval: 1000, + }, }, - } + }, }); grunt.loadNpmTasks('grunt-contrib-watch'); @@ -140,16 +140,16 @@ module.exports = function (grunt) { if (grunt.option('skip')) { worker = fork('app.js', args, { - env: env + env: env, }); } else { initWorker = fork('app.js', initArgs, { - env: env + env: env, }); initWorker.on('exit', function () { worker = fork('app.js', args, { - env: env + env: env, }); }); } diff --git a/app.js b/app.js index 57c57d61b6..de9d417045 100644 --- a/app.js +++ b/app.js @@ -17,8 +17,7 @@ along with this program. If not, see . */ -"use strict"; -/*global require, global, process*/ +'use strict'; var nconf = require('nconf'); nconf.argv().env('__'); @@ -37,11 +36,11 @@ winston.add(winston.transports.Console, { colorize: true, timestamp: function () { var date = new Date(); - return (!!nconf.get('json-logging')) ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,8) + ' [' + global.process.pid + ']'; + return nconf.get('json-logging') ? date.toJSON() : date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 8) + ' [' + global.process.pid + ']'; }, level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'), json: (!!nconf.get('json-logging')), - stringify: (!!nconf.get('json-logging')) + stringify: (!!nconf.get('json-logging')), }); @@ -75,7 +74,7 @@ if (nconf.get('setup') || nconf.get('install')) { } else if (nconf.get('reset')) { async.waterfall([ async.apply(require('./src/reset').reset), - async.apply(require('./src/meta/build').buildAll) + async.apply(require('./src/meta/build').buildAll), ], function (err) { process.exit(err ? 1 : 0); }); @@ -93,7 +92,7 @@ function loadConfig(callback) { winston.verbose('* using configuration stored in: %s', configFile); nconf.file({ - file: configFile + file: configFile, }); nconf.defaults({ @@ -101,7 +100,7 @@ function loadConfig(callback) { themes_path: path.join(__dirname, 'node_modules'), upload_path: 'public/uploads', views_dir: path.join(__dirname, 'build/public/templates'), - version: pkg.version + version: pkg.version, }); if (!nconf.get('isCluster')) { @@ -113,7 +112,7 @@ function loadConfig(callback) { nconf.set('themes_path', path.resolve(__dirname, nconf.get('themes_path'))); nconf.set('core_templates_path', path.join(__dirname, 'src/views')); nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); - + nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path'))); if (nconf.get('url')) { @@ -149,14 +148,14 @@ function setup() { async.series([ async.apply(install.setup), async.apply(loadConfig), - async.apply(build.buildAll) + async.apply(build.buildAll), ], function (err, data) { // Disregard build step data data = data[0]; var separator = ' '; if (process.stdout.columns > 10) { - for(var x = 0,cols = process.stdout.columns - 10; x < cols; x++) { + for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) { separator += '='; } } @@ -194,7 +193,7 @@ function upgrade() { async.apply(db.init), async.apply(meta.configs.init), async.apply(upgrade.upgrade), - async.apply(build.buildAll) + async.apply(build.buildAll), ], function (err) { if (err) { winston.error(err.stack); diff --git a/bcrypt.js b/bcrypt.js index 4040aa2a8f..40a493e75d 100644 --- a/bcrypt.js +++ b/bcrypt.js @@ -1,8 +1,8 @@ 'use strict'; -var bcrypt = require('bcryptjs'), - async = require('async'); +var bcrypt = require('bcryptjs'); +var async = require('async'); process.on('message', function (msg) { @@ -20,15 +20,15 @@ function hashPassword(password, rounds) { }, function (salt, next) { bcrypt.hash(password, salt, next); - } + }, ], done); } function done(err, result) { if (err) { - process.send({err: err.message}); + process.send({ err: err.message }); return process.disconnect(); } - process.send({result: result}); + process.send({ result: result }); process.disconnect(); -} \ No newline at end of file +} diff --git a/install/databases.js b/install/databases.js index c314ad75ef..6a8d68d633 100644 --- a/install/databases.js +++ b/install/databases.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var prompt = require('prompt'); @@ -6,7 +6,7 @@ var winston = require('winston'); var questions = { redis: require('../src/database/redis').questions, - mongo: require('../src/database/mongo').questions + mongo: require('../src/database/mongo').questions, }; module.exports = function (config, callback) { @@ -18,7 +18,7 @@ module.exports = function (config, callback) { }, function (databaseConfig, next) { saveDatabaseConfig(config, databaseConfig, next); - } + }, ], callback); }; @@ -55,7 +55,7 @@ function saveDatabaseConfig(config, databaseConfig, callback) { host: databaseConfig['redis:host'], port: databaseConfig['redis:port'], password: databaseConfig['redis:password'], - database: databaseConfig['redis:database'] + database: databaseConfig['redis:database'], }; if (config.redis.host.slice(0, 1) === '/') { @@ -67,16 +67,16 @@ function saveDatabaseConfig(config, databaseConfig, callback) { port: databaseConfig['mongo:port'], username: databaseConfig['mongo:username'], password: databaseConfig['mongo:password'], - database: databaseConfig['mongo:database'] + database: databaseConfig['mongo:database'], }; } else { return callback(new Error('unknown database : ' + config.database)); } var allQuestions = questions.redis.concat(questions.mongo); - for (var x = 0; x < allQuestions.length; x++) { + for (var x = 0; x < allQuestions.length; x += 1) { delete config[allQuestions[x].name]; } callback(null, config); -} \ No newline at end of file +} diff --git a/install/web.js b/install/web.js index 1bac1577d0..88b2495614 100644 --- a/install/web.js +++ b/install/web.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var winston = require('winston'); var express = require('express'); @@ -17,9 +17,9 @@ winston.add(winston.transports.File, { colorize: true, timestamp: function () { var date = new Date(); - return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0,5) + ' [' + global.process.pid + ']'; + return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + date.toTimeString().substr(0, 5) + ' [' + global.process.pid + ']'; }, - level: 'verbose' + level: 'verbose', }); var web = {}; @@ -27,7 +27,7 @@ var scripts = [ 'public/vendor/xregexp/xregexp.js', 'public/vendor/xregexp/unicode/unicode-base.js', 'public/src/utils.js', - 'public/src/installer/install.js' + 'public/src/installer/install.js', ]; web.install = function (port) { @@ -39,7 +39,7 @@ web.install = function (port) { app.set('view engine', 'tpl'); app.set('views', path.join(__dirname, '../src/views')); app.use(bodyParser.urlencoded({ - extended: true + extended: true, })); async.parallel([compileLess, compileJS], function () { @@ -66,7 +66,7 @@ function welcome(req, res) { var databases = dbs.map(function (el) { return { name: el, - questions: require('../src/database/' + el).questions + questions: require('../src/database/' + el).questions, }; }); @@ -75,10 +75,10 @@ function welcome(req, res) { res.render('install/index', { databases: databases, skipDatabaseSetup: !!nconf.get('database'), - error: res.locals.error ? true : false, - success: res.locals.success ? true : false, + error: !!res.locals.error, + success: !!res.locals.success, values: req.body, - minimumPasswordLength: defaults.minimumPasswordLength + minimumPasswordLength: defaults.minimumPasswordLength, }); } @@ -90,7 +90,7 @@ function install(req, res) { } var child = require('child_process').fork('app', ['--setup'], { - env: process.env + env: process.env, }); child.on('close', function (data) { @@ -110,7 +110,7 @@ function launch(req, res) { var child = require('child_process').spawn('node', ['loader.js'], { detached: true, - stdio: ['ignore', 'ignore', 'ignore'] + stdio: ['ignore', 'ignore', 'ignore'], }); process.stdout.write('\nStarting NodeBB\n'); @@ -120,7 +120,7 @@ function launch(req, res) { async.parallel([ async.apply(fs.unlink(path.join(__dirname, '../public/installer.css'))), - async.apply(fs.unlink(path.join(__dirname, '../public/installer.min.js'))) + async.apply(fs.unlink(path.join(__dirname, '../public/installer.min.js'))), ], function (err) { if (err) { winston.warn('Unable to remove installer files'); @@ -138,7 +138,7 @@ function compileLess(callback) { } less.render(style.toString(), function (err, css) { - if(err) { + if (err) { return winston.error('Unable to compile LESS: ', err); } @@ -157,4 +157,4 @@ function compileJS(callback) { fs.writeFile(path.join(__dirname, '../public/installer.min.js'), result.code, callback); } -module.exports = web; \ No newline at end of file +module.exports = web; diff --git a/loader.js b/loader.js index 592a15c490..654d77fb23 100644 --- a/loader.js +++ b/loader.js @@ -1,29 +1,28 @@ 'use strict'; -var nconf = require('nconf'), - fs = require('fs'), - url = require('url'), - path = require('path'), - fork = require('child_process').fork, - - async = require('async'), - logrotate = require('logrotate-stream'), - file = require('./src/file'), - pkg = require('./package.json'); +var nconf = require('nconf'); +var fs = require('fs'); +var url = require('url'); +var path = require('path'); +var fork = require('child_process').fork; +var async = require('async'); +var logrotate = require('logrotate-stream'); +var file = require('./src/file'); +var pkg = require('./package.json'); nconf.argv().env().file({ - file: path.join(__dirname, '/config.json') + file: path.join(__dirname, 'config.json'), }); -var pidFilePath = __dirname + '/pidfile', - output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }), - silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false, - numProcs, - workers = [], - - Loader = { - timesStarted: 0 - }; +var pidFilePath = path.join(__dirname, 'pidfile'); +var outputLogFilePath = path.join(__dirname, 'logs/output.log'); +var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true }); +var silent = nconf.get('silent') === 'false' ? false : nconf.get('silent') !== false; +var numProcs; +var workers = []; +var Loader = { + timesStarted: 0, +}; Loader.init = function (callback) { if (silent) { @@ -50,11 +49,10 @@ Loader.displayStartupMessages = function (callback) { }; Loader.addWorkerEvents = function (worker) { - worker.on('exit', function (code, signal) { if (code !== 0) { if (Loader.timesStarted < numProcs * 3) { - Loader.timesStarted++; + Loader.timesStarted += 1; if (Loader.crashTimer) { clearTimeout(Loader.crashTimer); } @@ -62,7 +60,7 @@ Loader.addWorkerEvents = function (worker) { Loader.timesStarted = 0; }, 10000); } else { - console.log(numProcs * 3 + ' restarts in 10 seconds, most likely an error on startup. Halting.'); + console.log((numProcs * 3) + ' restarts in 10 seconds, most likely an error on startup. Halting.'); process.exit(); } } @@ -78,13 +76,13 @@ Loader.addWorkerEvents = function (worker) { worker.on('message', function (message) { if (message && typeof message === 'object' && message.action) { switch (message.action) { - case 'restart': - console.log('[cluster] Restarting...'); - Loader.restart(); + case 'restart': + console.log('[cluster] Restarting...'); + Loader.restart(); break; - case 'reload': - console.log('[cluster] Reloading...'); - Loader.reload(); + case 'reload': + console.log('[cluster] Reloading...'); + Loader.reload(); break; } } @@ -95,7 +93,7 @@ Loader.start = function (callback) { numProcs = getPorts().length; console.log('Clustering enabled: Spinning up ' + numProcs + ' process(es).\n'); - for (var x = 0; x < numProcs; ++x) { + for (var x = 0; x < numProcs; x += 1) { forkWorker(x, x === 0); } @@ -108,17 +106,17 @@ function forkWorker(index, isPrimary) { var ports = getPorts(); var args = []; - if(!ports[index]) { + if (!ports[index]) { return console.log('[cluster] invalid port for worker : ' + index + ' ports: ' + ports.length); } process.env.isPrimary = isPrimary; - process.env.isCluster = ports.length > 1 ? true : false; + process.env.isCluster = ports.length > 1; process.env.port = ports[index]; var worker = fork('app.js', args, { silent: silent, - env: process.env + env: process.env, }); worker.index = index; @@ -129,7 +127,7 @@ function forkWorker(index, isPrimary) { Loader.addWorkerEvents(worker); if (silent) { - var output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }); + var output = logrotate({ file: outputLogFilePath, size: '1m', keep: 3, compress: true }); worker.stdout.pipe(output); worker.stderr.pipe(output); } @@ -156,7 +154,7 @@ Loader.restart = function () { nconf.remove('file'); nconf.use('file', { file: pathToConfig }); - fs.readFile(pathToConfig, {encoding: 'utf-8'}, function (err, configFile) { + fs.readFile(pathToConfig, { encoding: 'utf-8' }, function (err, configFile) { if (err) { console.log('Error reading config : ' + err.message); process.exit(); @@ -175,7 +173,7 @@ Loader.restart = function () { Loader.reload = function () { workers.forEach(function (worker) { worker.send({ - action: 'reload' + action: 'reload', }); }); }; @@ -184,7 +182,7 @@ Loader.stop = function () { killWorkers(); // Clean up the pidfile - fs.unlinkSync(__dirname + '/pidfile'); + fs.unlinkSync(pidFilePath); }; function killWorkers() { @@ -222,16 +220,16 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) { require('daemon')({ stdout: process.stdout, - stderr: process.stderr + stderr: process.stderr, }); - fs.writeFile(__dirname + '/pidfile', process.pid); + fs.writeFileSync(pidFilePath, process.pid); } async.series([ Loader.init, Loader.displayStartupMessages, - Loader.start + Loader.start, ], function (err) { if (err) { console.log('[loader] Error during startup: ' + err.message); @@ -239,6 +237,6 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) { }); } else { // No config detected, kickstart web installer - var child = require('child_process').fork('app'); + require('child_process').fork('app'); } }); diff --git a/package.json b/package.json index 8a870e9c97..38f3922af3 100644 --- a/package.json +++ b/package.json @@ -52,17 +52,17 @@ "morgan": "^1.3.2", "mousetrap": "^1.5.3", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "4.4.1", + "nodebb-plugin-composer-default": "4.4.2", "nodebb-plugin-dbsearch": "1.0.5", "nodebb-plugin-emoji-extended": "1.1.1", "nodebb-plugin-emoji-one": "1.1.5", "nodebb-plugin-markdown": "7.1.1", "nodebb-plugin-mentions": "1.1.3", "nodebb-plugin-soundpack-default": "1.0.0", - "nodebb-plugin-spam-be-gone": "0.4.10", + "nodebb-plugin-spam-be-gone": "0.4.13", "nodebb-rewards-essentials": "0.0.9", - "nodebb-theme-lavender": "3.0.15", - "nodebb-theme-persona": "4.2.4", + "nodebb-theme-lavender": "4.0.0", + "nodebb-theme-persona": "4.2.6", "nodebb-theme-vanilla": "5.2.0", "nodebb-widget-essentials": "2.0.13", "nodemailer": "2.6.4", @@ -87,22 +87,21 @@ "socket.io-redis": "3.1.0", "socketio-wildcard": "~0.3.0", "string": "^3.0.0", - "templates.js": "0.3.6", + "templates.js": "0.3.10", "toobusy-js": "^0.5.1", "uglify-js": "^2.6.0", "underscore": "^1.8.3", "underscore.deep": "^0.5.1", "validator": "^6.1.0", "winston": "^2.1.0", + "xml": "^1.0.1", "xregexp": "~3.1.0" }, "devDependencies": { "coveralls": "^2.11.14", "eslint": "^3.12.0", - "eslint-config-airbnb": "^13.0.0", - "eslint-plugin-import": "^2.0.0", - "eslint-plugin-jsx-a11y": "^2.2.3", - "eslint-plugin-react": "^6.8.0", + "eslint-config-airbnb-base": "^11.1.0", + "eslint-plugin-import": "^2.2.0", "grunt": "~1.0.0", "grunt-contrib-watch": "^1.0.0", "istanbul": "^0.4.2", diff --git a/public/.eslintrc b/public/.eslintrc new file mode 100644 index 0000000000..7c80ae2ec1 --- /dev/null +++ b/public/.eslintrc @@ -0,0 +1,58 @@ +{ + "globals": { + "app": true, + "io": true, + "socket": true, + "ajaxify": true, + "config": true, + "RELATIVE_PATH": true, + "utils": true, + "overrides": true, + "componentHandler": true, + "bootbox": true, + "templates": true, + "Visibility": true, + "Tinycon": true, + "Promise": true + }, + "env": { + "jquery": true, + "amd": true, + "browser": true, + "es6": false + }, + "rules": { + "no-dupe-class-members": "off", + "no-var": "off", + "object-shorthand": "off", + "prefer-arrow-callback": "off", + "prefer-spread": "off", + "prefer-reflect": "off", + "prefer-template": "off" + }, + "parserOptions": { + "ecmaVersion": 5, + "ecmaFeatures": { + "arrowFunctions": false, + "classes": false, + "defaultParams": false, + "destructuring": false, + "experimentalObjectRestSpread": false, + "blockBindings": false, + "forOf": false, + "generators": false, + "globalReturn": false, + "jsx": false, + "modules": false, + "objectLiteralComputedProperties": false, + "objectLiteralDuplicateProperties": false, + "objectLiteralShorthandMethods": false, + "objectLiteralShorthandProperties": false, + "impliedStrict": false, + "restParams": false, + "spread": false, + "superInFunctions": false, + "templateStrings": false + } + } +} diff --git a/public/.jshintrc b/public/.jshintrc new file mode 100644 index 0000000000..5201bccc62 --- /dev/null +++ b/public/.jshintrc @@ -0,0 +1,84 @@ +{ + "maxerr" : 50, // {int} Maximum error before stopping + + // Enforcing + "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) + "camelcase" : false, // true: Identifiers must be in camelCase + "curly" : true, // true: Require {} for every new block or scope + "eqeqeq" : true, // true: Require triple equals (===) for comparison + "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() + "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` + "indent" : 4, // {int} Number of spaces to use for indentation + "latedef" : false, // true: Require variables/functions to be defined before being used + "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` + "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` + "noempty" : true, // true: Prohibit use of empty blocks + "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) + "plusplus" : false, // true: Prohibit use of `++` & `--` + "quotmark" : false, // Quotation mark consistency: + // false : do nothing (default) + // true : ensure whatever is used is consistent + // "single" : require single quotes + // "double" : require double quotes + "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) + "unused" : true, // true: Require all defined variables be used + "strict" : true, // true: Requires all functions run in ES5 Strict Mode + "trailing" : false, // true: Prohibit trailing whitespaces + "maxparams" : false, // {int} Max number of formal params allowed per function + "maxdepth" : false, // {int} Max depth of nested blocks (within functions) + "maxstatements" : false, // {int} Max number statements per function + "maxcomplexity" : false, // {int} Max cyclomatic complexity per function + "maxlen" : false, // {int} Max number of characters per line + + // Relaxing + "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) + "boss" : false, // true: Tolerate assignments where comparisons would be expected + "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // true: Tolerate use of `== null` + "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) + "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) + "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) + // (ex: `for each`, multiple try/catch, function expression…) + "evil" : false, // true: Tolerate use of `eval` and `new Function()` + "expr" : false, // true: Tolerate `ExpressionStatement` as Programs + "funcscope" : false, // true: Tolerate defining variables inside control statements" + "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') + "iterator" : false, // true: Tolerate using the `__iterator__` property + "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block + "laxbreak" : false, // true: Tolerate possibly unsafe line breakings + "laxcomma" : false, // true: Tolerate comma-first style coding + "loopfunc" : false, // true: Tolerate functions being defined in loops + "multistr" : false, // true: Tolerate multi-line strings + "proto" : false, // true: Tolerate using the `__proto__` property + "scripturl" : false, // true: Tolerate script-targeted URLs + "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment + "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` + "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation + "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` + "validthis" : false, // true: Tolerate using this in a non-constructor function + + "globals": { + "app": true, + "io": true, + "socket": true, + "ajaxify": true, + "config": true, + "RELATIVE_PATH": true, + "utils": true, + "overrides": true, + "componentHandler": true, + "bootbox": true, + "templates": true, + "Visibility": true, + "Tinycon": true, + "require": true, + "define": true, + "ace": true, + "Sortable": true, + "Slideout": true, + "NProgress": true + }, + + "jquery": true, + "browser": true +} \ No newline at end of file diff --git a/public/language/de/admin/advanced/events.json b/public/language/de/admin/advanced/events.json index 15976369c3..6ed2a251da 100644 --- a/public/language/de/admin/advanced/events.json +++ b/public/language/de/admin/advanced/events.json @@ -1,6 +1,6 @@ { - "events": "Veranstaltungen", - "no-events": "Es gibt keine Veranstaltungen", - "control-panel": "Veranstaltungen Steuerung", - "delete-events": "Veranstaltungen löschen" + "events": "Ereignisse", + "no-events": "Es gibt keine Ereignisse", + "control-panel": "Ereignis-Steuerung", + "delete-events": "Ereignisse löschen" } \ No newline at end of file diff --git a/public/language/en-GB/admin/manage/flags.json b/public/language/en-GB/admin/manage/flags.json index bfc488a409..8286861d01 100644 --- a/public/language/en-GB/admin/manage/flags.json +++ b/public/language/en-GB/admin/manage/flags.json @@ -9,7 +9,7 @@ "search": "Search", "dismiss-all": "Dismiss All", "none-flagged": "No flagged posts!", - "posted-in": "Posted in %1", + "posted-in": "Posted in", "read-more": "Read More", "flagged-x-times": "This post has been flagged %1 time(s):", "dismiss": "Dismiss this Flag", diff --git a/public/language/en-GB/admin/settings/general.json b/public/language/en-GB/admin/settings/general.json index c26740ee4f..8db88bb958 100644 --- a/public/language/en-GB/admin/settings/general.json +++ b/public/language/en-GB/admin/settings/general.json @@ -26,5 +26,6 @@ "touch-icon.upload": "Upload", "touch-icon.help": "Recommended size and format: 192x192, PNG format only. If no touch icon is specified, NodeBB will fall back to using the favicon.", "outgoing-links": "Outgoing Links", - "outgoing-links.warning-page": "Use Outgoing Links Warning Page" + "outgoing-links.warning-page": "Use Outgoing Links Warning Page", + "outgoing-links.whitelist": "Domains to whitelist for bypassing the warning page" } \ No newline at end of file diff --git a/public/language/en-GB/groups.json b/public/language/en-GB/groups.json index a55cc8603f..08c8d4d1f5 100644 --- a/public/language/en-GB/groups.json +++ b/public/language/en-GB/groups.json @@ -32,6 +32,7 @@ "details.disableJoinRequests": "Disable join requests", "details.grant": "Grant/Rescind Ownership", "details.kick": "Kick", + "details.kick_confirm": "Are you sure you want to remove this member from the group?", "details.owner_options": "Group Administration", "details.group_name": "Group Name", diff --git a/public/language/it/admin/advanced/database.json b/public/language/it/admin/advanced/database.json index 33dc5f4934..53404f0915 100644 --- a/public/language/it/admin/advanced/database.json +++ b/public/language/it/admin/advanced/database.json @@ -8,27 +8,27 @@ "mongo.version": "Versione MongoDB", "mongo.storage-engine": "Storage Engine", "mongo.collections": "Collections", - "mongo.objects": "Objects", - "mongo.avg-object-size": "Avg. Object Size", - "mongo.data-size": "Data Size", - "mongo.storage-size": "Storage Size", - "mongo.index-size": "Index Size", - "mongo.file-size": "File Size", - "mongo.resident-memory": "Resident Memory", - "mongo.virtual-memory": "Virtual Memory", - "mongo.mapped-memory": "Mapped Memory", + "mongo.objects": "Oggetti", + "mongo.avg-object-size": "Dimensione Media dell'Oggetto", + "mongo.data-size": "Dimensione del Data", + "mongo.storage-size": "Dimensione dello Spazio di Archiviazione", + "mongo.index-size": "Dimensione dell'Indice", + "mongo.file-size": "Dimensione del file", + "mongo.resident-memory": "Memoria Allocata", + "mongo.virtual-memory": "Memoria Virtuale", + "mongo.mapped-memory": "Memoria Mappata", "mongo.raw-info": "MongoDB Raw Info", "redis": "Redis", - "redis.version": "Redis Version", - "redis.connected-clients": "Connected Clients", + "redis.version": "Versione Redis", + "redis.connected-clients": "Clients Connessi", "redis.connected-slaves": "Connected Slaves", - "redis.blocked-clients": "Blocked Clients", - "redis.used-memory": "Used Memory", - "redis.memory-frag-ratio": "Memory Fragmentation Ratio", - "redis.total-connections-recieved": "Total Connections Received", - "redis.total-commands-processed": "Total Commands Processed", - "redis.iops": "Instantaneous Ops. Per Second", + "redis.blocked-clients": "Clients Bloccati", + "redis.used-memory": "Memoria Usata", + "redis.memory-frag-ratio": "Rateo della Frammentazione della Memoria", + "redis.total-connections-recieved": "Totale Connessioni Ricevute", + "redis.total-commands-processed": "Totale Comandi Processati", + "redis.iops": "Operazioni Instantanee al Secondo", "redis.keyspace-hits": "Keyspace Hits", "redis.keyspace-misses": "Keyspace Misses", "redis.raw-info": "Redis Raw Info" diff --git a/public/language/it/admin/advanced/errors.json b/public/language/it/admin/advanced/errors.json index 546f0f1508..ca148b1236 100644 --- a/public/language/it/admin/advanced/errors.json +++ b/public/language/it/admin/advanced/errors.json @@ -1,14 +1,14 @@ { - "figure-x": "Figure %1", - "error-events-per-day": "%1 events per day", - "error.404": "404 Not Found", - "error.503": "503 Service Unavailable", - "manage-error-log": "Manage Error Log", - "export-error-log": "Export Error Log (CSV)", - "clear-error-log": "Clear Error Log", - "route": "Route", - "count": "Count", - "no-routes-not-found": "Hooray! No 404 errors!", - "clear404-confirm": "Are you sure you wish to clear the 404 error logs?", - "clear404-success": "\"404 Not Found\" errors cleared" + "figure-x": "Figura %1", + "error-events-per-day": "%1 eventi per giorno", + "error.404": "404 Non Trovato", + "error.503": "503 Servizio Non Disponibile", + "manage-error-log": "Gestisci il Registro degli Errori", + "export-error-log": "Esporta il Registro degli Errori (CSV)", + "clear-error-log": "Cancella il Registro degli Errori", + "route": "Strada", + "count": "Numero", + "no-routes-not-found": "Hooray! Nessun Errore 404!", + "clear404-confirm": "Sei sicuro di voler cancellare il Registro degli Errori 404?", + "clear404-success": "Error \"404 Non Trovato\" Cancellati" } \ No newline at end of file diff --git a/public/language/it/admin/advanced/events.json b/public/language/it/admin/advanced/events.json index 766eb5e951..ca64e626db 100644 --- a/public/language/it/admin/advanced/events.json +++ b/public/language/it/admin/advanced/events.json @@ -1,6 +1,6 @@ { - "events": "Events", - "no-events": "There are no events", - "control-panel": "Events Control Panel", - "delete-events": "Delete Events" + "events": "Eventi", + "no-events": "Non ci sono Eventi", + "control-panel": "Pannello di controllo degli Eventi", + "delete-events": "Cancella gli Eventi" } \ No newline at end of file diff --git a/public/language/it/admin/advanced/logs.json b/public/language/it/admin/advanced/logs.json index b9de400e1c..72b330fb5c 100644 --- a/public/language/it/admin/advanced/logs.json +++ b/public/language/it/admin/advanced/logs.json @@ -1,7 +1,7 @@ { - "logs": "Logs", - "control-panel": "Logs Control Panel", - "reload": "Reload Logs", - "clear": "Clear Logs", - "clear-success": "Logs Cleared!" + "logs": "Registri", + "control-panel": "Pannello di Controllo dei Registri", + "reload": "Ricarica i Registri", + "clear": "Cancella i Registri", + "clear-success": "Registri Cancellati!" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/customise.json b/public/language/it/admin/appearance/customise.json index 767d443e29..c97943fd6f 100644 --- a/public/language/it/admin/appearance/customise.json +++ b/public/language/it/admin/appearance/customise.json @@ -1,9 +1,9 @@ { - "custom-css": "Custom CSS", - "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS", + "custom-css": "CSS Personalizzato", + "custom-css.description": "Inserisci le tue dichiarazioni CSS qui, verranno applicate dopo tutti gli altri stili.", + "custom-css.enable": "Abilita CSS Personalizzato", - "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", - "custom-header.enable": "Enable Custom Header" + "custom-header": "Intestazione Personalizzata", + "custom-header.description": "Inserisci l' HTML personalizzato qui (es. JavaScript, Meta Tags, ecc.), verrà attaccato al codice <head> sezione del markup del tuo forum", + "custom-header.enable": "Abilita l'Intestazione Personalizzata" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/skins.json b/public/language/it/admin/appearance/skins.json index 4db6fbdd8a..e7c26359b5 100644 --- a/public/language/it/admin/appearance/skins.json +++ b/public/language/it/admin/appearance/skins.json @@ -1,9 +1,9 @@ { - "loading": "Loading Skins...", - "homepage": "Homepage", - "select-skin": "Select Skin", - "current-skin": "Current Skin", - "skin-updated": "Skin Updated", - "applied-success": "%1 skin was succesfully applied", - "revert-success": "Skin reverted to base colours" + "loading": "Caricamento Skins", + "homepage": "Pagina Home", + "select-skin": "Seleziona la Skin", + "current-skin": "Skin Corrente", + "skin-updated": "Skin Aggiornata", + "applied-success": "%1 skin è stata applicata con successo", + "revert-success": "Skin riportata ai colori base" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/themes.json b/public/language/it/admin/appearance/themes.json index 3148a01337..1406bb9276 100644 --- a/public/language/it/admin/appearance/themes.json +++ b/public/language/it/admin/appearance/themes.json @@ -1,11 +1,11 @@ { - "checking-for-installed": "Checking for installed themes...", - "homepage": "Homepage", - "select-theme": "Select Theme", - "current-theme": "Current Theme", - "no-themes": "No installed themes found", - "revert-confirm": "Are you sure you wish to restore the default NodeBB theme?", - "theme-changed": "Theme Changed", - "revert-success": "You have successfully reverted your NodeBB back to it's default theme.", - "restart-to-activate": "Please restart your NodeBB to fully activate this theme" + "checking-for-installed": "Controllando se ci sono temi installati...", + "homepage": "Pagina Home", + "select-theme": "Seleziona il Tema", + "current-theme": "Tema Corrente", + "no-themes": "Nessun tema installato trovato", + "revert-confirm": "Sei sicuro di voler ripristinare al tema originale di NodeBB?", + "theme-changed": "Tema Cambiato", + "revert-success": "Hai correttamente ripristinato il tuo NodeBB al tema originale.", + "restart-to-activate": "Perfavore riavvia il tuo NodeBB per attivare correttamente questo tema" } \ No newline at end of file diff --git a/public/language/it/admin/development/info.json b/public/language/it/admin/development/info.json index b2768ca212..38e991ebd6 100644 --- a/public/language/it/admin/development/info.json +++ b/public/language/it/admin/development/info.json @@ -1,16 +1,16 @@ { - "you-are-on": "Info - You are on %1:%2", + "you-are-on": "Informazione - Tu sei su %1:%2", "host": "host", "pid": "pid", "nodejs": "nodejs", "online": "online", "git": "git", - "load": "load", - "uptime": "uptime", + "load": "carica", + "uptime": "tempo di caricamento", - "registered": "Registered", + "registered": "Registrato", "sockets": "Sockets", - "guests": "Guests", + "guests": "Ospiti", - "info": "Info" + "info": "Informazioni" } \ No newline at end of file diff --git a/public/language/it/admin/development/logger.json b/public/language/it/admin/development/logger.json index 6ab9558149..ea6fc6a8c7 100644 --- a/public/language/it/admin/development/logger.json +++ b/public/language/it/admin/development/logger.json @@ -1,6 +1,6 @@ { - "logger-settings": "Logger Settings", - "description": "By enabling the check boxes, you will receive logs to your terminal. If you specify a path, logs will then be saved to a file instead. HTTP logging is useful for collecting statistics about who, when, and what people access on your forum. In addition to logging HTTP requests, we can also log socket.io events. Socket.io logging, in combination with redis-cli monitor, can be very helpful for learning NodeBB's internals.", + "logger-settings": "Impostazioni del Registratore", + "description": "Abilitando le \"check boxes\", riceverai i registri sul tuo terminale. Se vuoi specificare un percorso, i registri verranno invece salvati in un file. Registrare l' HTTP è utile per collezionare statistiche su chi, quando, e a cosa le persone hanno accesso sul tuo forum. In più sul registrare le richieste HTTP, in combinazione con il monitoraggio redis-cli, può essere veramente utile per imparare l'interno di NodeBB", "explanation": "Simply check/uncheck the logging settings to enable or disable logging on the fly. No restart needed.", "enable-http": "Enable HTTP logging", "enable-socket": "Enable socket.io event logging", diff --git a/public/language/pl/admin/settings/group.json b/public/language/pl/admin/settings/group.json index 6db8cb32b4..c5900c2a39 100644 --- a/public/language/pl/admin/settings/group.json +++ b/public/language/pl/admin/settings/group.json @@ -1,5 +1,5 @@ { - "general": "General", + "general": "Ogólne", "private-groups": "Prywatne Grupy", "private-groups.help": "If enabled, joining of groups requires the approval of the group owner (Default: enabled)", "private-groups.warning": "Beware! If this option is disabled and you have private groups, they automatically become public.", diff --git a/public/language/pl/admin/settings/tags.json b/public/language/pl/admin/settings/tags.json index d67523c8e6..ef8efabbcd 100644 --- a/public/language/pl/admin/settings/tags.json +++ b/public/language/pl/admin/settings/tags.json @@ -1,6 +1,6 @@ { "tag": "Ustawienia Tagów", - "min-per-topic": "Minimum Tags per Topic", + "min-per-topic": "Minimalna ilość Tagów na Temat", "max-per-topic": "Maximum Tags per Topic", "min-length": "Minimum Tag Length", "max-length": "Maximum Tag Length", diff --git a/public/language/pl/admin/settings/uploads.json b/public/language/pl/admin/settings/uploads.json index 9a610fb576..05edbff41a 100644 --- a/public/language/pl/admin/settings/uploads.json +++ b/public/language/pl/admin/settings/uploads.json @@ -1,6 +1,6 @@ { "posts": "Posty", - "allow-files": "Allow users to upload regular files", + "allow-files": "Pozwolić użytkownikom wgrywać pliki", "private": "Make uploaded files private", "max-image-width": "Resize images down to specified width (in pixels)", "max-image-width-help": "(in pixels, default: 760 pixels, set to 0 to disable)", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 67f18374c3..fb4e7993a4 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -15,7 +15,7 @@ "invalid-username-or-password": "Молимо наведите и корисничко име и лозинку", "invalid-search-term": "Неисправан упит за претрагу", "csrf-invalid": "Нисмо успели да вас пријавимо, вероватно због истека сесије. Молимо покушајте поново", - "invalid-pagination-value": "Неважећа вредност при обележавању страна, мора бити најмање %1 а највише %2 ", + "invalid-pagination-value": "Неважећа вредност приликом нумерисања страница, мора бити најмање %1 а највише %2 ", "username-taken": "Корисничко име је заузето", "email-taken": "Адреса е-поште је заузета", "email-not-confirmed": "Ваша адреса е-поште још увек није оверена, кликните овде да би сте то учинили.", diff --git a/public/language/sr/global.json b/public/language/sr/global.json index cb938fa889..a66b424eef 100644 --- a/public/language/sr/global.json +++ b/public/language/sr/global.json @@ -21,7 +21,7 @@ "save_changes": "Сачувај измене", "save": "Сачувај", "close": "Затвори", - "pagination": "Обележавање страна", + "pagination": "Нумерисање страница", "pagination.out_of": "%1 од %2", "pagination.enter_index": "Унесите индекс", "header.admin": "Админ", diff --git a/public/language/sr/topic.json b/public/language/sr/topic.json index 3992fad51d..95655a8162 100644 --- a/public/language/sr/topic.json +++ b/public/language/sr/topic.json @@ -13,7 +13,7 @@ "notify_me": "Будите обавештени о новим порукама у овој теми", "quote": "Цитирај", "reply": "Одговори", - "replies_to_this_post": "%1 одговора", + "replies_to_this_post": "Одговора: %1", "last_reply_time": "Последњи одговор", "reply-as-topic": "Постави одговор као тему", "guest-login-reply": "Пријавите се да бисте одговорили", diff --git a/public/language/sr/user.json b/public/language/sr/user.json index 08c61c887c..86b2264429 100644 --- a/public/language/sr/user.json +++ b/public/language/sr/user.json @@ -31,7 +31,7 @@ "signature": "Потпис", "birthday": "Рођендан", "chat": "Ђаскање", - "chat_with": "Настави ћаскање са %1", + "chat_with": "Ћаскај са %1", "new_chat_with": "Започни ново ћаскање са %1", "flag-profile": "Означи профил", "follow": "Прати", @@ -90,7 +90,7 @@ "has_no_voted_posts": "Овај корисник нема објаве за које се гласало.", "email_hidden": "Скривена е-пошта", "hidden": "скривена", - "paginate_description": "Подели теме и поруке по страницама уместо бесконачног скроловања", + "paginate_description": "Нумериши теме и странице уместо бесконачног скроловања", "topics_per_page": "Тема по страници", "posts_per_page": "Порука по страници", "notification_sounds": "Репродукуј звук приликом примања обавештења", diff --git a/public/language/tr/admin/settings/chat.json b/public/language/tr/admin/settings/chat.json index ea8de84c54..a695d56607 100644 --- a/public/language/tr/admin/settings/chat.json +++ b/public/language/tr/admin/settings/chat.json @@ -1,9 +1,9 @@ { "chat-settings": "Sohbet Ayarları", "disable": "Sohbeti kapat", - "disable-editing": "Disable chat message editing/deletion", + "disable-editing": "Sohbet mesajlarını düzenlemeyi/silmeyi kapat", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", - "max-length": "Maximum length of chat messages", + "max-length": "Maksimum sohbet mesajı uzunluğu", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds" } \ No newline at end of file diff --git a/public/language/tr/admin/settings/user.json b/public/language/tr/admin/settings/user.json index 258f7f4121..dd7154fc35 100644 --- a/public/language/tr/admin/settings/user.json +++ b/public/language/tr/admin/settings/user.json @@ -7,14 +7,14 @@ "allow-login-with": "Allow login with", "allow-login-with.username-email": "Kullanıcı adı veya Email", "allow-login-with.username": "Sadece kullanıcı adı", - "allow-login-with.email": "Email Only", + "allow-login-with.email": "Sadece Email", "account-settings": "Hesap Ayarları", - "disable-username-changes": "Disable username changes", - "disable-email-changes": "Disable email changes", - "disable-password-changes": "Disable password changes", - "allow-account-deletion": "Allow account deletion", - "user-info-private": "Make user info private", - "themes": "Themes", + "disable-username-changes": "Kullanıcı adı değişikliği kapalı", + "disable-email-changes": "Email değişikliği kapalı", + "disable-password-changes": "Parola değişikliği kapalı", + "allow-account-deletion": "Hesap silmeye izin ver", + "user-info-private": "Kullanıcı bilgilerini gizli yap", + "themes": "Temalar", "disable-user-skins": "Prevent users from choosing a custom skin", "account-protection": "Account Protection", "login-attempts": "Login attempts per hour", @@ -23,13 +23,13 @@ "login-days": "Days to remember user login sessions", "password-expiry-days": "Force password reset after a set number of days", "registration": "User Registration", - "registration-type": "Registration Type", + "registration-type": "Kayıt Tipi", "registration-type.normal": "Normal", - "registration-type.admin-approval": "Admin Approval", - "registration-type.admin-approval-ip": "Admin Approval for IPs", - "registration-type.invite-only": "Invite Only", - "registration-type.admin-invite-only": "Admin Invite Only", - "registration-type.disabled": "No registration", + "registration-type.admin-approval": "Yönetici Onayı", + "registration-type.admin-approval-ip": "IP'ler için Yönetici Onayı", + "registration-type.invite-only": "Sadece Davet", + "registration-type.admin-invite-only": "Sadece Yönetici Daveti", + "registration-type.disabled": "Kayıt yok", "registration-type.help": "Normal - Users can register from the /register page.
\nAdmin Approval - User registrations are placed in an approval queue for administrators.
\nAdmin Approval for IPs - Normal for new users, Admin Approval for IP addresses that already have an account.
\nInvite Only - Users can invite others from the users page.
\nAdmin Invite Only - Only administrators can invite others from users and admin/manage/users pages.
\nNo registration - No user registration.
", "registration.max-invites": "Maximum Invitations per User", "max-invites": "Maximum Invitations per User", diff --git a/public/language/vi/admin/admin.json b/public/language/vi/admin/admin.json index 9c01f56006..726cef0e8b 100644 --- a/public/language/vi/admin/admin.json +++ b/public/language/vi/admin/admin.json @@ -1,7 +1,7 @@ { - "alert.confirm-reload": "Are you sure you wish to reload NodeBB?", - "alert.confirm-restart": "Are you sure you wish to restart NodeBB?", + "alert.confirm-reload": "Bạn có thật sự muốn tải lại NodeBB", + "alert.confirm-restart": "Bạn có thật sự muốn khởi động lại NodeBB", - "acp-title": "%1 | NodeBB Admin Control Panel", - "settings-header-contents": "Contents" + "acp-title": "%1 | Bảng điểu khiển", + "settings-header-contents": "Nội dung" } \ No newline at end of file diff --git a/public/language/vi/admin/advanced/cache.json b/public/language/vi/admin/advanced/cache.json index 5a954f1232..505b1a4510 100644 --- a/public/language/vi/admin/advanced/cache.json +++ b/public/language/vi/admin/advanced/cache.json @@ -1,11 +1,11 @@ { - "post-cache": "Post Cache", - "posts-in-cache": "Posts in Cache", - "average-post-size": "Average Post Size", - "length-to-max": "Length / Max", - "percent-full": "%1% Full", - "post-cache-size": "Post Cache Size", - "items-in-cache": "Items in Cache", - "control-panel": "Control Panel", - "update-settings": "Update Cache Settings" + "post-cache": "Cache bài viết", + "posts-in-cache": "Cache cho bài viết", + "average-post-size": "Kích thước bài viết", + "length-to-max": "Độ dài / Tối Đa", + "percent-full": "%1% Đầy", + "post-cache-size": "Kích thước cache bài viết", + "items-in-cache": "Thành phần trong Cache", + "control-panel": "Bảng điều khiển", + "update-settings": "Cập nhật thiết lập Cache" } \ No newline at end of file diff --git a/public/language/vi/admin/advanced/database.json b/public/language/vi/admin/advanced/database.json index f7db6220ee..fe446d1759 100644 --- a/public/language/vi/admin/advanced/database.json +++ b/public/language/vi/admin/advanced/database.json @@ -1,30 +1,30 @@ { "x-b": "%1 b", "x-mb": "%1 mb", - "uptime-seconds": "Uptime in Seconds", - "uptime-days": "Uptime in Days", + "uptime-seconds": "Thời gian hoạt động(giây)", + "uptime-days": "Thời gian hoạt động(Ngày)", "mongo": "Mongo", - "mongo.version": "MongoDB Version", - "mongo.storage-engine": "Storage Engine", - "mongo.collections": "Collections", - "mongo.objects": "Objects", - "mongo.avg-object-size": "Avg. Object Size", - "mongo.data-size": "Data Size", - "mongo.storage-size": "Storage Size", - "mongo.index-size": "Index Size", - "mongo.file-size": "File Size", + "mongo.version": "Phiên bản MongoDB ", + "mongo.storage-engine": "Lưu Trữ", + "mongo.collections": "Tập dữ liệu", + "mongo.objects": "Đối tượng", + "mongo.avg-object-size": "Kích thước trung bình", + "mongo.data-size": "Kích thước dữ liệu", + "mongo.storage-size": "Kích thước lưu trữ", + "mongo.index-size": "Kích thước chỉ mục", + "mongo.file-size": "Kích thước tập tin", "mongo.resident-memory": "Resident Memory", - "mongo.virtual-memory": "Virtual Memory", + "mongo.virtual-memory": "Bộ nhớ ảo", "mongo.mapped-memory": "Mapped Memory", - "mongo.raw-info": "MongoDB Raw Info", + "mongo.raw-info": "Thông tin MongoDB", "redis": "Redis", - "redis.version": "Redis Version", - "redis.connected-clients": "Connected Clients", + "redis.version": "Phiên bản Redis", + "redis.connected-clients": "Người dùng kết nối", "redis.connected-slaves": "Connected Slaves", - "redis.blocked-clients": "Blocked Clients", - "redis.used-memory": "Used Memory", + "redis.blocked-clients": "Người dùng vi phạm", + "redis.used-memory": "Bộ nhớ đã sử dụng", "redis.memory-frag-ratio": "Memory Fragmentation Ratio", "redis.total-connections-recieved": "Total Connections Received", "redis.total-commands-processed": "Total Commands Processed", diff --git a/public/language/vi/global.json b/public/language/vi/global.json index 5a4e6a1406..65db660c60 100644 --- a/public/language/vi/global.json +++ b/public/language/vi/global.json @@ -103,5 +103,5 @@ "cookies.message": "Trang web này sử dụng cookie để đảm bảo trải nghiệm tốt nhất cho người dùng", "cookies.accept": "Đã rõ!", "cookies.learn_more": "Xem thêm", - "edited": "Edited" + "edited": "Đã cập nhật" } \ No newline at end of file diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index aaa940bdc3..5c1cd238c7 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -13,8 +13,8 @@ "notify_me": "Được thông báo khi có trả lời mới trong chủ đề này", "quote": "Trích dẫn", "reply": "Trả lời", - "replies_to_this_post": "%1 Replies", - "last_reply_time": "Last reply", + "replies_to_this_post": "%1 trả lời", + "last_reply_time": "Trả lời cuối cùng", "reply-as-topic": "Trả lời dưới dạng chủ đề", "guest-login-reply": "Hãy đăng nhập để trả lời", "edit": "Chỉnh sửa", diff --git a/public/language/zh-CN/users.json b/public/language/zh-CN/users.json index 23a86966db..253d4db756 100644 --- a/public/language/zh-CN/users.json +++ b/public/language/zh-CN/users.json @@ -2,11 +2,11 @@ "latest_users": "最新会员", "top_posters": "发帖排行", "most_reputation": "声望排行", - "most_flags": "被举报次数最多", + "most_flags": "最多举报", "search": "搜索", "enter_username": "输入用户名搜索", "load_more": "加载更多", - "users-found-search-took": "找到 %1 位用户!耗时 %2 毫秒。", + "users-found-search-took": "找到 %1 位用户!耗时 %2 秒。", "filter-by": "过滤选项", "online-only": "只看在线", "invite": "邀请注册", diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 23f3bead8c..bcf6ddca58 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -272,4 +272,8 @@ body { border: 1px dashed @brand-success; background: lighten(@brand-success, 10%); opacity: 0.5; +} + +form small { + color: @gray-light; } \ No newline at end of file diff --git a/public/less/admin/settings.less b/public/less/admin/settings.less index 84572def68..decfc8b7ed 100644 --- a/public/less/admin/settings.less +++ b/public/less/admin/settings.less @@ -16,4 +16,20 @@ [data-action="upload"][type="text"] { width: 95%; } + + .bootstrap-tagsinput { + width: 100%; + border: 0; + box-shadow: none; + padding-left: 0; + + input { + width: 100%; + margin-left: 1px; + margin-top: 9px; + border-bottom: 1px dotted #ccc !important; + padding-bottom: 5px; + padding-left: 0; + } + } } \ No newline at end of file diff --git a/public/src/admin/.eslintrc b/public/src/admin/.eslintrc new file mode 100644 index 0000000000..0c670302fa --- /dev/null +++ b/public/src/admin/.eslintrc @@ -0,0 +1,8 @@ +{ + "globals": { + "ace": true, + "Sortable": true, + "Slideout": true, + "NProgress": true + } +} \ No newline at end of file diff --git a/public/src/admin/admin.js b/public/src/admin/admin.js index c4d92d63bc..7ec41a553b 100644 --- a/public/src/admin/admin.js +++ b/public/src/admin/admin.js @@ -1,5 +1,4 @@ -"use strict"; -/*global config, componentHandler, socket, app, bootbox, Slideout, NProgress, utils*/ +'use strict'; (function () { var logoutTimer = 0; @@ -14,7 +13,7 @@ message: '[[login:logged-out-due-to-inactivity]]', callback: function () { window.location.reload(); - } + }, }); }, 3600000); } @@ -34,7 +33,7 @@ $(document).ready(function () { setupKeybindings(); - if(!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { + if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { require(['admin/modules/search'], function (search) { search.init(); }); @@ -109,14 +108,15 @@ var mainTitle; var pageTitle; if (/admin\/general\/dashboard$/.test(url)) { - mainTitle = pageTitle = '[[admin/menu:general/dashboard]]'; + pageTitle = '[[admin/menu:general/dashboard]]'; + mainTitle = pageTitle; } else if (/admin\/plugins\//.test(url)) { mainTitle = fallback; pageTitle = '[[admin/menu:section-plugins]] > ' + mainTitle; } else { var matches = url.match(/admin\/(.+?)\/(.+?)$/); mainTitle = '[[admin/menu:' + matches[1] + '/' + matches[2] + ']]'; - pageTitle = '[[admin/menu:section-' + + pageTitle = '[[admin/menu:section-' + (matches[1] === 'development' ? 'advanced' : matches[1]) + ']]' + (matches[2] ? (' > ' + mainTitle) : ''); if (matches[2] === 'settings') { @@ -158,14 +158,14 @@ } function launchSnackbar(params) { - var message = (params.title ? "" + params.title + "" : '') + (params.message ? params.message : ''); + var message = (params.title ? '' + params.title + '' : '') + (params.message ? params.message : ''); require(['translator'], function (translator) { translator.translate(message, function (html) { var bar = $.snackbar({ content: html, timeout: params.timeout || 3000, - htmlAllowed: true + htmlAllowed: true, }); if (params.clickfn) { @@ -177,18 +177,18 @@ function configureSlidemenu() { var env = utils.findBootstrapEnvironment(); - + var slideout = new Slideout({ - 'panel': document.getElementById('panel'), - 'menu': document.getElementById('menu'), - 'padding': 256, - 'tolerance': 70 + panel: document.getElementById('panel'), + menu: document.getElementById('menu'), + padding: 256, + tolerance: 70, }); - + if (env === 'md' || env === 'lg') { slideout.disableTouch(); } - + $('#mobile-menu').on('click', function () { slideout.toggle(); }); @@ -199,36 +199,36 @@ $(window).on('resize', function () { slideout.close(); - + env = utils.findBootstrapEnvironment(); - + if (env === 'md' || env === 'lg') { slideout.disableTouch(); $('#header').css({ - 'position': 'relative' - }); + position: 'relative', + }); } else { slideout.enableTouch(); $('#header').css({ - 'position': 'fixed' + position: 'fixed', }); } }); function onOpeningMenu() { $('#header').css({ - 'top': $('#panel').position().top * -1 + 'px', - 'position': 'absolute' + top: ($('#panel').position().top * -1) + 'px', + position: 'absolute', }); } slideout.on('open', onOpeningMenu); - + slideout.on('close', function () { $('#header').css({ - 'top': '0px', - 'position': 'fixed' + top: '0px', + position: 'fixed', }); }); } -}()); \ No newline at end of file +}()); diff --git a/public/src/admin/advanced/errors.js b/public/src/admin/advanced/errors.js index d4cfccb7bd..6356d5690b 100644 --- a/public/src/admin/advanced/errors.js +++ b/public/src/admin/advanced/errors.js @@ -1,7 +1,7 @@ -"use strict"; -/*global config, define, app, socket, ajaxify, bootbox, templates, Chart, utils */ +'use strict'; -define('admin/advanced/errors', ['Chart', 'translator'], function (Chart, translator) { + +define('admin/advanced/errors', ['Chart'], function (Chart) { var Errors = {}; Errors.init = function () { @@ -26,9 +26,9 @@ define('admin/advanced/errors', ['Chart', 'translator'], function (Chart, transl }; Errors.setupCharts = function () { - var notFoundCanvas = document.getElementById('not-found'), - tooBusyCanvas = document.getElementById('toobusy'), - dailyLabels = utils.getDaysArray(); + var notFoundCanvas = document.getElementById('not-found'); + var tooBusyCanvas = document.getElementById('toobusy'); + var dailyLabels = utils.getDaysArray(); dailyLabels = dailyLabels.slice(-7); @@ -41,73 +41,73 @@ define('admin/advanced/errors', ['Chart', 'translator'], function (Chart, transl labels: dailyLabels, datasets: [ { - label: "", - backgroundColor: "rgba(186,139,175,0.2)", - borderColor: "rgba(186,139,175,1)", - pointBackgroundColor: "rgba(186,139,175,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(186,139,175,1)", - data: ajaxify.data.analytics['not-found'] - } - ] + label: '', + backgroundColor: 'rgba(186,139,175,0.2)', + borderColor: 'rgba(186,139,175,1)', + pointBackgroundColor: 'rgba(186,139,175,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(186,139,175,1)', + data: ajaxify.data.analytics['not-found'], + }, + ], }, - 'toobusy': { + toobusy: { labels: dailyLabels, datasets: [ { - label: "", - backgroundColor: "rgba(151,187,205,0.2)", - borderColor: "rgba(151,187,205,1)", - pointBackgroundColor: "rgba(151,187,205,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(151,187,205,1)", - data: ajaxify.data.analytics['toobusy'] - } - ] - } + label: '', + backgroundColor: 'rgba(151,187,205,0.2)', + borderColor: 'rgba(151,187,205,1)', + pointBackgroundColor: 'rgba(151,187,205,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(151,187,205,1)', + data: ajaxify.data.analytics.toobusy, + }, + ], + }, }; notFoundCanvas.width = $(notFoundCanvas).parent().width(); tooBusyCanvas.width = $(tooBusyCanvas).parent().width(); - + new Chart(notFoundCanvas.getContext('2d'), { type: 'line', data: data['not-found'], options: { responsive: true, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); - + new Chart(tooBusyCanvas.getContext('2d'), { type: 'line', - data: data['toobusy'], + data: data.toobusy, options: { responsive: true, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); }; return Errors; -}); \ No newline at end of file +}); diff --git a/public/src/admin/advanced/events.js b/public/src/admin/advanced/events.js index b4f18414ea..2be2c44ee7 100644 --- a/public/src/admin/advanced/events.js +++ b/public/src/admin/advanced/events.js @@ -1,13 +1,10 @@ -"use strict"; - -/* global define, socket, app */ +'use strict'; define('admin/advanced/events', function () { var Events = {}; Events.init = function () { - $('[data-action="clear"]').on('click', function () { socket.emit('admin.deleteAllEvents', function (err) { if (err) { @@ -16,7 +13,6 @@ define('admin/advanced/events', function () { $('.events-list').empty(); }); }); - }; return Events; diff --git a/public/src/admin/advanced/logs.js b/public/src/admin/advanced/logs.js index 667dcd7280..e756bea7d8 100644 --- a/public/src/admin/advanced/logs.js +++ b/public/src/admin/advanced/logs.js @@ -1,5 +1,5 @@ -"use strict"; -/* global define, socket, app */ +'use strict'; + define('admin/advanced/logs', function () { var Logs = {}; @@ -10,30 +10,30 @@ define('admin/advanced/logs', function () { // Affix menu $('.affix').affix(); - $('.logs').find('button[data-action]').on('click', function (event) { - var btnEl = $(this), - action = btnEl.attr('data-action'); + $('.logs').find('button[data-action]').on('click', function () { + var btnEl = $(this); + var action = btnEl.attr('data-action'); - switch(action) { - case 'reload': - socket.emit('admin.logs.get', function (err, logs) { - if (!err) { - logsEl.text(logs); - logsEl.scrollTop(logsEl.prop('scrollHeight')); - } else { - app.alertError(err.message); - } - }); - break; + switch (action) { + case 'reload': + socket.emit('admin.logs.get', function (err, logs) { + if (!err) { + logsEl.text(logs); + logsEl.scrollTop(logsEl.prop('scrollHeight')); + } else { + app.alertError(err.message); + } + }); + break; - case 'clear': - socket.emit('admin.logs.clear', function (err) { - if (!err) { - app.alertSuccess('[[admin/advanced/logs:clear-success]]'); - btnEl.prev().click(); - } - }); - break; + case 'clear': + socket.emit('admin.logs.clear', function (err) { + if (!err) { + app.alertSuccess('[[admin/advanced/logs:clear-success]]'); + btnEl.prev().click(); + } + }); + break; } }); }; diff --git a/public/src/admin/appearance/customise.js b/public/src/admin/appearance/customise.js index d8ad5e3ecb..566161e5a9 100644 --- a/public/src/admin/appearance/customise.js +++ b/public/src/admin/appearance/customise.js @@ -1,37 +1,36 @@ -"use strict"; -/* global ace, define, app, socket */ +'use strict'; + define('admin/appearance/customise', ['admin/settings'], function (Settings) { var Customise = {}; - - Customise.init = function () { + + Customise.init = function () { Settings.prepare(function () { $('#customCSS').text($('#customCSS-holder').val()); $('#customHTML').text($('#customHTML-holder').val()); - - var customCSS = ace.edit("customCSS"), - customHTML = ace.edit("customHTML"); - customCSS.setTheme("ace/theme/twilight"); - customCSS.getSession().setMode("ace/mode/css"); + var customCSS = ace.edit('customCSS'); + var customHTML = ace.edit('customHTML'); - customCSS.on('change', function (event) { + customCSS.setTheme('ace/theme/twilight'); + customCSS.getSession().setMode('ace/mode/css'); + + customCSS.on('change', function () { app.flags = app.flags || {}; app.flags._unsaved = true; - $('#customCSS-holder').val(customCSS.getValue()); - }); + $('#customCSS-holder').val(customCSS.getValue()); + }); - customHTML.setTheme("ace/theme/twilight"); - customHTML.getSession().setMode("ace/mode/html"); + customHTML.setTheme('ace/theme/twilight'); + customHTML.getSession().setMode('ace/mode/html'); - customHTML.on('change', function (event) { + customHTML.on('change', function () { app.flags = app.flags || {}; app.flags._unsaved = true; - $('#customHTML-holder').val(customHTML.getValue()); - }); + $('#customHTML-holder').val(customHTML.getValue()); + }); }); }; return Customise; }); - \ No newline at end of file diff --git a/public/src/admin/appearance/skins.js b/public/src/admin/appearance/skins.js index 35ad5a2289..f234cac414 100644 --- a/public/src/admin/appearance/skins.js +++ b/public/src/admin/appearance/skins.js @@ -1,14 +1,14 @@ -"use strict"; -/* global define, app, socket, templates */ +'use strict'; + define('admin/appearance/skins', ['translator'], function (translator) { var Skins = {}; - + Skins.init = function () { // Populate skins from Bootswatch API $.ajax({ method: 'get', - url: 'https://bootswatch.com/api/3.json' + url: 'https://bootswatch.com/api/3.json', }).done(Skins.render); $('#skins').on('click', function (e) { @@ -21,16 +21,16 @@ define('admin/appearance/skins', ['translator'], function (translator) { var action = target.attr('data-action'); if (action && action === 'use') { - var parentEl = target.parents('[data-theme]'), - themeType = parentEl.attr('data-type'), - cssSrc = parentEl.attr('data-css'), - themeId = parentEl.attr('data-theme'); + var parentEl = target.parents('[data-theme]'); + var themeType = parentEl.attr('data-type'); + var cssSrc = parentEl.attr('data-css'); + var themeId = parentEl.attr('data-theme'); socket.emit('admin.themes.set', { type: themeType, id: themeId, - src: cssSrc + src: cssSrc, }, function (err) { if (err) { return app.alertError(err.message); @@ -42,7 +42,7 @@ define('admin/appearance/skins', ['translator'], function (translator) { type: 'info', title: '[[admin/appearance/skins:skin-updated]]', message: themeId ? ('[[admin/appearance/skins:applied-success, ' + themeId + ']]') : '[[admin/appearance/skins:revert-success]]', - timeout: 5000 + timeout: 5000, }); }); } @@ -62,10 +62,10 @@ define('admin/appearance/skins', ['translator'], function (translator) { screenshot_url: theme.thumbnail, url: theme.preview, css: theme.cssCdn, - skin: true + skin: true, }; }), - showRevert: true + showRevert: true, }, function (html) { translator.translate(html, function (html) { themeContainer.html(html); @@ -73,7 +73,7 @@ define('admin/appearance/skins', ['translator'], function (translator) { if (config['theme:src']) { var skin = config['theme:src'] .match(/latest\/(\S+)\/bootstrap.min.css/)[1] - .replace(/(^|\s)([a-z])/g , function (m,p1,p2) {return p1 + p2.toUpperCase();}); + .replace(/(^|\s)([a-z])/g, function (m, p1, p2) { return p1 + p2.toUpperCase(); }); highlightSelectedTheme(skin); } diff --git a/public/src/admin/appearance/themes.js b/public/src/admin/appearance/themes.js index 4158f6fef7..68165268b2 100644 --- a/public/src/admin/appearance/themes.js +++ b/public/src/admin/appearance/themes.js @@ -1,24 +1,24 @@ -"use strict"; -/* global define, app, socket, bootbox, templates, config */ +'use strict'; + define('admin/appearance/themes', ['translator'], function (translator) { var Themes = {}; Themes.init = function () { $('#installed_themes').on('click', function (e) { - var target = $(e.target), - action = target.attr('data-action'); + var target = $(e.target); + var action = target.attr('data-action'); if (action && action === 'use') { - var parentEl = target.parents('[data-theme]'), - themeType = parentEl.attr('data-type'), - cssSrc = parentEl.attr('data-css'), - themeId = parentEl.attr('data-theme'); + var parentEl = target.parents('[data-theme]'); + var themeType = parentEl.attr('data-type'); + var cssSrc = parentEl.attr('data-css'); + var themeId = parentEl.attr('data-theme'); socket.emit('admin.themes.set', { type: themeType, id: themeId, - src: cssSrc + src: cssSrc, }, function (err) { if (err) { return app.alertError(err.message); @@ -34,18 +34,18 @@ define('admin/appearance/themes', ['translator'], function (translator) { timeout: 5000, clickfn: function () { socket.emit('admin.restart'); - } + }, }); }); } }); - + $('#revert_theme').on('click', function () { bootbox.confirm('[[admin/appearance/themes:revert-confirm]]', function (confirm) { if (confirm) { socket.emit('admin.themes.set', { type: 'local', - id: 'nodebb-theme-persona' + id: 'nodebb-theme-persona', }, function (err) { if (err) { return app.alertError(err.message); @@ -56,7 +56,7 @@ define('admin/appearance/themes', ['translator'], function (translator) { type: 'success', title: '[[admin/appearance/themes:theme-changed]]', message: '[[admin/appearance/themes:revert-success]]', - timeout: 3500 + timeout: 3500, }); }); } @@ -64,7 +64,7 @@ define('admin/appearance/themes', ['translator'], function (translator) { }); socket.emit('admin.themes.getInstalled', function (err, themes) { - if(err) { + if (err) { return app.alertError(err.message); } @@ -72,10 +72,9 @@ define('admin/appearance/themes', ['translator'], function (translator) { if (!themes.length) { instListEl.append($('
  • ').addClass('no-themes').translateHtml('[[admin/appearance/themes:no-themes]]')); - return; } else { templates.parse('admin/partials/theme_list', { - themes: themes + themes: themes, }, function (html) { translator.translate(html, function (html) { instListEl.html(html); diff --git a/public/src/admin/extend/plugins.js b/public/src/admin/extend/plugins.js index d3774922c6..9622b4fbc0 100644 --- a/public/src/admin/extend/plugins.js +++ b/public/src/admin/extend/plugins.js @@ -1,12 +1,12 @@ -"use strict"; -/* global define, app, socket, bootbox */ +'use strict'; + define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, translator) { var Plugins = {}; Plugins.init = function () { - var pluginsList = $('.plugins'), - numPlugins = pluginsList[0].querySelectorAll('li').length, - pluginID; + var pluginsList = $('.plugins'); + var numPlugins = pluginsList[0].querySelectorAll('li').length; + var pluginID; if (!numPlugins) { translator.translate('
  • [[admin/extend/plugins:none-found]]

  • ', function (html) { @@ -29,7 +29,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t btn.html(buttonText); btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active); - //clone it to active plugins tab + // clone it to active plugins tab if (status.active && !$('#active #' + pluginID).length) { $('#active ul').prepend(pluginEl.clone(true)); } @@ -44,7 +44,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t require(['admin/modules/instance'], function (instance) { instance.restart(); }); - } + }, }); }); }); @@ -71,21 +71,19 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t return; } - require(['semver'], function (semver) { - if (payload.version !== 'latest') { - Plugins.toggleInstall(pluginID, payload.version); - } else if (payload.version === 'latest') { - confirmInstall(pluginID, function (confirm) { - if (confirm) { - Plugins.toggleInstall(pluginID, 'latest'); - } else { - btn.removeAttr('disabled'); - } - }); - } else { - btn.removeAttr('disabled'); - } - }); + if (payload.version !== 'latest') { + Plugins.toggleInstall(pluginID, payload.version); + } else if (payload.version === 'latest') { + confirmInstall(pluginID, function (confirm) { + if (confirm) { + Plugins.toggleInstall(pluginID, 'latest'); + } else { + btn.removeAttr('disabled'); + } + }); + } else { + btn.removeAttr('disabled'); + } }); }); @@ -145,7 +143,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t var plugins = $('#order-active-plugins-modal .plugin-list').children(); var data = []; plugins.each(function (index, el) { - data.push({name: $(el).text(), order: index}); + data.push({ name: $(el).text(), order: index }); }); socket.emit('admin.plugins.orderActivePlugins', data, function (err) { @@ -162,7 +160,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t function confirmInstall(pluginID, callback) { bootbox.confirm(translator.compile('admin/extend/plugins:alert.possibly-incompatible', pluginID), function (confirm) { - callback(confirm); + callback(confirm); }); } @@ -170,7 +168,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t btn.attr('disabled', true).find('i').attr('class', 'fa fa-refresh fa-spin'); socket.emit('admin.plugins.upgrade', { id: pluginID, - version: version + version: version, }, function (err, isActive) { if (err) { return app.alertError(err.message); @@ -190,7 +188,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t require(['admin/modules/instance'], function (instance) { instance.reload(); }); - } + }, }); } }); @@ -198,12 +196,11 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t Plugins.toggleInstall = function (pluginID, version, callback) { var btn = $('li[data-plugin-id="' + pluginID + '"] button[data-action="toggleInstall"]'); - var activateBtn = btn.siblings('[data-action="toggleActive"]'); btn.find('i').attr('class', 'fa fa-refresh fa-spin'); socket.emit('admin.plugins.toggleInstall', { id: pluginID, - version: version + version: version, }, function (err, pluginData) { if (err) { btn.removeAttr('disabled'); @@ -217,7 +214,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t title: '[[admin/extend/plugins:alert.' + (pluginData.installed ? 'installed' : 'uninstalled') + ']]', message: '[[admin/extend/plugins:alert.' + (pluginData.installed ? 'install-success' : 'uninstall-success') + ']]', type: 'info', - timeout: 5000 + timeout: 5000, }); if (typeof callback === 'function') { @@ -232,9 +229,9 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t type: 'GET', data: { package: pluginId, - version: nbbVersion[0] + version: nbbVersion[0], }, - dataType: 'json' + dataType: 'json', }).done(function (payload) { callback(undefined, payload); }).fail(callback); diff --git a/public/src/admin/extend/rewards.js b/public/src/admin/extend/rewards.js index 8b347101f9..fe1322b8e2 100644 --- a/public/src/admin/extend/rewards.js +++ b/public/src/admin/extend/rewards.js @@ -1,14 +1,14 @@ -"use strict"; -/* global define, app, ajaxify, socket, templates, bootbox */ +'use strict'; + define('admin/extend/rewards', ['translator'], function (translator) { var rewards = {}; - var available, - active, - conditions, - conditionals; + var available; + var active; + var conditions; + var conditionals; rewards.init = function () { available = ajaxify.data.rewards; @@ -25,10 +25,10 @@ define('admin/extend/rewards', ['translator'], function (translator) { update($(this)); }) .on('click', '.delete', function () { - var parent = $(this).parents('[data-id]'), - id = parent.attr('data-id'); + var parent = $(this).parents('[data-id]'); + var id = parent.attr('data-id'); - socket.emit('admin.rewards.delete', {id: id}, function (err) { + socket.emit('admin.rewards.delete', { id: id }, function (err) { if (err) { app.alertError(err.message); } else { @@ -40,10 +40,9 @@ define('admin/extend/rewards', ['translator'], function (translator) { return false; }) .on('click', '.toggle', function () { - var btn = $(this), - disabled = btn.hasClass('btn-success'), - id = $(this).parents('[data-id]').attr('data-id'); - btn.toggleClass('btn-warning').toggleClass('btn-success').translateHtml('[[admin/extend/rewards:' + disabled ? 'disable' : 'enable' + ']]'); + var btn = $(this); + var disabled = btn.hasClass('btn-success'); + btn.toggleClass('btn-warning').toggleClass('btn-success').translateHtml('[[admin/extend/rewards:' + (disabled ? 'disable' : 'enable') + ']]'); // send disable api call return false; }); @@ -57,26 +56,26 @@ define('admin/extend/rewards', ['translator'], function (translator) { function select(el) { el.val(el.attr('data-selected')); switch (el.attr('name')) { - case 'rid': - selectReward(el); - break; + case 'rid': + selectReward(el); + break; } } function update(el) { el.attr('data-selected', el.val()); switch (el.attr('name')) { - case 'rid': - selectReward(el); - break; + case 'rid': + selectReward(el); + break; } } function selectReward(el) { - var parent = el.parents('[data-rid]'), - div = parent.find('.inputs'), - inputs, - html = ''; + var parent = el.parents('[data-rid]'); + var div = parent.find('.inputs'); + var inputs; + var html = ''; for (var reward in available) { if (available.hasOwnProperty(reward)) { @@ -95,15 +94,15 @@ define('admin/extend/rewards', ['translator'], function (translator) { inputs.forEach(function (input) { html += '
    '; }); @@ -113,8 +112,8 @@ define('admin/extend/rewards', ['translator'], function (translator) { function populateInputs() { $('[data-rid]').each(function (i) { - var div = $(this).find('.inputs'), - rewards = active[i].rewards; + var div = $(this).find('.inputs'); + var rewards = active[i].rewards; for (var reward in rewards) { if (rewards.hasOwnProperty(reward)) { @@ -133,7 +132,7 @@ define('admin/extend/rewards', ['translator'], function (translator) { value: '', claimable: 1, rid: null, - id: null + id: null, }], conditions: conditions, conditionals: conditionals, @@ -153,9 +152,9 @@ define('admin/extend/rewards', ['translator'], function (translator) { var activeRewards = []; $('#active li').each(function () { - var data = {rewards: {}}, - main = $(this).find('form.main').serializeArray(), - rewards = $(this).find('form.rewards').serializeArray(); + var data = { rewards: {} }; + var main = $(this).find('form.main').serializeArray(); + var rewards = $(this).find('form.rewards').serializeArray(); main.forEach(function (obj) { data[obj.name] = obj.value; diff --git a/public/src/admin/extend/widgets.js b/public/src/admin/extend/widgets.js index 6db6b53490..4394ee9a04 100644 --- a/public/src/admin/extend/widgets.js +++ b/public/src/admin/extend/widgets.js @@ -1,7 +1,7 @@ -"use strict"; -/* global define, app, socket, bootbox */ +'use strict'; -define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { + +define('admin/extend/widgets', ['jqueryui'], function () { var Widgets = {}; Widgets.init = function () { @@ -35,7 +35,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { return $(e.target).parents('.widget-panel').clone(); }, distance: 10, - connectToSortable: ".widget-area" + connectToSortable: '.widget-area', }); $('#widgets .available-containers .containers > [data-container-html]') @@ -46,7 +46,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { return target.clone().addClass('block').width(target.width()).css('opacity', '0.5'); }, - distance: 10 + distance: 10, }) .each(function () { $(this).attr('data-container-html', $(this).attr('data-container-html').replace(/\\\{([\s\S]*?)\\\}/g, '{$1}')); @@ -57,7 +57,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { createDatePicker(ui.item); appendToggle(ui.item); }, - connectWith: "div" + connectWith: 'div', }).on('click', '.delete-widget', function () { var panel = $(this).parents('.widget-panel'); @@ -67,7 +67,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { } }); }).on('mouseup', '> .panel > .panel-heading', function (evt) { - if ( !( $(this).parent().is('.ui-sortable-helper') || $(evt.target).closest('.delete-widget').length ) ) { + if (!($(this).parent().is('.ui-sortable-helper') || $(evt.target).closest('.delete-widget').length)) { $(this).parent().children('.panel-body').toggleClass('hidden'); } }); @@ -80,24 +80,26 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { $('#widgets [data-template][data-location]').each(function (i, el) { el = $(el); - var template = el.attr('data-template'), - location = el.attr('data-location'), - area = el.children('.widget-area'), - widgets = []; + var template = el.attr('data-template'); + var location = el.attr('data-location'); + var area = el.children('.widget-area'); + var widgets = []; area.find('.widget-panel[data-widget]').each(function () { - var widgetData = {}, - data = $(this).find('form').serializeArray(); + var widgetData = {}; + var data = $(this).find('form').serializeArray(); for (var d in data) { if (data.hasOwnProperty(d)) { if (data[d].name) { if (widgetData[data[d].name]) { - if(!Array.isArray(widgetData[data[d].name])) { - widgetData[data[d].name] = [ widgetData[data[d].name] ]; + if (!Array.isArray(widgetData[data[d].name])) { + widgetData[data[d].name] = [ + widgetData[data[d].name], + ]; } widgetData[data[d].name].push(data[d].value); - }else{ + } else { widgetData[data[d].name] = data[d].value; } } @@ -106,16 +108,16 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { widgets.push({ widget: $(this).attr('data-widget'), - data: widgetData + data: widgetData, }); }); socket.emit('admin.widgets.set', { template: template, location: location, - widgets: widgets + widgets: widgets, }, function (err) { - total--; + total -= 1; if (err) { app.alertError(err.message); @@ -127,19 +129,18 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { type: 'success', title: '[[admin/extend/widgets:alert.updated]]', message: '[[admin/extend/widgets:alert.update-success]]', - timeout: 2500 + timeout: 2500, }); } - }); }); } $('.color-selector').on('click', '.btn', function () { - var btn = $(this), - selector = btn.parents('.color-selector'), - container = selector.parents('[data-container-html]'), - classList = []; + var btn = $(this); + var selector = btn.parents('.color-selector'); + var container = selector.parents('[data-container-html]'); + var classList = []; selector.children().each(function () { classList.push($(this).attr('data-class')); @@ -160,7 +161,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { el.find('.date-selector').datepicker({ changeMonth: true, changeYear: true, - yearRange: currentYear + ':' + (currentYear + 100) + yearRange: currentYear + ':' + (currentYear + 100), }); } @@ -175,7 +176,7 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { el.find('.panel-body .container-html').val(ui.draggable.attr('data-container-html')); el.find('.panel-body').removeClass('hidden'); }, - hoverClass: "panel-info" + hoverClass: 'panel-info', }) .children('.panel-heading') .append('
     
    ') @@ -191,8 +192,8 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { } widget.find('input, textarea, select').each(function () { - var input = $(this), - value = data[input.attr('name')]; + var input = $(this); + var value = data[input.attr('name')]; if (input.attr('type') === 'checkbox') { input.prop('checked', !!value).trigger('change'); @@ -207,15 +208,15 @@ define('admin/extend/widgets', ['jqueryui'], function (jqueryui) { $.get(RELATIVE_PATH + '/api/admin/extend/widgets', function (data) { var areas = data.areas; - for(var i = 0; i < areas.length; ++i) { - var area = areas[i], - widgetArea = $('#widgets .area[data-template="' + area.template + '"][data-location="' + area.location + '"]').find('.widget-area'); + for (var i = 0; i < areas.length; i += 1) { + var area = areas[i]; + var widgetArea = $('#widgets .area[data-template="' + area.template + '"][data-location="' + area.location + '"]').find('.widget-area'); widgetArea.html(''); - for (var k = 0; k < area.data.length; ++k) { - var widgetData = area.data[k], - widgetEl = $('.available-widgets [data-widget="' + widgetData.widget + '"]').clone(true).removeClass('hide'); + for (var k = 0; k < area.data.length; k += 1) { + var widgetData = area.data[k]; + var widgetEl = $('.available-widgets [data-widget="' + widgetData.widget + '"]').clone(true).removeClass('hide'); widgetArea.append(populateWidget(widgetEl, widgetData.data)); appendToggle(widgetEl); diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index f9e2589f65..8adb9498ce 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -1,30 +1,32 @@ -"use strict"; -/*global define, ajaxify, app, socket, utils, bootbox, RELATIVE_PATH*/ +'use strict'; + define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (semver, Chart, translator) { var Admin = {}; var intervals = { rooms: false, - graphs: false + graphs: false, }; var isMobile = false; var isPrerelease = /^v?\d+\.\d+\.\d+-.+$/; var graphData = { rooms: {}, - traffic: {} + traffic: {}, }; var currentGraph = { units: 'hours', - until: undefined + until: undefined, }; var DEFAULTS = { roomInterval: 10000, graphInterval: 15000, - realtimeInterval: 1500 + realtimeInterval: 1500, }; - - $(window).on('action:ajaxify.start', function (ev, data) { + + var usedTopicColors = []; + + $(window).on('action:ajaxify.start', function () { clearInterval(intervals.rooms); clearInterval(intervals.graphs); @@ -37,7 +39,6 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s Admin.init = function () { app.enterRoom('admin'); - socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); @@ -51,10 +52,10 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s return !isPrerelease.test(version.name); // filter out automated prerelease versions }); - var version = $('#version').html(), - latestVersion = releases[0].name.slice(1), - checkEl = $('.version-check'), - text; + var version = $('#version').html(); + var latestVersion = releases[0].name.slice(1); + var checkEl = $('.version-check'); + var text; // Alter box colour accordingly if (semver.eq(latestVersion, version)) { @@ -80,8 +81,10 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s $('[data-toggle="tooltip"]').tooltip(); setupRealtimeButton(); - setupGraphs(); - initiateDashboard(); + setupGraphs(function () { + socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); + initiateDashboard(); + }); }; Admin.updateRoomUsage = function (err, data) { @@ -123,51 +126,53 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s traffic: null, registered: null, presence: null, - topics: null + topics: null, }; - var topicColors = ["#bf616a","#5B90BF","#d08770","#ebcb8b","#a3be8c","#96b5b4","#8fa1b3","#b48ead","#ab7967","#46BFBD"]; - var usedTopicColors = []; + var topicColors = ['#bf616a', '#5B90BF', '#d08770', '#ebcb8b', '#a3be8c', '#96b5b4', '#8fa1b3', '#b48ead', '#ab7967', '#46BFBD']; + /* eslint-disable */ // from chartjs.org function lighten(col, amt) { var usePound = false; - if (col[0] == "#") { + if (col[0] === '#') { col = col.slice(1); usePound = true; } - var num = parseInt(col,16); + var num = parseInt(col, 16); var r = (num >> 16) + amt; if (r > 255) r = 255; - else if (r < 0) r = 0; + else if (r < 0) r = 0; var b = ((num >> 8) & 0x00FF) + amt; if (b > 255) b = 255; - else if (b < 0) b = 0; + else if (b < 0) b = 0; var g = (num & 0x0000FF) + amt; if (g > 255) g = 255; else if (g < 0) g = 0; - return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16); + return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16); } + /* eslint-enable */ - function setupGraphs() { - var trafficCanvas = document.getElementById('analytics-traffic'), - registeredCanvas = document.getElementById('analytics-registered'), - presenceCanvas = document.getElementById('analytics-presence'), - topicsCanvas = document.getElementById('analytics-topics'), - trafficCtx = trafficCanvas.getContext('2d'), - registeredCtx = registeredCanvas.getContext('2d'), - presenceCtx = presenceCanvas.getContext('2d'), - topicsCtx = topicsCanvas.getContext('2d'), - trafficLabels = utils.getHoursArray(); + function setupGraphs(callback) { + callback = callback || function () {}; + var trafficCanvas = document.getElementById('analytics-traffic'); + var registeredCanvas = document.getElementById('analytics-registered'); + var presenceCanvas = document.getElementById('analytics-presence'); + var topicsCanvas = document.getElementById('analytics-topics'); + var trafficCtx = trafficCanvas.getContext('2d'); + var registeredCtx = registeredCanvas.getContext('2d'); + var presenceCtx = presenceCanvas.getContext('2d'); + var topicsCtx = topicsCanvas.getContext('2d'); + var trafficLabels = utils.getHoursArray(); if (isMobile) { Chart.defaults.global.tooltips.enabled = false; @@ -190,25 +195,25 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s datasets: [ { label: translations[0], - backgroundColor: "rgba(220,220,220,0.2)", - borderColor: "rgba(220,220,220,1)", - pointBackgroundColor: "rgba(220,220,220,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(220,220,220,1)", - data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] + backgroundColor: 'rgba(220,220,220,0.2)', + borderColor: 'rgba(220,220,220,1)', + pointBackgroundColor: 'rgba(220,220,220,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(220,220,220,1)', + data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, { label: translations[1], - backgroundColor: "rgba(151,187,205,0.2)", - borderColor: "rgba(151,187,205,1)", - pointBackgroundColor: "rgba(151,187,205,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(151,187,205,1)", - data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] - } - ] + backgroundColor: 'rgba(151,187,205,0.2)', + borderColor: 'rgba(151,187,205,1)', + pointBackgroundColor: 'rgba(151,187,205,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(151,187,205,1)', + data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, + ], }; trafficCanvas.width = $(trafficCanvas).parent().width(); @@ -218,34 +223,34 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s options: { responsive: true, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); - + graphs.registered = new Chart(registeredCtx, { type: 'doughnut', data: { labels: translations.slice(2, 4), datasets: [{ data: [1, 1], - backgroundColor: ["#F7464A", "#46BFBD"], - hoverBackgroundColor: ["#FF5A5E", "#5AD3D1"] - }] + backgroundColor: ['#F7464A', '#46BFBD'], + hoverBackgroundColor: ['#FF5A5E', '#5AD3D1'], + }], }, options: { responsive: true, legend: { - display: false - } - } + display: false, + }, + }, }); graphs.presence = new Chart(presenceCtx, { @@ -254,18 +259,18 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s labels: translations.slice(4, 9), datasets: [{ data: [1, 1, 1, 1, 1], - backgroundColor: ["#F7464A", "#46BFBD", "#FDB45C", "#949FB1", "#9FB194"], - hoverBackgroundColor: ["#FF5A5E", "#5AD3D1", "#FFC870", "#A8B3C5", "#A8B3C5"] - }] + backgroundColor: ['#F7464A', '#46BFBD', '#FDB45C', '#949FB1', '#9FB194'], + hoverBackgroundColor: ['#FF5A5E', '#5AD3D1', '#FFC870', '#A8B3C5', '#A8B3C5'], + }], }, options: { responsive: true, legend: { - display: false - } - } + display: false, + }, + }, }); - + graphs.topics = new Chart(topicsCtx, { type: 'doughnut', data: { @@ -273,15 +278,15 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s datasets: [{ data: [], backgroundColor: [], - hoverBackgroundColor: [] - }] + hoverBackgroundColor: [], + }], }, options: { responsive: true, legend: { - display: false - } - } + display: false, + }, + }, }); updateTrafficGraph(); @@ -291,14 +296,16 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s $('[data-action="updateGraph"]').on('click', function () { var until; - switch($(this).attr('data-until')) { - case 'last-month': - var lastMonth = new Date(); - lastMonth.setDate(lastMonth.getDate() - 30); - until = lastMonth.getTime(); + switch ($(this).attr('data-until')) { + case 'last-month': + var lastMonth = new Date(); + lastMonth.setDate(lastMonth.getDate() - 30); + until = lastMonth.getTime(); } updateTrafficGraph($(this).attr('data-units'), until); }); + + callback(); }); } @@ -322,7 +329,7 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s socket.emit('admin.analytics.get', { graph: 'traffic', units: units || 'hours', - until: until + until: until, }, function (err, data) { if (err) { return app.alertError(err.message); @@ -371,36 +378,36 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s graphs.presence.update(); } - + function updateTopicsGraph(topics) { if (!Object.keys(topics).length) { - topics = {"0": { - title: "No users browsing", - value: 1 - }}; + topics = { 0: { + title: 'No users browsing', + value: 1, + } }; } var tids = Object.keys(topics); - + graphs.topics.data.labels = []; graphs.topics.data.datasets[0].data = []; graphs.topics.data.datasets[0].backgroundColor = []; graphs.topics.data.datasets[0].hoverBackgroundColor = []; - - for (var i = 0, ii = tids.length; i < ii; i++) { + + for (var i = 0, ii = tids.length; i < ii; i += 1) { graphs.topics.data.labels.push(topics[tids[i]].title); graphs.topics.data.datasets[0].data.push(topics[tids[i]].value); graphs.topics.data.datasets[0].backgroundColor.push(topicColors[i]); graphs.topics.data.datasets[0].hoverBackgroundColor.push(lighten(topicColors[i], 10)); } - + function buildTopicsLegend() { var legend = $('#topics-legend').html(''); - for (var i = 0, ii = tids.length; i < ii; i++) { + for (var i = 0, ii = tids.length; i < ii; i += 1) { var topic = topics[tids[i]]; var label = topic.value === '0' ? topic.title : ' ' + topic.title + ''; - + legend.append( '
  • ' + '
    ' + diff --git a/public/src/admin/general/homepage.js b/public/src/admin/general/homepage.js index f0239e784c..ca5438c6a1 100644 --- a/public/src/admin/general/homepage.js +++ b/public/src/admin/general/homepage.js @@ -1,12 +1,11 @@ -"use strict"; -/*global define*/ +'use strict'; -define('admin/general/homepage', ['admin/settings'], function (Settings) { +define('admin/general/homepage', ['admin/settings'], function () { function toggleCustomRoute() { if ($('[data-field="homePageRoute"]').val()) { $('#homePageCustom').hide(); - }else{ + } else { $('#homePageCustom').show(); } } diff --git a/public/src/admin/general/languages.js b/public/src/admin/general/languages.js index 8ccf016698..05d3175b27 100644 --- a/public/src/admin/general/languages.js +++ b/public/src/admin/general/languages.js @@ -1,5 +1,5 @@ -"use strict"; -/*global define*/ +'use strict'; + define('admin/general/languages', ['admin/settings'], function (Settings) { var Languages = {}; diff --git a/public/src/admin/general/navigation.js b/public/src/admin/general/navigation.js index 6fa59aff24..5269c1c2c0 100644 --- a/public/src/admin/general/navigation.js +++ b/public/src/admin/general/navigation.js @@ -1,9 +1,9 @@ -"use strict"; -/* global define, app, ajaxify, socket, templates */ +'use strict'; -define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], function (translator, iconSelect, jqueryui) { - var navigation = {}, - available; + +define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], function (translator, iconSelect) { + var navigation = {}; + var available; navigation.init = function () { available = ajaxify.data.available; @@ -18,12 +18,12 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun connectToSortable: '#active-navigation', helper: 'clone', distance: 10, - stop: drop + stop: drop, }); }); - + $('#active-navigation').sortable().droppable({ - accept: $('#available li .drag-item') + accept: $('#available li .drag-item'), }); $('#enabled').on('click', '.iconPicker', function () { @@ -40,8 +40,8 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun $('#active-navigation').on('click', 'li', onSelect); $('#enabled') - .on('click', '.delete', remove) - .on('click', '.toggle', toggle); + .on('click', '.delete', remove) + .on('click', '.toggle', toggle); $('#save').on('click', save); }; @@ -61,14 +61,14 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun } function drop(ev, ui) { - var id = ui.helper.attr('data-id'), - el = $('#active-navigation [data-id="' + id + '"]'), - data = id === 'custom' ? {iconClass: 'fa-navicon'} : available[id]; + var id = ui.helper.attr('data-id'); + var el = $('#active-navigation [data-id="' + id + '"]'); + var data = id === 'custom' ? { iconClass: 'fa-navicon' } : available[id]; data.enabled = false; data.index = (parseInt($('#enabled').children().last().attr('data-index'), 10) || 0) + 1; - templates.parse('admin/general/navigation', 'navigation', {navigation: [data]}, function (li) { + templates.parse('admin/general/navigation', 'navigation', { navigation: [data] }, function (li) { translator.translate(li, function (li) { li = $(translator.unescape(li)); el.after(li); @@ -76,12 +76,12 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun }); }); - templates.parse('admin/general/navigation', 'enabled', {enabled: [data]}, function (li) { + templates.parse('admin/general/navigation', 'enabled', { enabled: [data] }, function (li) { translator.translate(li, function (li) { li = $(translator.unescape(li)); $('#enabled').append(li); componentHandler.upgradeDom(); - }); + }); }); } @@ -95,9 +95,9 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun indices.forEach(function (index) { var el = $('#enabled').children('[data-index="' + index + '"]'); - var form = el.find('form').serializeArray(), - data = {}, - properties = {}; + var form = el.find('form').serializeArray(); + var data = {}; + var properties = {}; form.forEach(function (input) { if (input.name.slice(0, 9) === 'property:' && input.value === 'on') { @@ -135,8 +135,8 @@ define('admin/general/navigation', ['translator', 'iconSelect', 'jqueryui'], fun } function toggle() { - var btn = $(this), - disabled = btn.hasClass('btn-success'); + var btn = $(this); + var disabled = btn.hasClass('btn-success'); translator.translate(disabled ? '[[admin/general/navigation:btn.disable]]' : '[[admin/general/navigation:btn.enable]]', function (html) { btn.toggleClass('btn-warning').toggleClass('btn-success').html(html); btn.parents('li').find('[name="enabled"]').val(disabled ? 'on' : ''); diff --git a/public/src/admin/general/social.js b/public/src/admin/general/social.js index cfcc3d3c52..49ee4e6ad0 100644 --- a/public/src/admin/general/social.js +++ b/public/src/admin/general/social.js @@ -1,5 +1,5 @@ -"use strict"; -/*global define, socket*/ +'use strict'; + define('admin/general/social', [], function () { var social = {}; @@ -12,7 +12,7 @@ define('admin/general/social', [], function () { networks.push($(this).attr('id')); } }); - + socket.emit('admin.social.savePostSharingNetworks', networks, function (err) { if (err) { return app.alertError(err); diff --git a/public/src/admin/general/sounds.js b/public/src/admin/general/sounds.js index 259b21f657..5e17015dd7 100644 --- a/public/src/admin/general/sounds.js +++ b/public/src/admin/general/sounds.js @@ -1,5 +1,5 @@ -"use strict"; -/* global app, define, socket */ +'use strict'; + define('admin/general/sounds', ['sounds', 'settings', 'admin/settings'], function (Sounds, Settings, AdminSettings) { var SoundsAdmin = {}; @@ -13,20 +13,6 @@ define('admin/general/sounds', ['sounds', 'settings', 'admin/settings'], functio Sounds.playSound(soundName); }); - // Load Form Values - Settings.load('sounds', $('.sounds form')); - - // Saving of Form Values - var saveEl = $('#save'); - saveEl.on('click', function () { - Settings.save('sounds', $('.sounds form'), function () { - socket.emit('admin.fireEvent', { - name: 'event:sounds.reloadMapping' - }); - app.alertSuccess('[[admin/general/sounds:saved]]'); - }); - }); - AdminSettings.prepare(); }; diff --git a/public/src/admin/manage/categories.js b/public/src/admin/manage/categories.js index acb55b82e9..cb5d7e9975 100644 --- a/public/src/admin/manage/categories.js +++ b/public/src/admin/manage/categories.js @@ -1,12 +1,14 @@ -"use strict"; -/*global define, socket, app, bootbox, templates, ajaxify, Sortable */ +'use strict'; + define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-serializeobject.min', 'translator'], function (serialize, translator) { - var Categories = {}, newCategoryId = -1, sortables; + var Categories = {}; + var newCategoryId = -1; + var sortables; Categories.init = function () { socket.emit('admin.categories.getAll', function (error, payload) { - if(error) { + if (error) { return app.alertError(error.message); } @@ -17,10 +19,10 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri // Enable/Disable toggle events $('.categories').on('click', 'button[data-action="toggle"]', function () { - var $this = $(this), - cid = $this.attr('data-cid'), - parentEl = $this.parents('li[data-cid="' + cid + '"]'), - disabled = parentEl.hasClass('disabled'); + var $this = $(this); + var cid = $this.attr('data-cid'); + var parentEl = $this.parents('li[data-cid="' + cid + '"]'); + var disabled = parentEl.hasClass('disabled'); var children = parentEl.find('li[data-cid]').map(function () { return $(this).attr('data-cid'); @@ -38,8 +40,20 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri } templates.parse('admin/partials/categories/create', { - categories: categories + categories: categories, }, function (html) { + var modal = bootbox.dialog({ + title: '[[admin/manage/categories:alert.create]]', + message: html, + buttons: { + save: { + label: '[[global:save]]', + className: 'btn-primary', + callback: submit, + }, + }, + }); + function submit() { var formData = modal.find('form').serializeObject(); formData.description = ''; @@ -50,18 +64,6 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri return false; } - var modal = bootbox.dialog({ - title: '[[admin/manage/categories:alert.create]]', - message: html, - buttons: { - save: { - label: '[[global:save]]', - className: 'btn-primary', - callback: submit - } - } - }); - modal.find('form').on('submit', submit); }); }); @@ -78,7 +80,7 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri title: '[[admin/manage/categories:alert.created]]', message: '[[admin/manage/categories:alert.create-success]]', type: 'success', - timeout: 2000 + timeout: 2000, }); ajaxify.go('admin/manage/categories/' + data.cid); @@ -106,7 +108,7 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri cids.forEach(function (cid) { payload[cid] = { - disabled: disabled ? 1 : 0 + disabled: disabled ? 1 : 0, }; }); @@ -123,16 +125,19 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri } function itemDragDidEnd(e) { - var isCategoryUpdate = (newCategoryId != -1); + var isCategoryUpdate = parseInt(newCategoryId, 10) !== -1; - //Update needed? - if((e.newIndex != undefined && e.oldIndex != e.newIndex) || isCategoryUpdate) { - var parentCategory = isCategoryUpdate ? sortables[newCategoryId] : sortables[e.from.dataset.cid], - modified = {}, i = 0, list = parentCategory.toArray(), len = list.length; + // Update needed? + if ((e.newIndex != null && parseInt(e.oldIndex, 10) !== parseInt(e.newIndex, 10)) || isCategoryUpdate) { + var parentCategory = isCategoryUpdate ? sortables[newCategoryId] : sortables[e.from.dataset.cid]; + var modified = {}; + var i = 0; + var list = parentCategory.toArray(); + var len = list.length; - for(i; i < len; ++i) { + for (i; i < len; i += 1) { modified[list[i]] = { - order: (i + 1) + order: (i + 1), }; } @@ -161,7 +166,7 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri if (category.name !== translated) { category.name = translated; } - ++count; + count += 1; if (count === parent.length) { continueRender(); @@ -176,13 +181,13 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri function continueRender() { templates.parse('admin/partials/categories/category-rows', { cid: parentId, - categories: categories + categories: categories, }, function (html) { translator.translate(html, function (html) { container.append(html); // Handle and children categories in this level have - for(var x = 0,numCategories = categories.length; x < numCategories; x++) { + for (var x = 0, numCategories = categories.length; x < numCategories; x += 1) { renderList(categories[x].children, $('li[data-cid="' + categories[x].cid + '"]'), categories[x].cid); } @@ -192,9 +197,9 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri animation: 150, handle: '.icon', dataIdAttr: 'data-cid', - ghostClass: "placeholder", + ghostClass: 'placeholder', onAdd: itemDidAdd, - onEnd: itemDragDidEnd + onEnd: itemDragDidEnd, }); }); }); @@ -202,4 +207,4 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri } return Categories; -}); \ No newline at end of file +}); diff --git a/public/src/admin/manage/category-analytics.js b/public/src/admin/manage/category-analytics.js index 4bd80c305e..c9d4d55c2e 100644 --- a/public/src/admin/manage/category-analytics.js +++ b/public/src/admin/manage/category-analytics.js @@ -1,5 +1,5 @@ -"use strict"; -/*global define, ajaxify, utils */ +'use strict'; + define('admin/manage/category-analytics', ['Chart'], function (Chart) { var CategoryAnalytics = {}; @@ -10,11 +10,11 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { var topicsCanvas = document.getElementById('topics:daily'); var postsCanvas = document.getElementById('posts:daily'); var hourlyLabels = utils.getHoursArray().map(function (text, idx) { - return idx % 3 ? '' : text; - }); + return idx % 3 ? '' : text; + }); var dailyLabels = utils.getDaysArray().map(function (text, idx) { - return idx % 3 ? '' : text; - }); + return idx % 3 ? '' : text; + }); if (utils.isMobile()) { Chart.defaults.global.tooltips.enabled = false; @@ -25,69 +25,69 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { labels: hourlyLabels, datasets: [ { - label: "", - backgroundColor: "rgba(186,139,175,0.2)", - borderColor: "rgba(186,139,175,1)", - pointBackgroundColor: "rgba(186,139,175,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(186,139,175,1)", - data: ajaxify.data.analytics['pageviews:hourly'] - } - ] + label: '', + backgroundColor: 'rgba(186,139,175,0.2)', + borderColor: 'rgba(186,139,175,1)', + pointBackgroundColor: 'rgba(186,139,175,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(186,139,175,1)', + data: ajaxify.data.analytics['pageviews:hourly'], + }, + ], }, 'pageviews:daily': { labels: dailyLabels, datasets: [ { - label: "", - backgroundColor: "rgba(151,187,205,0.2)", - borderColor: "rgba(151,187,205,1)", - pointBackgroundColor: "rgba(151,187,205,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(151,187,205,1)", - data: ajaxify.data.analytics['pageviews:daily'] - } - ] + label: '', + backgroundColor: 'rgba(151,187,205,0.2)', + borderColor: 'rgba(151,187,205,1)', + pointBackgroundColor: 'rgba(151,187,205,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(151,187,205,1)', + data: ajaxify.data.analytics['pageviews:daily'], + }, + ], }, 'topics:daily': { labels: dailyLabels.slice(-7), datasets: [ { - label: "", - backgroundColor: "rgba(171,70,66,0.2)", - borderColor: "rgba(171,70,66,1)", - pointBackgroundColor: "rgba(171,70,66,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(171,70,66,1)", - data: ajaxify.data.analytics['topics:daily'] - } - ] + label: '', + backgroundColor: 'rgba(171,70,66,0.2)', + borderColor: 'rgba(171,70,66,1)', + pointBackgroundColor: 'rgba(171,70,66,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(171,70,66,1)', + data: ajaxify.data.analytics['topics:daily'], + }, + ], }, 'posts:daily': { labels: dailyLabels.slice(-7), datasets: [ { - label: "", - backgroundColor: "rgba(161,181,108,0.2)", - borderColor: "rgba(161,181,108,1)", - pointBackgroundColor: "rgba(161,181,108,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(161,181,108,1)", - data: ajaxify.data.analytics['posts:daily'] - } - ] - } + label: '', + backgroundColor: 'rgba(161,181,108,0.2)', + borderColor: 'rgba(161,181,108,1)', + pointBackgroundColor: 'rgba(161,181,108,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(161,181,108,1)', + data: ajaxify.data.analytics['posts:daily'], + }, + ], + }, }; hourlyCanvas.width = $(hourlyCanvas).parent().width(); dailyCanvas.width = $(dailyCanvas).parent().width(); topicsCanvas.width = $(topicsCanvas).parent().width(); postsCanvas.width = $(postsCanvas).parent().width(); - + new Chart(hourlyCanvas.getContext('2d'), { type: 'line', data: data['pageviews:hourly'], @@ -95,18 +95,18 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { responsive: true, animation: false, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); - + new Chart(dailyCanvas.getContext('2d'), { type: 'line', data: data['pageviews:daily'], @@ -114,18 +114,18 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { responsive: true, animation: false, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); - + new Chart(topicsCanvas.getContext('2d'), { type: 'line', data: data['topics:daily'], @@ -133,18 +133,18 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { responsive: true, animation: false, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); - + new Chart(postsCanvas.getContext('2d'), { type: 'line', data: data['posts:daily'], @@ -152,18 +152,18 @@ define('admin/manage/category-analytics', ['Chart'], function (Chart) { responsive: true, animation: false, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); }; return CategoryAnalytics; -}); \ No newline at end of file +}); diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index cb0eb22a35..22fc5d77ec 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -1,12 +1,12 @@ -"use strict"; -/*global config, define, app, socket, ajaxify, bootbox, templates */ +'use strict'; + define('admin/manage/category', [ 'uploader', 'iconSelect', 'admin/modules/colorpicker', 'autocomplete', - 'translator' + 'translator', ], function (uploader, iconSelect, colorpicker, autocomplete, translator) { var Category = {}; var modified_categories = {}; @@ -26,40 +26,14 @@ define('admin/manage/category', [ } } - function save(e) { - e.preventDefault(); - - if(Object.keys(modified_categories).length) { - socket.emit('admin.categories.update', modified_categories, function (err, results) { - if (err) { - return app.alertError(err.message); - } - - if (results && results.length) { - app.flags._unsaved = false; - app.alert({ - title: '[[admin/manage/categories:alert.updated]]', - message: translator.compile( - 'admin/manage/categories:alert.updated-success', - results.join(', ') - ), - type: 'success', - timeout: 2000 - }); - } - }); - modified_categories = {}; - } - } - $('.blockclass, form.category select').each(function () { var $this = $(this); $this.val($this.attr('data-value')); }); function enableColorPicker(idx, inputEl) { - var $inputEl = $(inputEl), - previewEl = $inputEl.parents('[data-cid]').find('.category-preview'); + var $inputEl = $(inputEl); + var previewEl = $inputEl.parents('[data-cid]').find('.category-preview'); colorpicker.enable($inputEl, function (hsb, hex) { if ($inputEl.attr('data-name') === 'bgColor') { @@ -103,7 +77,7 @@ define('admin/manage/category', [ title: 'Updated Categories', message: 'Category IDs ' + result.join(', ') + ' was successfully updated.', type: 'success', - timeout: 2000 + timeout: 2000, }); } }); @@ -134,7 +108,7 @@ define('admin/manage/category', [ $('.copy-settings').on('click', function () { selectCategoryModal(function (cid) { - socket.emit('admin.categories.copySettingsFrom', {fromCid: cid, toCid: ajaxify.data.category.cid}, function (err) { + socket.emit('admin.categories.copySettingsFrom', { fromCid: cid, toCid: ajaxify.data.category.cid }, function (err) { if (err) { return app.alertError(err.message); } @@ -152,7 +126,7 @@ define('admin/manage/category', [ uploader.show({ title: '[[admin/manage/categories:alert.upload-image]]', route: config.relative_path + '/api/admin/category/uploadpicture', - params: {cid: cid} + params: { cid: cid }, }, function (imageUrlOnServer) { $('#category-image').val(imageUrlOnServer); var previewBox = inputEl.parent().parent().siblings('.category-preview'); @@ -186,7 +160,7 @@ define('admin/manage/category', [ $('button[data-action="removeParent"]').on('click', function () { var payload = {}; payload[ajaxify.data.category.cid] = { - parentCid: 0 + parentCid: 0, }; socket.emit('admin.categories.update', payload, function (err) { @@ -220,26 +194,26 @@ define('admin/manage/category', [ var tagEl = $('#tag-whitelist'); tagEl.tagsinput({ confirmKeys: [13, 44], - trimValue: true + trimValue: true, }); ajaxify.data.category.tagWhitelist.forEach(function (tag) { tagEl.tagsinput('add', tag); }); - tagEl.on('itemAdded itemRemoved', function (event) { + tagEl.on('itemAdded itemRemoved', function () { modified(tagEl); }); } Category.setupPrivilegeTable = function () { $('.privilege-table-container').on('change', 'input[type="checkbox"]', function () { - var checkboxEl = $(this), - privilege = checkboxEl.parent().attr('data-privilege'), - state = checkboxEl.prop('checked'), - rowEl = checkboxEl.parents('tr'), - member = rowEl.attr('data-group-name') || rowEl.attr('data-uid'), - isPrivate = parseInt(rowEl.attr('data-private') || 0, 10), - isGroup = rowEl.attr('data-group-name') !== undefined; + var checkboxEl = $(this); + var privilege = checkboxEl.parent().attr('data-privilege'); + var state = checkboxEl.prop('checked'); + var rowEl = checkboxEl.parents('tr'); + var member = rowEl.attr('data-group-name') || rowEl.attr('data-uid'); + var isPrivate = parseInt(rowEl.attr('data-private') || 0, 10); + var isGroup = rowEl.attr('data-group-name') !== undefined; if (member) { if (isGroup && privilege === 'groups:moderate' && !isPrivate && state) { @@ -247,7 +221,7 @@ define('admin/manage/category', [ if (confirm) { Category.setPrivilege(member, privilege, state, checkboxEl); } else { - checkboxEl.prop('checked', checkboxEl.prop('checked') ^ 1); + checkboxEl.prop('checked', !checkboxEl.prop('checked')); } }); } else { @@ -273,7 +247,7 @@ define('admin/manage/category', [ } templates.parse('admin/partials/categories/privileges', { - privileges: privileges + privileges: privileges, }, function (html) { translator.translate(html, function (html) { $('.privilege-table-container').html(html); @@ -295,7 +269,7 @@ define('admin/manage/category', [ privs.push(el.getAttribute('data-privilege')); } }); - for(var x = 0,numPrivs = privs.length; x < numPrivs; x++) { + for (var x = 0, numPrivs = privs.length; x < numPrivs; x += 1) { var inputs = $('.privilege-table tr[data-group-name]:not([data-group-name="registered-users"],[data-group-name="guests"]) td[data-privilege="' + privs[x] + '"] input'); inputs.each(function (idx, el) { if (!el.checked) { @@ -310,7 +284,7 @@ define('admin/manage/category', [ cid: ajaxify.data.category.cid, privilege: privilege, set: state, - member: member + member: member, }, function (err) { if (err) { return app.alertError(err.message); @@ -332,19 +306,19 @@ define('admin/manage/category', [ }); templates.parse('partials/category_list', { - categories: categories + categories: categories, }, function (html) { var modal = bootbox.dialog({ message: html, - title: '[[admin/manage/categories:alert.set-parent-category]]' + title: '[[admin/manage/categories:alert.set-parent-category]]', }); modal.find('li[data-cid]').on('click', function () { - var parentCid = $(this).attr('data-cid'), - payload = {}; + var parentCid = $(this).attr('data-cid'); + var payload = {}; payload[ajaxify.data.category.cid] = { - parentCid: parentCid + parentCid: parentCid, }; socket.emit('admin.categories.update', payload, function (err) { @@ -371,7 +345,7 @@ define('admin/manage/category', [ var modal = bootbox.dialog({ title: '[[admin/manage/categories:alert.find-user]]', message: '', - show: true + show: true, }); modal.on('shown.bs.modal', function () { @@ -382,7 +356,7 @@ define('admin/manage/category', [ cid: ajaxify.data.category.cid, privilege: ['find', 'read', 'topics:read'], set: true, - member: ui.item.user.uid + member: ui.item.user.uid, }, function (err) { if (err) { return app.alertError(err.message); @@ -399,7 +373,7 @@ define('admin/manage/category', [ var modal = bootbox.dialog({ title: '[[admin/manage/categories:alert.find-group]]', message: '', - show: true + show: true, }); modal.on('shown.bs.modal', function () { @@ -410,7 +384,7 @@ define('admin/manage/category', [ cid: ajaxify.data.category.cid, privilege: ['groups:find', 'groups:read', 'groups:topics:read'], set: true, - member: ui.item.group.name + member: ui.item.group.name, }, function (err) { if (err) { return app.alertError(err.message); @@ -434,7 +408,7 @@ define('admin/manage/category', [ Category.copyPrivilegesFromCategory = function () { selectCategoryModal(function (cid) { - socket.emit('admin.categories.copyPrivilegesFrom', {toCid: ajaxify.data.category.cid, fromCid: cid}, function (err) { + socket.emit('admin.categories.copyPrivilegesFrom', { toCid: ajaxify.data.category.cid, fromCid: cid }, function (err) { if (err) { return app.alertError(err.message); } @@ -450,16 +424,9 @@ define('admin/manage/category', [ } templates.parse('admin/partials/categories/select-category', { - categories: categories + categories: categories, }, function (html) { translator.translate(html, function (html) { - function submit() { - var formData = modal.find('form').serializeObject(); - callback(formData['select-cid']); - modal.modal('hide'); - return false; - } - var modal = bootbox.dialog({ title: 'Select a Category', message: html, @@ -467,11 +434,18 @@ define('admin/manage/category', [ save: { label: 'Copy', className: 'btn-primary', - callback: submit - } - } + callback: submit, + }, + }, }); + function submit() { + var formData = modal.find('form').serializeObject(); + callback(formData['select-cid']); + modal.modal('hide'); + return false; + } + modal.find('form').on('submit', submit); }); }); @@ -480,4 +454,4 @@ define('admin/manage/category', [ return Category; -}); \ No newline at end of file +}); diff --git a/public/src/admin/manage/flags.js b/public/src/admin/manage/flags.js index 0bf47060dd..26e9bd3f73 100644 --- a/public/src/admin/manage/flags.js +++ b/public/src/admin/manage/flags.js @@ -1,13 +1,12 @@ -"use strict"; -/*global define, socket, app, utils, bootbox, ajaxify*/ +'use strict'; + define('admin/manage/flags', [ 'autocomplete', 'Chart', 'components', - 'translator' + 'translator', ], function (autocomplete, Chart, components, translator) { - var Flags = {}; Flags.init = function () { @@ -38,7 +37,7 @@ define('admin/manage/flags', [ socket.emit('posts.dismissFlag', pid, function (err) { done(err, btn); }); - }); + }); } function handleDismissAll() { @@ -63,7 +62,7 @@ define('admin/manage/flags', [ } var pid = btn.parents('[data-pid]').attr('data-pid'); var tid = btn.parents('[data-pid]').attr('data-tid'); - socket.emit('posts.delete', {pid: pid, tid: tid}, function (err) { + socket.emit('posts.delete', { pid: pid, tid: tid }, function (err) { done(err, btn); }); }); @@ -98,17 +97,17 @@ define('admin/manage/flags', [ labels: dailyLabels, datasets: [ { - label: "", - backgroundColor: "rgba(151,187,205,0.2)", - borderColor: "rgba(151,187,205,1)", - pointBackgroundColor: "rgba(151,187,205,1)", - pointHoverBackgroundColor: "#fff", - pointBorderColor: "#fff", - pointHoverBorderColor: "rgba(151,187,205,1)", - data: ajaxify.data.analytics - } - ] - } + label: '', + backgroundColor: 'rgba(151,187,205,0.2)', + borderColor: 'rgba(151,187,205,1)', + pointBackgroundColor: 'rgba(151,187,205,1)', + pointHoverBackgroundColor: '#fff', + pointBorderColor: '#fff', + pointHoverBorderColor: 'rgba(151,187,205,1)', + data: ajaxify.data.analytics, + }, + ], + }, }; dailyCanvas.width = $(dailyCanvas).parent().width(); @@ -119,21 +118,21 @@ define('admin/manage/flags', [ responsive: true, animation: false, legend: { - display: false + display: false, }, scales: { yAxes: [{ ticks: { - beginAtZero: true - } - }] - } - } + beginAtZero: true, + }, + }], + }, + }, }); } function updateFlagDetails(source) { - // As the flag details are returned in the API, + // As the flag details are returned in the API, // update the form controls to show the correct data // Create reference hash for use in this method @@ -147,7 +146,7 @@ define('admin/manage/flags', [ el = $(el); if (source[pid]) { - for(var prop in source[pid]) { + for (var prop in source[pid]) { if (source[pid].hasOwnProperty(prop)) { el.find('[name="' + prop + '"]').val(source[pid][prop]); } @@ -162,15 +161,14 @@ define('admin/manage/flags', [ socket.emit('posts.updateFlag', { pid: pid, - data: formData + data: formData, }, function (err) { if (err) { return app.alertError(err.message); - } else { - app.alertSuccess('[[topic:flag_manage_saved]]'); } + app.alertSuccess('[[topic:flag_manage_saved]]'); }); } return Flags; -}); \ No newline at end of file +}); diff --git a/public/src/admin/manage/group.js b/public/src/admin/manage/group.js index 05337f9f97..a4ed2eab7c 100644 --- a/public/src/admin/manage/group.js +++ b/public/src/admin/manage/group.js @@ -1,22 +1,22 @@ -"use strict"; -/*global define, templates, socket, ajaxify, app, bootbox */ +'use strict'; + define('admin/manage/group', [ 'forum/groups/memberlist', 'iconSelect', 'admin/modules/colorpicker', - 'translator' + 'translator', ], function (memberList, iconSelect, colorpicker, translator) { var Groups = {}; Groups.init = function () { - var groupDetailsSearch = $('#group-details-search'), - groupDetailsSearchResults = $('#group-details-search-results'), - groupIcon = $('#group-icon'), - changeGroupUserTitle = $('#change-group-user-title'), - changeGroupLabelColor = $('#change-group-label-color'), - groupLabelPreview = $('#group-label-preview'), - searchDelay; + var groupDetailsSearch = $('#group-details-search'); + var groupDetailsSearchResults = $('#group-details-search-results'); + var groupIcon = $('#group-icon'); + var changeGroupUserTitle = $('#change-group-user-title'); + var changeGroupLabelColor = $('#change-group-label-color'); + var groupLabelPreview = $('#group-label-preview'); + var searchDelay; var groupName = ajaxify.data.group.name; @@ -32,28 +32,27 @@ define('admin/manage/group', [ }); groupDetailsSearch.on('keyup', function () { - if (searchDelay) { clearTimeout(searchDelay); } searchDelay = setTimeout(function () { - var searchText = groupDetailsSearch.val(), - foundUser; + var searchText = groupDetailsSearch.val(); + var foundUser; socket.emit('admin.user.search', { - query: searchText + query: searchText, }, function (err, results) { if (!err && results && results.users.length > 0) { - var numResults = results.users.length, - x; + var numResults = results.users.length; + var x; if (numResults > 20) { numResults = 20; } groupDetailsSearchResults.empty(); - for (x = 0; x < numResults; x++) { + for (x = 0; x < numResults; x += 1) { foundUser = $('
  • '); foundUser .attr({ @@ -63,7 +62,7 @@ define('admin/manage/group', [ 'data-userslug': results.users[x].userslug, 'data-picture': results.users[x].picture, 'data-usericon-bgColor': results.users[x]['icon:bgColor'], - 'data-usericon-text': results.users[x]['icon:text'] + 'data-usericon-text': results.users[x]['icon:text'], }) .append(results.users[x].picture ? $('').addClass('avatar avatar-sm').attr('src', results.users[x].picture) : @@ -80,12 +79,12 @@ define('admin/manage/group', [ }); groupDetailsSearchResults.on('click', 'li[data-uid]', function () { - var userLabel = $(this), - uid = parseInt(userLabel.attr('data-uid'), 10); + var userLabel = $(this); + var uid = parseInt(userLabel.attr('data-uid'), 10); socket.emit('admin.groups.join', { groupName: groupName, - uid: uid + uid: uid, }, function (err) { if (err) { return app.alertError(err.message); @@ -96,15 +95,15 @@ define('admin/manage/group', [ username: userLabel.attr('data-username'), userslug: userLabel.attr('data-userslug'), picture: userLabel.attr('data-picture'), - "icon:bgColor": userLabel.attr('data-usericon-bgColor'), - "icon:text": userLabel.attr('data-usericon-text') + 'icon:bgColor': userLabel.attr('data-usericon-bgColor'), + 'icon:text': userLabel.attr('data-usericon-text'), }; templates.parse('admin/partials/groups/memberlist', 'members', { group: { isOwner: ajaxify.data.group.isOwner, - members: [member] - } + members: [member], + }, }, function (html) { translator.translate(html, function (html) { $('[component="groups/members"] tbody').prepend(html); @@ -114,18 +113,18 @@ define('admin/manage/group', [ }); $('[component="groups/members"]').on('click', '[data-action]', function () { - var btnEl = $(this), - userRow = btnEl.parents('[data-uid]'), - ownerFlagEl = userRow.find('.member-name i'), - isOwner = !ownerFlagEl.hasClass('invisible') ? true : false, - uid = userRow.attr('data-uid'), - action = btnEl.attr('data-action'); + var btnEl = $(this); + var userRow = btnEl.parents('[data-uid]'); + var ownerFlagEl = userRow.find('.member-name i'); + var isOwner = !ownerFlagEl.hasClass('invisible'); + var uid = userRow.attr('data-uid'); + var action = btnEl.attr('data-action'); switch (action) { case 'toggleOwnership': socket.emit('groups.' + (isOwner ? 'rescind' : 'grant'), { toUid: uid, - groupName: groupName + groupName: groupName, }, function (err) { if (err) { return app.alertError(err.message); @@ -141,14 +140,13 @@ define('admin/manage/group', [ } socket.emit('admin.groups.leave', { uid: uid, - groupName: groupName + groupName: groupName, }, function (err) { if (err) { return app.alertError(err.message); } userRow.slideUp().remove(); }); - }); break; default: @@ -176,8 +174,8 @@ define('admin/manage/group', [ userTitleEnabled: $('#group-userTitleEnabled').is(':checked'), private: $('#group-private').is(':checked'), hidden: $('#group-hidden').is(':checked'), - disableJoinRequests: $('#group-disableJoinRequests').is(':checked') - } + disableJoinRequests: $('#group-disableJoinRequests').is(':checked'), + }, }, function (err) { if (err) { return app.alertError(err.message); @@ -194,7 +192,6 @@ define('admin/manage/group', [ }); return false; }); - }; return Groups; diff --git a/public/src/admin/manage/groups.js b/public/src/admin/manage/groups.js index 5c30e7f3cd..5aa7b969b7 100644 --- a/public/src/admin/manage/groups.js +++ b/public/src/admin/manage/groups.js @@ -1,5 +1,5 @@ -"use strict"; -/*global define, templates, socket, ajaxify, app, admin, bootbox, utils, config */ +'use strict'; + define('admin/manage/groups', ['translator'], function (translator) { var Groups = {}; @@ -7,10 +7,10 @@ define('admin/manage/groups', ['translator'], function (translator) { var intervalId = 0; Groups.init = function () { - var createModal = $('#create-modal'), - createGroupName = $('#create-group-name'), - createModalGo = $('#create-modal-go'), - createModalError = $('#create-modal-error'); + var createModal = $('#create-modal'); + var createGroupName = $('#create-group-name'); + var createModalGo = $('#create-modal-go'); + var createModalError = $('#create-modal-error'); handleSearch(); @@ -29,10 +29,9 @@ define('admin/manage/groups', ['translator'], function (translator) { createModalGo.on('click', function () { var submitObj = { - name: createGroupName.val(), - description: $('#create-group-desc').val() - }, - errorText; + name: createGroupName.val(), + description: $('#create-group-desc').val(), + }; socket.emit('admin.groups.create', submitObj, function (err) { if (err) { @@ -52,18 +51,18 @@ define('admin/manage/groups', ['translator'], function (translator) { }); $('.groups-list').on('click', 'button[data-action]', function () { - var el = $(this), - action = el.attr('data-action'), - groupName = el.parents('tr[data-groupname]').attr('data-groupname'); + var el = $(this); + var action = el.attr('data-action'); + var groupName = el.parents('tr[data-groupname]').attr('data-groupname'); switch (action) { case 'delete': bootbox.confirm('[[admin/manage/groups:alerts.confirm-delete]]', function (confirm) { if (confirm) { socket.emit('groups.delete', { - groupName: groupName - }, function (err, data) { - if(err) { + groupName: groupName, + }, function (err) { + if (err) { return app.alertError(err.message); } @@ -77,6 +76,8 @@ define('admin/manage/groups', ['translator'], function (translator) { }; function handleSearch() { + var queryEl = $('#group-search'); + function doSearch() { if (!queryEl.val()) { return ajaxify.refresh(); @@ -86,15 +87,15 @@ define('admin/manage/groups', ['translator'], function (translator) { socket.emit('groups.search', { query: queryEl.val(), options: { - sort: 'date' - } + sort: 'date', + }, }, function (err, groups) { if (err) { return app.alertError(err.message); } templates.parse('admin/manage/groups', 'groups', { - groups: groups + groups: groups, }, function (html) { translator.translate(html, function (html) { groupsEl.find('[data-groupname]').remove(); @@ -104,8 +105,6 @@ define('admin/manage/groups', ['translator'], function (translator) { }); } - var queryEl = $('#group-search'); - queryEl.on('keyup', function () { if (intervalId) { clearTimeout(intervalId); diff --git a/public/src/admin/manage/ip-blacklist.js b/public/src/admin/manage/ip-blacklist.js index 321bc9fac1..0b565325d7 100644 --- a/public/src/admin/manage/ip-blacklist.js +++ b/public/src/admin/manage/ip-blacklist.js @@ -1,15 +1,14 @@ 'use strict'; -/* globals $, app, socket, templates, define, bootbox */ -define('admin/manage/ip-blacklist', ['translator'], function (translator) { +define('admin/manage/ip-blacklist', [], function () { var Blacklist = {}; Blacklist.init = function () { var blacklist = $('#blacklist-rules'); blacklist.on('keyup', function () { - $('#blacklist-rules-holder').val(blacklist.val()); + $('#blacklist-rules-holder').val(blacklist.val()); }); $('[data-action="apply"]').on('click', function () { @@ -27,7 +26,7 @@ define('admin/manage/ip-blacklist', ['translator'], function (translator) { $('[data-action="test"]').on('click', function () { socket.emit('blacklist.validate', { - rules: blacklist.val() + rules: blacklist.val(), }, function (err, data) { if (err) { return app.alertError(err.message); @@ -41,4 +40,4 @@ define('admin/manage/ip-blacklist', ['translator'], function (translator) { }; return Blacklist; -}); \ No newline at end of file +}); diff --git a/public/src/admin/manage/registration.js b/public/src/admin/manage/registration.js index 864ce2bf86..048aafbf96 100644 --- a/public/src/admin/manage/registration.js +++ b/public/src/admin/manage/registration.js @@ -1,19 +1,17 @@ -"use strict"; +'use strict'; -/* global config, socket, define, templates, bootbox, app, ajaxify, */ define('admin/manage/registration', function () { var Registration = {}; Registration.init = function () { - - $('.users-list').on('click', '[data-action]', function (ev) { + $('.users-list').on('click', '[data-action]', function () { var parent = $(this).parents('[data-username]'); var action = $(this).attr('data-action'); var username = parent.attr('data-username'); var method = action === 'accept' ? 'admin.user.acceptRegistration' : 'admin.user.rejectRegistration'; - socket.emit(method, {username: username}, function (err) { + socket.emit(method, { username: username }, function (err) { if (err) { return app.alertError(err.message); } @@ -22,7 +20,7 @@ define('admin/manage/registration', function () { return false; }); - $('.invites-list').on('click', '[data-action]', function (ev) { + $('.invites-list').on('click', '[data-action]', function () { var parent = $(this).parents('[data-invitation-mail][data-invited-by]'); var email = parent.attr('data-invitation-mail'); var invitedBy = parent.attr('data-invited-by'); @@ -30,9 +28,9 @@ define('admin/manage/registration', function () { var method = 'admin.user.deleteInvitation'; var removeRow = function () { - var nextRow = parent.next(), - thisRowinvitedBy = parent.find('.invited-by'), - nextRowInvitedBy = nextRow.find('.invited-by'); + var nextRow = parent.next(); + var thisRowinvitedBy = parent.find('.invited-by'); + var nextRowInvitedBy = nextRow.find('.invited-by'); if (nextRowInvitedBy.html() !== undefined && nextRowInvitedBy.html().length < 2) { nextRowInvitedBy.html(thisRowinvitedBy.html()); } @@ -41,7 +39,7 @@ define('admin/manage/registration', function () { if (action === 'delete') { bootbox.confirm('[[admin/manage/registration:invitations.confirm-delete]]', function (confirm) { if (confirm) { - socket.emit(method, {email: email, invitedBy: invitedBy}, function (err) { + socket.emit(method, { email: email, invitedBy: invitedBy }, function (err) { if (err) { return app.alertError(err.message); } diff --git a/public/src/admin/manage/tags.js b/public/src/admin/manage/tags.js index 9ead604c3f..717d4bba1d 100644 --- a/public/src/admin/manage/tags.js +++ b/public/src/admin/manage/tags.js @@ -1,13 +1,13 @@ -"use strict"; -/*global define, socket, app, utils, bootbox, ajaxify*/ +'use strict'; + define('admin/manage/tags', [ 'forum/infinitescroll', 'admin/modules/selectable', - 'admin/modules/colorpicker' + 'admin/modules/colorpicker', ], function (infinitescroll, selectable, colorpicker) { - var Tags = {}, - timeoutId = 0; + var Tags = {}; + var timeoutId = 0; Tags.init = function () { selectable.enable('.tag-management', '.tag-row'); @@ -38,7 +38,7 @@ define('admin/manage/tags', [ createModalGo.on('click', function () { socket.emit('admin.tags.create', { - tag: createTagName.val() + tag: createTagName.val(), }, function (err) { if (err) { return app.alertError(err.message); @@ -62,14 +62,14 @@ define('admin/manage/tags', [ timeoutId = setTimeout(function () { socket.emit('topics.searchAndLoadTags', { - query: $('#tag-search').val() + query: $('#tag-search').val(), }, function (err, result) { if (err) { return app.alertError(err.message); } app.parseAndTranslate('admin/manage/tags', 'tags', { - tags: result.tags + tags: result.tags, }, function (html) { $('.tag-list').html(html); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); @@ -89,20 +89,20 @@ define('admin/manage/tags', [ return; } - var firstTag = $(tagsToModify[0]), - title = tagsToModify.length > 1 ? '[[admin/manage/tags:alerts.editing-multiple]]' : '[[admin/manage/tags:alerts.editing-x, ' + firstTag.find('.tag-item').attr('data-tag') + ']]'; + var firstTag = $(tagsToModify[0]); + var title = tagsToModify.length > 1 ? '[[admin/manage/tags:alerts.editing-multiple]]' : '[[admin/manage/tags:alerts.editing-x, ' + firstTag.find('.tag-item').attr('data-tag') + ']]'; var modal = bootbox.dialog({ title: title, message: firstTag.find('.tag-modal').html(), buttons: { success: { - label: "Save", - className: "btn-primary save", + label: 'Save', + className: 'btn-primary save', callback: function () { - var modal = $('.bootbox'), - bgColor = modal.find('[data-name="bgColor"]').val(), - color = modal.find('[data-name="color"]').val(); + var modal = $('.bootbox'); + var bgColor = modal.find('[data-name="bgColor"]').val(); + var color = modal.find('[data-name="color"]').val(); tagsToModify.each(function (idx, tag) { tag = $(tag); @@ -113,9 +113,9 @@ define('admin/manage/tags', [ save(tag); }); - } - } - } + }, + }, + }, }); handleColorPickers(modal); @@ -138,7 +138,7 @@ define('admin/manage/tags', [ tags.push($(el).attr('data-tag')); }); socket.emit('admin.tags.deleteTags', { - tags: tags + tags: tags, }, function (err) { if (err) { return app.alertError(err.message); @@ -162,7 +162,7 @@ define('admin/manage/tags', [ var data = { tag: tag.attr('data-tag'), bgColor: tag.find('[data-name="bgColor"]').val(), - color: tag.find('[data-name="color"]').val() + color: tag.find('[data-name="color"]').val(), }; socket.emit('admin.tags.update', data, function (err) { diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index 192dec7501..604af20bbc 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -1,6 +1,5 @@ -"use strict"; +'use strict'; -/* global config, socket, define, templates, bootbox, app, ajaxify */ define('admin/manage/users', ['translator'], function (translator) { var Users = {}; @@ -91,7 +90,7 @@ define('admin/manage/users', ['translator'], function (translator) { buttons: { close: { label: '[[global:close]]', - className: 'btn-link' + className: 'btn-link', }, submit: { label: '[[admin/manage/users:alerts.button-ban-x, ' + uids.length + ']]', @@ -100,11 +99,11 @@ define('admin/manage/users', ['translator'], function (translator) { data[cur.name] = cur.value; return data; }, {}); - var until = formData.length ? (Date.now() + formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1)) : 0; + var until = formData.length ? (Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))) : 0; socket.emit('user.banUsers', { uids: uids, until: until, reason: formData.reason }, done('[[admin/manage/users:alerts.ban-success]]', '.ban', true)); - } - } - } + }, + }, + }, }); }); }); @@ -266,7 +265,7 @@ define('admin/manage/users', ['translator'], function (translator) { buttons: { cancel: { label: '[[admin/manage/users:alerts.button-cancel]]', - className: 'btn-link' + className: 'btn-link', }, create: { label: '[[admin/manage/users:alerts.button-create]]', @@ -274,9 +273,9 @@ define('admin/manage/users', ['translator'], function (translator) { callback: function () { createUser.call(this); return false; - } - } - } + }, + }, + }, }); }); }); @@ -298,11 +297,11 @@ define('admin/manage/users', ['translator'], function (translator) { var user = { username: username, email: email, - password: password + password: password, }; socket.emit('admin.user.createUser', user, function (err) { - if(err) { + if (err) { return errorEl.translateHtml('[[admin/manage/users:alerts.error-x, ' + err.message + ']]').removeClass('hide'); } @@ -323,12 +322,12 @@ define('admin/manage/users', ['translator'], function (translator) { } var $this = $(this); - var type = $this.attr('data-search-type'); + var type = $this.attr('data-search-type'); timeoutId = setTimeout(function () { $('.fa-spinner').removeClass('hidden'); - socket.emit('admin.user.search', {searchBy: type, query: $this.val()}, function (err, data) { + socket.emit('admin.user.search', { searchBy: type, query: $this.val() }, function (err, data) { if (err) { return app.alertError(err.message); } @@ -361,7 +360,6 @@ define('admin/manage/users', ['translator'], function (translator) { handleUserCreate(); handleInvite(); - }; function handleInvite() { diff --git a/public/src/admin/modules/colorpicker.js b/public/src/admin/modules/colorpicker.js index 47e129249a..c219df634f 100644 --- a/public/src/admin/modules/colorpicker.js +++ b/public/src/admin/modules/colorpicker.js @@ -1,6 +1,5 @@ -"use strict"; +'use strict'; -/*globals define*/ define('admin/modules/colorpicker', function () { var colorpicker = {}; @@ -19,7 +18,7 @@ define('admin/modules/colorpicker', function () { }, onShow: function (colpkr) { $(colpkr).css('z-index', 1051); - } + }, }); }); }; diff --git a/public/src/admin/modules/instance.js b/public/src/admin/modules/instance.js index 0b74ef3405..a8b38062d9 100644 --- a/public/src/admin/modules/instance.js +++ b/public/src/admin/modules/instance.js @@ -1,6 +1,5 @@ -"use strict"; +'use strict'; -/*globals define, app, socket*/ define('admin/modules/instance', function () { var instance = {}; @@ -11,7 +10,7 @@ define('admin/modules/instance', function () { type: 'info', title: 'Reloading... ', message: 'NodeBB is reloading.', - timeout: 5000 + timeout: 5000, }); $(window).one('action:reconnected', function () { @@ -20,7 +19,7 @@ define('admin/modules/instance', function () { type: 'success', title: ' Success', message: 'NodeBB has reloaded successfully.', - timeout: 5000 + timeout: 5000, }); if (typeof callback === 'function') { @@ -37,7 +36,7 @@ define('admin/modules/instance', function () { type: 'info', title: 'Rebuilding... ', message: 'NodeBB is rebuilding front-end assets (css, javascript, etc).', - timeout: 10000 + timeout: 10000, }); $(window).one('action:reconnected', function () { @@ -46,7 +45,7 @@ define('admin/modules/instance', function () { type: 'success', title: ' Success', message: 'NodeBB has successfully restarted.', - timeout: 10000 + timeout: 10000, }); if (typeof callback === 'function') { @@ -60,7 +59,7 @@ define('admin/modules/instance', function () { type: 'info', title: 'Build Complete!... ', message: 'NodeBB is reloading.', - timeout: 10000 + timeout: 10000, }); }); }; diff --git a/public/src/admin/modules/search.js b/public/src/admin/modules/search.js index 29379f0dac..c52008fdab 100644 --- a/public/src/admin/modules/search.js +++ b/public/src/admin/modules/search.js @@ -1,5 +1,5 @@ -"use strict"; -/* globals socket, app, define, ajaxify, config */ +'use strict'; + define('admin/modules/search', ['mousetrap'], function (mousetrap) { var search = {}; @@ -73,7 +73,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { if (!selected.length) { selected = menu.find('li.result > a').first().attr('href'); } - var href = selected ? selected : config.relative_path + '/search/' + input.val(); + var href = selected || config.relative_path + '/search?in=titlesposts&term=' + input.val(); ajaxify.go(href.replace(/^\//, '')); @@ -128,7 +128,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { menu.toggleClass('state-start-typing', len === 0); menu.toggleClass('state-keep-typing', len > 0 && len < 3); - + if (len >= 3) { menu.prepend(find(dict, value)); @@ -140,7 +140,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { menu.find('.search-forum') .not('.divider') .find('a') - .attr('href', config.relative_path + '/search/' + value) + .attr('href', config.relative_path + '/search?in=titlesposts&term=' + value) .find('strong') .html(value); } else { @@ -150,4 +150,4 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { } return search; -}); \ No newline at end of file +}); diff --git a/public/src/admin/modules/selectable.js b/public/src/admin/modules/selectable.js index 6964f74924..bd45e6f850 100644 --- a/public/src/admin/modules/selectable.js +++ b/public/src/admin/modules/selectable.js @@ -1,13 +1,12 @@ -"use strict"; +'use strict'; -/*globals define*/ -define('admin/modules/selectable', ['jqueryui'], function (jqueryui) { +define('admin/modules/selectable', ['jqueryui'], function () { var selectable = {}; selectable.enable = function (containerEl, targets) { $(containerEl).selectable({ - filter: targets + filter: targets, }); }; diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js index ce0a17933f..5495e3b71b 100644 --- a/public/src/admin/settings.js +++ b/public/src/admin/settings.js @@ -1,5 +1,5 @@ 'use strict'; -/*global define, app, socket, ajaxify */ + define('admin/settings', ['uploader'], function (uploader) { var Settings = {}; @@ -11,8 +11,8 @@ define('admin/settings', ['uploader'], function (uploader) { Settings.populateTOC = function () { $('.settings-header').each(function () { - var header = $(this).text(), - anchor = header.toLowerCase().replace(/ /g, '-').trim(); + var header = $(this).text(); + var anchor = header.toLowerCase().replace(/ /g, '-').trim(); $(this).prepend(''); $('.section-content ul').append('
  • ' + header + '
  • '); @@ -21,11 +21,14 @@ define('admin/settings', ['uploader'], function (uploader) { Settings.prepare = function (callback) { // Populate the fields on the page from the config - var fields = $('#content [data-field]'), - numFields = fields.length, - saveBtn = $('#save'), - revertBtn = $('#revert'), - x, key, inputType, field; + var fields = $('#content [data-field]'); + var numFields = fields.length; + var saveBtn = $('#save'); + var revertBtn = $('#revert'); + var x; + var key; + var inputType; + var field; // Handle unsaved changes $(fields).on('change', function () { @@ -33,7 +36,7 @@ define('admin/settings', ['uploader'], function (uploader) { app.flags._unsaved = true; }); - for (x = 0; x < numFields; x++) { + for (x = 0; x < numFields; x += 1) { field = fields.eq(x); key = field.attr('data-field'); inputType = field.attr('type'); @@ -80,7 +83,7 @@ define('admin/settings', ['uploader'], function (uploader) { timeout: 2500, title: 'Changes Not Saved', message: 'NodeBB encountered a problem saving your changes', - type: 'danger' + type: 'danger', }); } @@ -91,7 +94,7 @@ define('admin/settings', ['uploader'], function (uploader) { timeout: 2500, title: 'Changes Saved', message: 'Your changes to the NodeBB configuration have been saved.', - type: 'success' + type: 'success', }); $(window).trigger('action:admin.settingsSaved'); @@ -99,6 +102,7 @@ define('admin/settings', ['uploader'], function (uploader) { }); handleUploads(); + setupTagsInput(); $('#clear-sitemap-cache').off('click').on('click', function () { socket.emit('admin.settings.clearSitemapCache', function () { @@ -126,7 +130,7 @@ define('admin/settings', ['uploader'], function (uploader) { route: uploadBtn.attr('data-route'), params: {}, showHelp: uploadBtn.attr('data-help') ? uploadBtn.attr('data-help') === 1 : undefined, - accept: uploadBtn.attr('data-accept') + accept: uploadBtn.attr('data-accept'), }, function (image) { // need to move these into template, ex data-callback if (ajaxify.currentPage === 'admin/general/sounds') { @@ -139,6 +143,14 @@ define('admin/settings', ['uploader'], function (uploader) { }); } + function setupTagsInput() { + $('[data-field-type="tagsinput"]').tagsinput({ + confirmKeys: [13, 44], + trimValue: true, + }); + app.flags._unsaved = false; + } + Settings.remove = function (key) { socket.emit('admin.config.remove', key); }; @@ -148,8 +160,9 @@ define('admin/settings', ['uploader'], function (uploader) { fields.each(function () { var field = $(this); - var key = field.attr('data-field'), - value, inputType; + var key = field.attr('data-field'); + var value; + var inputType; if (field.is('input')) { inputType = field.attr('type'); @@ -178,7 +191,7 @@ define('admin/settings', ['uploader'], function (uploader) { return callback(err); } - for(var field in data) { + for (var field in data) { if (data.hasOwnProperty(field)) { app.config[field] = data[field]; } diff --git a/public/src/admin/settings/cookies.js b/public/src/admin/settings/cookies.js index 0e85691c12..0a2e8c7243 100644 --- a/public/src/admin/settings/cookies.js +++ b/public/src/admin/settings/cookies.js @@ -1,9 +1,8 @@ 'use strict'; -/* globals define */ define('admin/settings/cookies', [ - 'admin/modules/colorpicker' + 'admin/modules/colorpicker', ], function (colorpicker) { var Module = {}; @@ -22,4 +21,4 @@ define('admin/settings/cookies', [ }; return Module; -}); \ No newline at end of file +}); diff --git a/public/src/admin/settings/email.js b/public/src/admin/settings/email.js index 4cdb4da6d6..4156073367 100644 --- a/public/src/admin/settings/email.js +++ b/public/src/admin/settings/email.js @@ -1,9 +1,9 @@ -"use strict"; -/* global define, socket, app, ajaxify, ace */ +'use strict'; -define('admin/settings/email', ['admin/settings'], function (settings) { - var module = {}, - emailEditor; + +define('admin/settings/email', ['admin/settings'], function () { + var module = {}; + var emailEditor; module.init = function () { configureEmailTester(); @@ -17,7 +17,7 @@ define('admin/settings/email', ['admin/settings'], function (settings) { function configureEmailTester() { $('button[data-action="email.test"]').off('click').on('click', function () { - socket.emit('admin.email.test', {template: $('#test-email').val()}, function (err) { + socket.emit('admin.email.test', { template: $('#test-email').val() }, function (err) { if (err) { return app.alertError(err.message); } @@ -30,10 +30,10 @@ define('admin/settings/email', ['admin/settings'], function (settings) { function configureEmailEditor() { $('#email-editor-selector').on('change', updateEmailEditor); - emailEditor = ace.edit("email-editor"); + emailEditor = ace.edit('email-editor'); emailEditor.$blockScrolling = Infinity; - emailEditor.setTheme("ace/theme/twilight"); - emailEditor.getSession().setMode("ace/mode/html"); + emailEditor.setTheme('ace/theme/twilight'); + emailEditor.getSession().setMode('ace/mode/html'); emailEditor.on('change', function () { var emailPath = $('#email-editor-selector').val(); diff --git a/public/src/admin/settings/general.js b/public/src/admin/settings/general.js index af1028c70e..af66449e02 100644 --- a/public/src/admin/settings/general.js +++ b/public/src/admin/settings/general.js @@ -1,7 +1,7 @@ -"use strict"; -/* global define, socket */ +'use strict'; -define('admin/settings/general', ['admin/settings'], function (Settings) { + +define('admin/settings/general', ['admin/settings'], function () { var Module = {}; Module.init = function () { diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 4e1a576035..93eb4791b0 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -1,7 +1,7 @@ -"use strict"; -/*global app, bootbox, templates, socket, config, RELATIVE_PATH*/ +'use strict'; -var ajaxify = ajaxify || {}; + +var ajaxify = window.ajaxify || {}; $(document).ready(function () { var location = document.location || window.location; @@ -25,11 +25,11 @@ $(document).ready(function () { if (ev !== null && ev.state) { if (ev.state.url === null && ev.state.returnPath !== undefined) { window.history.replaceState({ - url: ev.state.returnPath + url: ev.state.returnPath, }, ev.state.returnPath, config.relative_path + '/' + ev.state.returnPath); } else if (ev.state.url !== undefined) { ajaxify.go(ev.state.url, function () { - $(window).trigger('action:popstate', {url: ev.state.url}); + $(window).trigger('action:popstate', { url: ev.state.url }); }, true); } } @@ -73,7 +73,7 @@ $(document).ready(function () { // If any listeners alter url and set it to an empty string, abort the ajaxification if (url === null) { - $(window).trigger('action:ajaxify.end', {url: url, tpl_url: ajaxify.data.template.name, title: ajaxify.data.title}); + $(window).trigger('action:ajaxify.end', { url: url, tpl_url: ajaxify.data.template.name, title: ajaxify.data.title }); return false; } @@ -81,7 +81,6 @@ $(document).ready(function () { $('#footer, #content').removeClass('hide').addClass('ajaxifying'); ajaxify.loadData(url, function (err, data) { - if (!err || (err && err.data && (parseInt(err.data.status, 10) !== 302 && parseInt(err.data.status, 10) !== 308))) { ajaxify.updateHistory(url, quiet); } @@ -100,10 +99,11 @@ $(document).ready(function () { }; ajaxify.handleRedirects = function (url) { - url = ajaxify.removeRelativePath(url.replace(/\/$/, '')).toLowerCase(); + url = ajaxify.removeRelativePath(url.replace(/^\/|\/$/g, '')).toLowerCase(); var isClientToAdmin = url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0; var isAdminToClient = !url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') === 0; - var uploadsOrApi = url.startsWith('uploads') || url.startsWith('api'); + var uploadsOrApi = url.startsWith('assets/uploads') || url.startsWith('uploads') || url.startsWith('api'); + if (isClientToAdmin || isAdminToClient || uploadsOrApi) { window.open(RELATIVE_PATH + '/' + url, '_top'); return true; @@ -116,7 +116,7 @@ $(document).ready(function () { url = ajaxify.removeRelativePath(url.replace(/^\/|\/$/g, '')); var payload = { - url: url + url: url, }; $(window).trigger('action:ajaxify.start', payload); @@ -128,7 +128,7 @@ $(document).ready(function () { ajaxify.currentPage = url.split(/[?#]/)[0]; if (window.history && window.history.pushState) { window.history[!quiet ? 'pushState' : 'replaceState']({ - url: url + url: url, }, url, RELATIVE_PATH + '/' + url); } }; @@ -158,7 +158,6 @@ $(document).ready(function () { app.alertError('[[global:please_log_in]]'); app.previousUrl = url; window.location.href = config.relative_path + '/login'; - return; } else if (status === 302 || status === 308) { if (data.responseJSON && data.responseJSON.external) { window.location.href = data.responseJSON.external; @@ -195,18 +194,19 @@ $(document).ready(function () { } ajaxify.end = function (url, tpl_url) { - function done() { - if (--count === 0) { - $(window).trigger('action:ajaxify.end', {url: url, tpl_url: tpl_url, title: ajaxify.data.title}); - } - } var count = 2; + function done() { + count -= 1; + if (count === 0) { + $(window).trigger('action:ajaxify.end', { url: url, tpl_url: tpl_url, title: ajaxify.data.title }); + } + } ajaxify.loadScript(tpl_url, done); ajaxify.widgets.render(tpl_url, url, done); - $(window).trigger('action:ajaxify.contentLoaded', {url: url, tpl: tpl_url}); + $(window).trigger('action:ajaxify.contentLoaded', { url: url, tpl: tpl_url }); app.processPage(); @@ -243,7 +243,7 @@ $(document).ready(function () { } var data = { tpl_url: tpl_url, - scripts: [location + tpl_url] + scripts: [location + tpl_url], }; $(window).trigger('action:script.load', data); @@ -285,13 +285,13 @@ $(document).ready(function () { ajaxify.loadData = function (url, callback) { url = ajaxify.removeRelativePath(url); - $(window).trigger('action:ajaxify.loadingData', {url: url}); + $(window).trigger('action:ajaxify.loadingData', { url: url }); apiXHR = $.ajax({ url: RELATIVE_PATH + '/api/' + url, cache: false, headers: { - 'X-Return-To': app.previousUrl + 'X-Return-To': app.previousUrl, }, success: function (data) { if (!data) { @@ -301,7 +301,7 @@ $(document).ready(function () { ajaxify.data = data; data.config = config; - $(window).trigger('action:ajaxify.dataLoaded', {url: url, data: data}); + $(window).trigger('action:ajaxify.dataLoaded', { url: url, data: data }); callback(null, data); }, @@ -311,9 +311,9 @@ $(document).ready(function () { } callback({ data: data, - textStatus: textStatus + textStatus: textStatus, }); - } + }, }); }; @@ -322,14 +322,14 @@ $(document).ready(function () { callback(templates.cache[template]); } else { $.ajax({ - url: config.relative_path + '/assets/templates/' + template + '.tpl' + '?' + config['cache-buster'], + url: config.relative_path + '/assets/templates/' + template + '.tpl?' + config['cache-buster'], type: 'GET', success: function (data) { callback(data.toString()); }, error: function (error) { - throw new Error("Unable to load template: " + template + " (" + error.statusText + ")"); - } + throw new Error('Unable to load template: ' + template + ' (' + error.statusText + ')'); + }, }); } }; @@ -344,6 +344,12 @@ $(document).ready(function () { // Enhancing all anchors to ajaxify... $(document.body).on('click', 'a', function (e) { var _self = this; + if (this.target !== '' || (this.protocol !== 'http:' && this.protocol !== 'https:')) { + return; + } + + var internalLink = utils.isInternalURI(this, window.location, RELATIVE_PATH); + var process = function () { if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) { if (internalLink) { @@ -352,35 +358,31 @@ $(document).ready(function () { // Special handling for urls with hashes if (window.location.pathname === this.pathname && this.hash.length) { window.location.hash = this.hash; - } else { - if (ajaxify.go(pathname)) { - e.preventDefault(); - } + } else if (ajaxify.go(pathname)) { + e.preventDefault(); } } else if (window.location.pathname !== '/outgoing') { if (config.openOutgoingLinksInNewTab && $.contains(contentEl, this)) { window.open(this.href, '_blank'); e.preventDefault(); } else if (config.useOutgoingLinksPage) { - ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); - e.preventDefault(); + var safeUrls = config.outgoingLinksWhitelist.trim().split(/[\s,]+/g); + var href = this.href; + + if (!safeUrls.some(function (url) { return href.indexOf(url) !== -1; })) { + ajaxify.go('outgoing?url=' + encodeURIComponent(href)); + e.preventDefault(); + } } } } }; - if (this.target !== '' || (this.protocol !== 'http:' && this.protocol !== 'https:')) { - return; - } - - var internalLink = utils.isInternalURI(this, window.location, RELATIVE_PATH); - if ($(this).attr('data-ajaxify') === 'false') { if (!internalLink) { return; - } else { - return e.preventDefault(); } + return e.preventDefault(); } // Default behaviour for rss feeds @@ -421,5 +423,4 @@ $(document).ready(function () { templates.cache[$(this).attr('data-template')] = $('
    ').html($(this).html()).text(); $(this).parent().remove(); }); - -}); \ No newline at end of file +}); diff --git a/public/src/app.js b/public/src/app.js index 85bb5065aa..b478bc459c 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -1,7 +1,7 @@ -"use strict"; -/*global templates, ajaxify, utils, bootbox, overrides, socket, config, Visibility*/ +'use strict'; -var app = app || {}; + +var app = window.app || {}; app.isFocused = true; app.currentRoom = null; @@ -17,7 +17,7 @@ app.cacheBuster = null; app.cacheBuster = config['cache-buster']; bootbox.setDefaults({ - locale: config.userLang + locale: config.userLang, }); app.load = function () { @@ -69,7 +69,7 @@ app.cacheBuster = null; clickfn: function () { window.location.reload(); }, - type: 'warning' + type: 'warning', }); } }); @@ -98,16 +98,16 @@ app.cacheBuster = null; $.ajax(config.relative_path + '/logout', { type: 'POST', headers: { - 'x-csrf-token': config.csrf_token + 'x-csrf-token': config.csrf_token, }, success: function () { var payload = { - next: config.relative_path + '/' + next: config.relative_path + '/', }; $(window).trigger('action:app.loggedOut', payload); window.location.href = payload.next; - } + }, }); }; @@ -128,7 +128,7 @@ app.cacheBuster = null; title: '[[global:alert.success]]', message: message, type: 'success', - timeout: timeout ? timeout : 5000 + timeout: timeout || 5000, }); }; @@ -143,7 +143,7 @@ app.cacheBuster = null; title: '[[global:alert.error]]', message: message, type: 'danger', - timeout: timeout ? timeout : 10000 + timeout: timeout || 10000, }); }; @@ -163,7 +163,7 @@ app.cacheBuster = null; closeButton: false, callback: function () { window.location.reload(); - } + }, }); }); }); @@ -175,7 +175,7 @@ app.cacheBuster = null; var previousRoom = app.currentRoom; app.currentRoom = room; socket.emit('meta.rooms.enter', { - enter: room + enter: room, }, function (err) { if (err) { app.currentRoom = previousRoom; @@ -213,7 +213,7 @@ app.cacheBuster = null; if (!utils.isTouchDevice()) { $(this).tooltip({ placement: placement || $(this).attr('title-placement') || 'top', - title: $(this).attr('title') + title: $(this).attr('title'), }); } }); @@ -222,8 +222,8 @@ app.cacheBuster = null; app.createStatusTooltips = function () { if (!utils.isTouchDevice()) { $('body').tooltip({ - selector:'.fa-circle.status', - placement: 'top' + selector: '.fa-circle.status', + placement: 'top', }); } }; @@ -262,36 +262,36 @@ app.cacheBuster = null; login: { format: 'alert', title: '[[global:welcome_back]] ' + app.user.username + '!', - message: '[[global:you_have_successfully_logged_in]]' + message: '[[global:you_have_successfully_logged_in]]', }, banned: { format: 'modal', title: '[[error:user-banned]]', - message: '[[error:user-banned-reason, ' + utils.params().banned + ']]' - } + message: '[[error:user-banned-reason, ' + utils.params().banned + ']]', + }, }; function showAlert(type) { switch (messages[type].format) { - case 'alert': - app.alert({ - type: 'success', - title: messages[type].title, - message: messages[type].message, - timeout: 5000 - }); - break; + case 'alert': + app.alert({ + type: 'success', + title: messages[type].title, + message: messages[type].message, + timeout: 5000, + }); + break; - case 'modal': - require(['translator'], function (translator) { - translator.translate(messages[type].message, function (translated) { - bootbox.alert({ - title: messages[type].title, - message: translated - }); + case 'modal': + require(['translator'], function (translator) { + translator.translate(messages[type].message, function (translated) { + bootbox.alert({ + title: messages[type].title, + message: translated, }); }); - break; + }); + break; } } @@ -325,7 +325,7 @@ app.cacheBuster = null; if (chat.modalExists(roomId)) { loadAndCenter(chat.getModal(roomId)); } else { - socket.emit('modules.chats.loadRoom', {roomId: roomId, uid: uid || app.user.uid}, function (err, roomData) { + socket.emit('modules.chats.loadRoom', { roomId: roomId, uid: uid || app.user.uid }, function (err, roomData) { if (err) { return app.alertError(err.message); } @@ -349,7 +349,7 @@ app.cacheBuster = null; return app.alertError('[[error:cant-chat-with-yourself]]'); } - socket.emit('modules.chats.newRoom', {touid: touid}, function (err, roomId) { + socket.emit('modules.chats.newRoom', { touid: touid }, function (err, roomId) { if (err) { return app.alertError(err.message); } @@ -365,10 +365,10 @@ app.cacheBuster = null; }; var titleObj = { - active: false, - interval: undefined, - titles: [] - }; + active: false, + interval: undefined, + titles: [], + }; app.alternatingTitle = function (title) { if (typeof title !== 'string') { @@ -424,7 +424,7 @@ app.cacheBuster = null; app.toggleNavbar = function (state) { var navbarEl = $('.navbar'); if (navbarEl) { - navbarEl.toggleClass('hidden', !!!state); + navbarEl.toggleClass('hidden', !state); } }; @@ -438,7 +438,7 @@ app.cacheBuster = null; $(this).tooltip({ placement: 'bottom', trigger: 'hover', - title: $(this).attr('title') + title: $(this).attr('title'), }); } }); @@ -447,7 +447,7 @@ app.cacheBuster = null; $('#search-form').parent().tooltip({ placement: 'bottom', trigger: 'hover', - title: $('#search-button i').attr('title') + title: $('#search-button i').attr('title'), }); } @@ -455,15 +455,15 @@ app.cacheBuster = null; $('#user_dropdown').tooltip({ placement: 'bottom', trigger: 'hover', - title: $('#user_dropdown').attr('title') + title: $('#user_dropdown').attr('title'), }); } } app.handleSearch = function () { - var searchButton = $("#search-button"), - searchFields = $("#search-fields"), - searchInput = $('#search-fields input'); + var searchButton = $('#search-button'); + var searchFields = $('#search-fields'); + var searchInput = $('#search-fields input'); $('#search-form .advanced-search-link').on('mousedown', function () { ajaxify.go('/search'); @@ -480,8 +480,8 @@ app.cacheBuster = null; searchButton.on('click', function (e) { if (!config.loggedIn && !config.allowGuestSearching) { app.alert({ - message:'[[error:search-requires-login]]', - timeout: 3000 + message: '[[error:search-requires-login]]', + timeout: 3000, }); ajaxify.go('login'); return false; @@ -506,8 +506,8 @@ app.cacheBuster = null; }; app.prepareSearch = function () { - $("#search-fields").removeClass('hidden'); - $("#search-button").addClass('hidden'); + $('#search-fields').removeClass('hidden'); + $('#search-button').addClass('hidden'); $('#search-fields input').focus(); }; @@ -515,7 +515,7 @@ app.cacheBuster = null; $('[component="header/usercontrol"] [data-status]').off('click').on('click', function (e) { var status = $(this).attr('data-status'); socket.emit('user.setStatus', status, function (err) { - if(err) { + if (err) { return app.alertError(err.message); } $('[data-uid="' + app.user.uid + '"] [component="user/status"], [component="header/profilelink"] [component="user/status"]') @@ -546,7 +546,7 @@ app.cacheBuster = null; app.newTopic = function (cid, tags) { $(window).trigger('action:composer.topic.new', { cid: cid || ajaxify.data.cid || 0, - tags: tags || (ajaxify.data.tag ? [ajaxify.data.tag] : []) + tags: tags || (ajaxify.data.tag ? [ajaxify.data.tag] : []), }); }; @@ -557,7 +557,7 @@ app.cacheBuster = null; var scriptEl = document.createElement('script'); scriptEl.type = 'text/javascript'; - scriptEl.src = config.relative_path + '/assets/vendor/jquery/js/jquery-ui.js' + '?' + config['cache-buster']; + scriptEl.src = config.relative_path + '/assets/vendor/jquery/js/jquery-ui.js?' + config['cache-buster']; scriptEl.onload = callback; document.head.appendChild(scriptEl); }; @@ -569,7 +569,7 @@ app.cacheBuster = null; var msg = { alert_id: 'email_confirm', type: 'warning', - timeout: 0 + timeout: 0, }; if (!app.user.email) { @@ -656,6 +656,5 @@ app.cacheBuster = null; }); }); }); - }; }()); diff --git a/public/src/client/account/best.js b/public/src/client/account/best.js index abc88620bf..562438297a 100644 --- a/public/src/client/account/best.js +++ b/public/src/client/account/best.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/best', ['forum/account/header', 'forum/account/posts'], function (header, posts) { var Best = {}; diff --git a/public/src/client/account/bookmarks.js b/public/src/client/account/bookmarks.js index 3f9b848b75..80357fe89b 100644 --- a/public/src/client/account/bookmarks.js +++ b/public/src/client/account/bookmarks.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/bookmarks', ['forum/account/header', 'forum/account/posts'], function (header, posts) { var Bookmarks = {}; diff --git a/public/src/client/account/downvoted.js b/public/src/client/account/downvoted.js index b84e5da6bf..b4f0cc181f 100644 --- a/public/src/client/account/downvoted.js +++ b/public/src/client/account/downvoted.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/downvoted', ['forum/account/header', 'forum/account/posts'], function (header, posts) { var Downvoted = {}; diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index 86b9dcafe6..02c1e57200 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -1,12 +1,10 @@ 'use strict'; -/* globals define, ajaxify, socket, app, config, templates, bootbox */ define('forum/account/edit', ['forum/account/header', 'translator', 'components', 'pictureCropper'], function (header, translator, components, pictureCropper) { var AccountEdit = {}; AccountEdit.init = function () { - header.init(); $('#submitBtn').on('click', updateProfile); @@ -16,7 +14,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' changeMonth: true, changeYear: true, yearRange: '1900:-5y', - defaultDate: '-13y' + defaultDate: '-13y', }); }); @@ -36,7 +34,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' location: $('#inputLocation').val(), groupTitle: $('#groupTitle').val(), signature: $('#inputSignature').val(), - aboutme: $('#inputAboutMe').val() + aboutme: $('#inputAboutMe').val(), }; $(window).trigger('action:profile.update', userData); @@ -71,10 +69,9 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' } function handleImageChange() { - $('#changePictureBtn').on('click', function () { socket.emit('user.getProfilePictures', { - uid: ajaxify.data.uid + uid: ajaxify.data.uid, }, function (err, pictures) { if (err) { return app.alertError(err.message); @@ -88,7 +85,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' templates.parse('partials/modals/change_picture_modal', { pictures: pictures, uploaded: uploaded, - allowProfileImageUploads: ajaxify.data.allowProfileImageUploads + allowProfileImageUploads: ajaxify.data.allowProfileImageUploads, }, function (html) { translator.translate(html, function (html) { var modal = bootbox.dialog({ @@ -100,13 +97,13 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' close: { label: '[[global:close]]', callback: onCloseModal, - className: 'btn-link' + className: 'btn-link', }, update: { label: '[[global:save_changes]]', - callback: saveSelection - } - } + callback: saveSelection, + }, + }, }); modal.on('shown.bs.modal', updateImages); @@ -171,15 +168,14 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' if ($('#confirm-username').val() !== app.user.username) { app.alertError('[[error:invalid-username]]'); return false; - } else { - socket.emit('user.deleteAccount', {}, function (err) { - if (err) { - return app.alertError(err.message); - } - - window.location.href = config.relative_path + '/'; - }); } + socket.emit('user.deleteAccount', {}, function (err) { + if (err) { + return app.alertError(err.message); + } + + window.location.href = config.relative_path + '/'; + }); }); modal.on('shown.bs.modal', function () { @@ -192,7 +188,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' function handleImageUpload(modal) { function onUploadComplete(urlOnServer) { - urlOnServer = urlOnServer + '?' + Date.now(); + urlOnServer = config.relative_path + urlOnServer + '?' + Date.now(); updateHeader(urlOnServer); @@ -227,7 +223,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' imageDimension: ajaxify.data.profileImageDimension, title: '[[user:upload_picture]]', description: '[[user:upload_a_picture]]', - accept: '.png,.jpg,.bmp' + accept: '.png,.jpg,.bmp', }, function (url) { onUploadComplete(url); }); @@ -245,22 +241,29 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' uploadModal.find('.upload-btn').on('click', function () { var url = uploadModal.find('#uploadFromUrl').val(); if (!url) { - return; + return false; } - - uploadModal.modal('hide'); - - pictureCropper.handleImageCrop({ + socket.emit('user.uploadProfileImageFromUrl', { + uid: ajaxify.data.uid, url: url, - socketMethod: 'user.uploadCroppedPicture', - aspectRatio: '1 / 1', - allowSkippingCrop: false, - restrictImageDimension: true, - imageDimension: ajaxify.data.profileImageDimension, - paramName: 'uid', - paramValue: ajaxify.data.theirid, - }, onUploadComplete); + }, function (err, url) { + if (err) { + return app.alertError(err); + } + uploadModal.modal('hide'); + + pictureCropper.handleImageCrop({ + url: url, + socketMethod: 'user.uploadCroppedPicture', + aspectRatio: '1 / 1', + allowSkippingCrop: false, + restrictImageDimension: true, + imageDimension: ajaxify.data.profileImageDimension, + paramName: 'uid', + paramValue: ajaxify.data.theirid, + }, onUploadComplete); + }); return false; }); }); @@ -271,7 +274,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' modal.find('[data-action="remove-uploaded"]').on('click', function () { socket.emit('user.removeUploadedPicture', { - uid: ajaxify.data.theirid + uid: ajaxify.data.theirid, }, function (err) { modal.modal('hide'); if (err) { @@ -298,7 +301,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' function changeUserPicture(type, callback) { socket.emit('user.changePicture', { type: type, - uid: ajaxify.data.theirid + uid: ajaxify.data.theirid, }, callback); } diff --git a/public/src/client/account/edit/email.js b/public/src/client/account/edit/email.js index df998bead0..e1a068979a 100644 --- a/public/src/client/account/edit/email.js +++ b/public/src/client/account/edit/email.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, ajaxify, socket, app */ define('forum/account/edit/email', ['forum/account/header'], function (header) { var AccountEditEmail = {}; @@ -12,7 +11,7 @@ define('forum/account/edit/email', ['forum/account/header'], function (header) { var userData = { uid: $('#inputUID').val(), email: $('#inputNewEmail').val(), - password: $('#inputCurrentPassword').val() + password: $('#inputCurrentPassword').val(), }; if (!userData.email) { diff --git a/public/src/client/account/edit/password.js b/public/src/client/account/edit/password.js index a123959804..d2239b36a0 100644 --- a/public/src/client/account/edit/password.js +++ b/public/src/client/account/edit/password.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, ajaxify, socket, app, utils */ define('forum/account/edit/password', ['forum/account/header', 'translator'], function (header, translator) { var AccountEditPassword = {}; @@ -64,9 +63,9 @@ define('forum/account/edit/password', ['forum/account/header', 'translator'], fu if ((passwordvalid && passwordsmatch) || app.user.isAdmin) { btn.addClass('disabled').find('i').removeClass('hide'); socket.emit('user.changePassword', { - 'currentPassword': currentPassword.val(), - 'newPassword': password.val(), - 'uid': ajaxify.data.theirid + currentPassword: currentPassword.val(), + newPassword: password.val(), + uid: ajaxify.data.theirid, }, function (err) { btn.removeClass('disabled').find('i').addClass('hide'); currentPassword.val(''); @@ -80,8 +79,8 @@ define('forum/account/edit/password', ['forum/account/header', 'translator'], fu onPasswordConfirmChanged(); return app.alertError(err.message); } - ajaxify.go('user/' + ajaxify.data.userslug); - app.alertSuccess('[[user:change_password_success]]'); + + window.location.href = config.relative_path + '/login'; }); } else { if (!passwordsmatch) { diff --git a/public/src/client/account/edit/username.js b/public/src/client/account/edit/username.js index cb924a3f53..33d8ea99cd 100644 --- a/public/src/client/account/edit/username.js +++ b/public/src/client/account/edit/username.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, ajaxify, socket, app, utils, config */ define('forum/account/edit/username', ['forum/account/header'], function (header) { var AccountEditUsername = {}; @@ -12,7 +11,7 @@ define('forum/account/edit/username', ['forum/account/header'], function (header var userData = { uid: $('#inputUID').val(), username: $('#inputNewUsername').val(), - password: $('#inputCurrentPassword').val() + password: $('#inputCurrentPassword').val(), }; if (!userData.username) { diff --git a/public/src/client/account/followers.js b/public/src/client/account/followers.js index 22970327fb..bae7343262 100644 --- a/public/src/client/account/followers.js +++ b/public/src/client/account/followers.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/followers', ['forum/account/header'], function (header) { var Followers = {}; diff --git a/public/src/client/account/following.js b/public/src/client/account/following.js index dff2f92709..5881ae1bec 100644 --- a/public/src/client/account/following.js +++ b/public/src/client/account/following.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/following', ['forum/account/header'], function (header) { var Following = {}; diff --git a/public/src/client/account/groups.js b/public/src/client/account/groups.js index f8fe55fdd9..ba3fb3ce7c 100644 --- a/public/src/client/account/groups.js +++ b/public/src/client/account/groups.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals ajaxify, define, app, socket, utils */ define('forum/account/groups', ['forum/account/header'], function (header) { var AccountTopics = {}; diff --git a/public/src/client/account/header.js b/public/src/client/account/header.js index 63869af05b..1ff436c7ee 100644 --- a/public/src/client/account/header.js +++ b/public/src/client/account/header.js @@ -1,11 +1,11 @@ 'use strict'; -/* globals define, app, config, ajaxify, socket, bootbox, templates */ + define('forum/account/header', [ 'coverPhoto', 'pictureCropper', 'components', - 'translator' + 'translator', ], function (coverPhoto, pictureCropper, components, translator) { var AccountHeader = {}; var isAdminOrSelfOrGlobalMod; @@ -76,7 +76,7 @@ define('forum/account/header', [ socket.emit('user.updateCover', { uid: ajaxify.data.uid, imageData: imageData, - position: position + position: position, }, callback); }, function () { @@ -88,7 +88,7 @@ define('forum/account/header', [ restrictImageDimension: false, paramName: 'uid', paramValue: ajaxify.data.theirid, - accept: '.png,.jpg,.bmp' + accept: '.png,.jpg,.bmp', }, function (imageUrlOnServer) { components.get('account/cover').css('background-image', 'url(' + imageUrlOnServer + '?' + config['cache-buster'] + ')'); }); @@ -99,7 +99,7 @@ define('forum/account/header', [ function toggleFollow(type) { socket.emit('user.' + type, { - uid: ajaxify.data.uid + uid: ajaxify.data.uid, }, function (err) { if (err) { return app.alertError(err.message); @@ -122,7 +122,7 @@ define('forum/account/header', [ buttons: { close: { label: '[[global:close]]', - className: 'btn-link' + className: 'btn-link', }, submit: { label: '[[user:ban_account]]', @@ -131,21 +131,21 @@ define('forum/account/header', [ data[cur.name] = cur.value; return data; }, {}); - var until = parseInt(formData.length, 10) ? (Date.now() + formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1)) : 0; + var until = parseInt(formData.length, 10) ? (Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))) : 0; socket.emit('user.banUsers', { uids: [ajaxify.data.theirid], until: until, - reason: formData.reason || '' + reason: formData.reason || '', }, function (err) { if (err) { return app.alertError(err.message); } ajaxify.refresh(); }); - } - } - } + }, + }, + }, }); }); } @@ -185,7 +185,7 @@ define('forum/account/header', [ } socket.emit('user.removeCover', { - uid: ajaxify.data.uid + uid: ajaxify.data.uid, }, function (err) { if (!err) { ajaxify.refresh(); diff --git a/public/src/client/account/info.js b/public/src/client/account/info.js index bd7d361d23..f366c0a3e7 100644 --- a/public/src/client/account/info.js +++ b/public/src/client/account/info.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, ajaxify, app */ define('forum/account/info', ['forum/account/header', 'components'], function (header, components) { var Info = {}; @@ -14,7 +13,7 @@ define('forum/account/info', ['forum/account/header', 'components'], function (h function handleModerationNote() { $('[component="account/save-moderation-note"]').on('click', function () { var note = $('[component="account/moderation-note"]').val(); - socket.emit('user.setModerationNote', {uid: ajaxify.data.uid, note: note}, function (err) { + socket.emit('user.setModerationNote', { uid: ajaxify.data.uid, note: note }, function (err) { if (err) { return app.alertError(err.message); } @@ -35,8 +34,8 @@ define('forum/account/info', ['forum/account/header', 'components'], function (h url: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/session/' + uuid, method: 'delete', headers: { - 'x-csrf-token': config.csrf_token - } + 'x-csrf-token': config.csrf_token, + }, }).done(function () { parentEl.remove(); }).fail(function (err) { diff --git a/public/src/client/account/posts.js b/public/src/client/account/posts.js index 9e2082e211..e247905852 100644 --- a/public/src/client/account/posts.js +++ b/public/src/client/account/posts.js @@ -1,10 +1,10 @@ 'use strict'; -/* globals define, app, socket, utils, config, ajaxify */ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], function (header, infinitescroll) { var AccountPosts = {}; - var method, template; + var method; + var template; AccountPosts.init = function () { header.init(); @@ -29,7 +29,7 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.loadMore(method, { uid: ajaxify.data.theirid, - after: $('[component="posts"]').attr('data-nextstart') + after: $('[component="posts"]').attr('data-nextstart'), }, function (data, done) { if (data.posts && data.posts.length) { onPostsLoaded(data.posts, done); @@ -41,7 +41,7 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], } function onPostsLoaded(posts, callback) { - app.parseAndTranslate(template, 'posts', {posts: posts}, function (html) { + app.parseAndTranslate(template, 'posts', { posts: posts }, function (html) { $('[component="posts"]').append(html); html.find('img:not(.not-responsive)').addClass('img-responsive'); html.find('.timeago').timeago(); diff --git a/public/src/client/account/profile.js b/public/src/client/account/profile.js index b1eaa218cf..2f8a834d36 100644 --- a/public/src/client/account/profile.js +++ b/public/src/client/account/profile.js @@ -1,13 +1,11 @@ 'use strict'; -/* globals define, ajaxify, app, socket, bootbox */ define('forum/account/profile', [ 'forum/account/header', 'forum/infinitescroll', - 'translator', - 'components' -], function (header, infinitescroll, translator) { + 'components', +], function (header, infinitescroll) { var Account = {}; var theirid; @@ -22,10 +20,10 @@ define('forum/account/profile', [ socket.removeListener('event:user_status_change', onUserStatusChange); socket.on('event:user_status_change', onUserStatusChange); - + if (!config.usePagination) { - infinitescroll.init(loadMorePosts); - } + infinitescroll.init(loadMorePosts); + } }; function processPage() { @@ -49,7 +47,7 @@ define('forum/account/profile', [ infinitescroll.loadMore('posts.loadMoreUserPosts', { after: $('[component="posts"]').attr('data-nextstart'), - uid: theirid + uid: theirid, }, function (data, done) { if (data.posts && data.posts.length) { onPostsLoaded(data.posts, done); @@ -70,8 +68,7 @@ define('forum/account/profile', [ return callback(); } - app.parseAndTranslate('account/profile', 'posts', {posts: posts}, function (html) { - + app.parseAndTranslate('account/profile', 'posts', { posts: posts }, function (html) { $('[component="posts"]').append(html); html.find('.timeago').timeago(); diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js index e04d5117ff..bffefc725f 100644 --- a/public/src/client/account/settings.js +++ b/public/src/client/account/settings.js @@ -1,10 +1,15 @@ 'use strict'; -/*global define, socket, app, ajaxify, config*/ define('forum/account/settings', ['forum/account/header', 'components', 'sounds'], function (header, components, sounds) { var AccountSettings = {}; + $(window).on('action:ajaxify.start', function () { + if (ajaxify.data.template.name === 'account/settings' && $('#bootswatchSkin').val() !== config.bootswatchSkin) { + changePageSkin(config.bootswatchSkin); + } + }); + AccountSettings.init = function () { header.init(); @@ -25,10 +30,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' }); $('#bootswatchSkin').on('change', function () { - var css = $('#bootswatchCSS'); - var val = $(this).val() === 'default' ? config['theme:src'] : '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + $(this).val() + '/bootstrap.min.css'; - - css.attr('href', val); + changePageSkin($(this).val()); }); $('[data-property="homePageRoute"]').on('change', toggleCustomRoute); @@ -45,6 +47,29 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' components.get('user/sessions').find('.timeago').timeago(); }; + function changePageSkin(skinName) { + var css = $('#bootswatchCSS'); + if (skinName === 'noskin' || (skinName === 'default' && config.defaultBootswatchSkin === 'noskin')) { + css.remove(); + } else { + if (skinName === 'default') { + skinName = config.defaultBootswatchSkin; + } + var cssSource = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + skinName + '/bootstrap.min.css'; + if (css.length) { + css.attr('href', cssSource); + } else { + css = $(''); + $('head').append(css); + } + } + + var currentSkinClassName = $('body').attr('class').split(/\s+/).filter(function (className) { + return className.startsWith('skin-'); + }); + $('body').removeClass(currentSkinClassName.join(' ')).addClass('skin-' + skinName); + } + function loadSettings() { var settings = {}; @@ -57,13 +82,13 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' } switch (input.attr('type')) { - case 'text': - case 'textarea': - settings[setting] = input.val(); - break; - case 'checkbox': - settings[setting] = input.is(':checked') ? 1 : 0; - break; + case 'text': + case 'textarea': + settings[setting] = input.val(); + break; + case 'checkbox': + settings[setting] = input.is(':checked') ? 1 : 0; + break; } }); @@ -71,7 +96,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' } function saveSettings(settings) { - socket.emit('user.saveSettings', {uid: ajaxify.data.theirid, settings: settings}, function (err, newSettings) { + socket.emit('user.saveSettings', { uid: ajaxify.data.theirid, settings: settings }, function (err, newSettings) { if (err) { return app.alertError(err.message); } @@ -99,7 +124,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds' timeout: 5000, clickfn: function () { ajaxify.refresh(); - } + }, }); } }); diff --git a/public/src/client/account/topics.js b/public/src/client/account/topics.js index 63658f0cbf..340c2e11b9 100644 --- a/public/src/client/account/topics.js +++ b/public/src/client/account/topics.js @@ -1,10 +1,9 @@ 'use strict'; -/* globals define, app, socket, utils, config, ajaxify */ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], function (header, infinitescroll) { var AccountTopics = {}; - var template, set; + var set; AccountTopics.init = function () { header.init(); @@ -13,7 +12,6 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], }; AccountTopics.handleInfiniteScroll = function (_template, _set) { - template = _template; set = _set; if (!config.usePagination) { @@ -28,7 +26,7 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.loadMore('topics.loadMoreFromSet', { set: set, - after: $('[component="category"]').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart'), }, function (data, done) { if (data.topics && data.topics.length) { onTopicsLoaded(data.topics, done); @@ -41,12 +39,12 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], } function onTopicsLoaded(topics, callback) { - app.parseAndTranslate('account/topics', 'topics', {topics: topics}, function (html) { + app.parseAndTranslate('account/topics', 'topics', { topics: topics }, function (html) { $('[component="category"]').append(html); html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); - $(window).trigger('action:topics.loaded', {topics: topics}); + $(window).trigger('action:topics.loaded', { topics: topics }); callback(); }); } diff --git a/public/src/client/account/upvoted.js b/public/src/client/account/upvoted.js index 76bf001b77..74c1f6c753 100644 --- a/public/src/client/account/upvoted.js +++ b/public/src/client/account/upvoted.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/account/upvoted', ['forum/account/header', 'forum/account/posts'], function (header, posts) { var Upvoted = {}; diff --git a/public/src/client/account/watched.js b/public/src/client/account/watched.js index 4e1ca01cfe..6ba9ccc19d 100644 --- a/public/src/client/account/watched.js +++ b/public/src/client/account/watched.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, socket, utils */ + define('forum/account/watched', ['forum/account/header', 'forum/account/topics'], function (header, topics) { var AccountWatched = {}; diff --git a/public/src/client/categories.js b/public/src/client/categories.js index bd27aed0a2..ff1dfa3401 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, app, templates, ajaxify*/ define('forum/categories', ['components', 'translator'], function (components, translator) { var categories = {}; @@ -18,7 +17,7 @@ define('forum/categories', ['components', 'translator'], function (components, t socket.on('event:new_post', categories.onNewPost); $('.category-header').tooltip({ - placement: 'bottom' + placement: 'bottom', }); }; @@ -36,11 +35,10 @@ define('forum/categories', ['components', 'translator'], function (components, t } var recentPosts = category.find('[component="category/posts"]'); - var insertBefore = recentPosts.first(); parseAndTranslate([post], function (html) { html.hide(); - if(recentPosts.length === 0) { + if (recentPosts.length === 0) { html.appendTo(category); } else { html.insertBefore(recentPosts.first()); @@ -55,12 +53,12 @@ define('forum/categories', ['components', 'translator'], function (components, t recentPosts.last().remove(); } - $(window).trigger('action:posts.loaded', {posts: [post]}); + $(window).trigger('action:posts.loaded', { posts: [post] }); }); } function parseAndTranslate(posts, callback) { - templates.parse('categories', '(categories.)?posts', {categories: {posts: posts}}, function (html) { + templates.parse('categories', '(categories.)?posts', { categories: { posts: posts } }, function (html) { translator.translate(html, function (translatedHTML) { translatedHTML = $(translatedHTML); translatedHTML.find('.post-content img:not(.not-responsive)').addClass('img-responsive'); diff --git a/public/src/client/category.js b/public/src/client/category.js index d0af1d21b2..e2dfcd9924 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -1,5 +1,5 @@ -"use strict"; -/* global define, config, templates, app, utils, ajaxify, socket */ +'use strict'; + define('forum/category', [ 'forum/infinitescroll', @@ -10,7 +10,7 @@ define('forum/category', [ 'components', 'translator', 'topicSelect', - 'forum/pagination' + 'forum/pagination', ], function (infinitescroll, share, navigator, categoryTools, sort, components, translator, topicSelect, pagination) { var Category = {}; @@ -62,8 +62,8 @@ define('forum/category', [ handleIgnoreWatch(cid); - $(window).trigger('action:topics.loaded', {topics: ajaxify.data.topics}); - $(window).trigger('action:category.loaded', {cid: ajaxify.data.cid}); + $(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); + $(window).trigger('action:category.loaded', { cid: ajaxify.data.cid }); }; function handleScrollToTopicIndex() { @@ -112,13 +112,12 @@ define('forum/category', [ }); }; - Category.navigatorCallback = function (topIndex, bottomIndex, elementCount) { + Category.navigatorCallback = function (topIndex, bottomIndex) { return bottomIndex; }; - $(window).on('action:ajaxify.contentLoaded', function (ev, data) { + $(window).on('action:ajaxify.contentLoaded', function () { if (ajaxify.data.template.category && ajaxify.data.cid) { - var bookmarkIndex = localStorage.getItem('category:' + ajaxify.data.cid + ':bookmark'); var clickedIndex = localStorage.getItem('category:' + ajaxify.data.cid + ':bookmark:clicked'); @@ -178,7 +177,7 @@ define('forum/category', [ if (scrollTo.length) { $('html, body').animate({ - scrollTop: (scrollTo.offset().top - offset) + 'px' + scrollTop: (scrollTo.offset().top - offset) + 'px', }, duration !== undefined ? duration : 400, function () { Category.highlightTopic(clickedIndex); navigator.update(); @@ -205,16 +204,16 @@ define('forum/category', [ var editable = !!$('.thread-tools').length; templates.parse('category', 'topics', { - privileges: {editable: editable}, + privileges: { editable: editable }, showSelect: editable, topics: [topic], - template: {category: true} + template: { category: true }, }, function (html) { translator.translate(html, function (translatedHTML) { - var topic = $(translatedHTML), - container = $('[component="category"]'), - topics = $('[component="category/topic"]'), - numTopics = topics.length; + var topic = $(translatedHTML); + var container = $('[component="category"]'); + var topics = $('[component="category/topic"]'); + var numTopics = topics.length; $('[component="category"]').removeClass('hidden'); $('.category-sidebar').removeClass('hidden'); @@ -226,16 +225,15 @@ define('forum/category', [ } if (numTopics > 0) { - for (var x = 0; x < numTopics; x++) { + for (var x = 0; x < numTopics; x += 1) { var pinned = $(topics[x]).hasClass('pinned'); - if (pinned) { - if(x === numTopics - 1) { - topic.insertAfter(topics[x]); - } - continue; + if (!pinned) { + topic.insertBefore(topics[x]); + break; + } + if (x === numTopics - 1) { + topic.insertAfter(topics[x]); } - topic.insertBefore(topics[x]); - break; } } else { container.append(topic); @@ -254,7 +252,7 @@ define('forum/category', [ function updateTopicCount() { socket.emit('categories.getTopicCount', ajaxify.data.cid, function (err, topicCount) { - if(err) { + if (err) { return app.alertError(err.message); } navigator.setCount(topicCount); @@ -287,7 +285,7 @@ define('forum/category', [ direction: direction, author: params.author, tag: params.tag, - categoryTopicSort: config.categoryTopicSort + categoryTopicSort: config.categoryTopicSort, }, function (data, done) { if (data.topics && data.topics.length) { Category.onTopicsLoaded(data, direction, done); @@ -319,7 +317,8 @@ define('forum/category', [ data.showSelect = data.privileges.editable; - var after, before; + var after; + var before; var topics = $('[component="category/topic"]'); if (direction > 0 && topics.length) { @@ -337,8 +336,8 @@ define('forum/category', [ if (after) { html.insertAfter(after); } else if (before) { - var height = $(document).height(), - scrollTop = $(window).scrollTop(); + var height = $(document).height(); + var scrollTop = $(window).scrollTop(); html.insertBefore(before); @@ -355,7 +354,7 @@ define('forum/category', [ app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); - $(window).trigger('action:topics.loaded', {topics: data.topics}); + $(window).trigger('action:topics.loaded', { topics: data.topics }); callback(); }); diff --git a/public/src/client/category/tools.js b/public/src/client/category/tools.js index 947ab50d28..0f0dc7b77d 100644 --- a/public/src/client/category/tools.js +++ b/public/src/client/category/tools.js @@ -1,16 +1,13 @@ 'use strict'; -/* globals define, app, socket, bootbox, ajaxify */ - define('forum/category/tools', [ - 'forum/topic/move', - 'topicSelect', - 'components', - 'translator' + 'forum/topic/move', + 'topicSelect', + 'components', + 'translator', ], function (move, topicSelect, components, translator) { - var CategoryTools = {}; CategoryTools.init = function (cid) { @@ -38,7 +35,7 @@ define('forum/category/tools', [ components.get('topic/lock').on('click', function () { var tids = topicSelect.getSelectedTids(); if (tids.length) { - socket.emit('topics.lock', {tids: tids, cid: CategoryTools.cid}, onCommandComplete); + socket.emit('topics.lock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); } return false; }); @@ -46,7 +43,7 @@ define('forum/category/tools', [ components.get('topic/unlock').on('click', function () { var tids = topicSelect.getSelectedTids(); if (tids.length) { - socket.emit('topics.unlock', {tids: tids, cid: CategoryTools.cid}, onCommandComplete); + socket.emit('topics.unlock', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); } return false; }); @@ -54,7 +51,7 @@ define('forum/category/tools', [ components.get('topic/pin').on('click', function () { var tids = topicSelect.getSelectedTids(); if (tids.length) { - socket.emit('topics.pin', {tids: tids, cid: CategoryTools.cid}, onCommandComplete); + socket.emit('topics.pin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); } return false; }); @@ -62,7 +59,7 @@ define('forum/category/tools', [ components.get('topic/unpin').on('click', function () { var tids = topicSelect.getSelectedTids(); if (tids.length) { - socket.emit('topics.unpin', {tids: tids, cid: CategoryTools.cid}, onCommandComplete); + socket.emit('topics.unpin', { tids: tids, cid: CategoryTools.cid }, onCommandComplete); } return false; }); @@ -126,7 +123,7 @@ define('forum/category/tools', [ return; } - socket.emit('topics.' + command, {tids: tids, cid: CategoryTools.cid}, onDeletePurgeComplete); + socket.emit('topics.' + command, { tids: tids, cid: CategoryTools.cid }, onDeletePurgeComplete); }); }); } @@ -163,7 +160,6 @@ define('forum/category/tools', [ } function updateDropdownOptions() { - var tids = topicSelect.getSelectedTids(); var isAnyDeleted = isAny(isTopicDeleted, tids); var areAllDeleted = areAll(isTopicDeleted, tids); @@ -182,8 +178,8 @@ define('forum/category/tools', [ } function isAny(method, tids) { - for(var i = 0; i < tids.length; ++i) { - if(method(tids[i])) { + for (var i = 0; i < tids.length; i += 1) { + if (method(tids[i])) { return true; } } @@ -191,8 +187,8 @@ define('forum/category/tools', [ } function areAll(method, tids) { - for(var i = 0; i < tids.length; ++i) { - if(!method(tids[i])) { + for (var i = 0; i < tids.length; i += 1) { + if (!method(tids[i])) { return false; } } @@ -254,7 +250,7 @@ define('forum/category/tools', [ var pinnedTopics = $('[component="category/topic"].pinned'); pinnedTopics.each(function (index, element) { - data.push({tid: $(element).attr('data-tid'), order: pinnedTopics.length - index - 1}); + data.push({ tid: $(element).attr('data-tid'), order: pinnedTopics.length - index - 1 }); }); socket.emit('topics.orderPinnedTopics', data, function (err) { @@ -262,7 +258,7 @@ define('forum/category/tools', [ return app.alertError(err.message); } }); - } + }, }); }); } diff --git a/public/src/client/chats.js b/public/src/client/chats.js index e401ab0f29..c42a8e9330 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, ajaxify, utils, socket, templates */ define('forum/chats', [ 'components', @@ -8,10 +7,10 @@ define('forum/chats', [ 'mousetrap', 'forum/chats/recent', 'forum/chats/search', - 'forum/chats/messages' + 'forum/chats/messages', ], function (components, translator, mousetrap, recentChats, search, messages) { var Chats = { - initialised: false + initialised: false, }; var newMessage = false; @@ -61,7 +60,6 @@ define('forum/chats', [ Chats.addSendHandlers(ajaxify.data.roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); $('[data-action="pop-out"]').on('click', function () { - var text = components.get('chat/input').val(); var roomId = ajaxify.data.roomId; @@ -99,8 +97,8 @@ define('forum/chats', [ return; } loading = true; - var start = parseInt($('.chat-content').children('[data-index]').first().attr('data-index'), 10) + 1; - socket.emit('modules.chats.getMessages', {roomId: roomId, uid: uid, start: start}, function (err, data) { + var start = parseInt($('.chat-content').children('[data-index]').first().attr('data-index'), 10) + 1; + socket.emit('modules.chats.getMessages', { roomId: roomId, uid: uid, start: start }, function (err, data) { if (err) { return app.alertError(err.message); } @@ -134,16 +132,16 @@ define('forum/chats', [ Chats.addHotkeys = function () { mousetrap.bind('ctrl+up', function () { - var activeContact = $('.chats-list .bg-primary'), - prev = activeContact.prev(); + var activeContact = $('.chats-list .bg-primary'); + var prev = activeContact.prev(); if (prev.length) { Chats.switchChat(prev.attr('data-roomid')); } }); mousetrap.bind('ctrl+down', function () { - var activeContact = $('.chats-list .bg-primary'), - next = activeContact.next(); + var activeContact = $('.chats-list .bg-primary'); + var next = activeContact.next(); if (next.length) { Chats.switchChat(next.attr('data-roomid')); @@ -172,7 +170,7 @@ define('forum/chats', [ if (oldName === newName) { return; } - socket.emit('modules.chats.renameRoom', {roomId: roomId, newName: newName}, function (err) { + socket.emit('modules.chats.renameRoom', { roomId: roomId, newName: newName }, function (err) { if (err) { return app.alertError(err.message); } @@ -207,8 +205,8 @@ define('forum/chats', [ this.$el.css(this._applyPlacement(position)); this.$el.css('position', 'absolute'); return this; - } - } + }, + }, }; $(window).trigger('chat:autocomplete:init', data); @@ -220,7 +218,7 @@ define('forum/chats', [ Chats.createTagsInput = function (tagEl, data) { tagEl.tagsinput({ confirmKeys: [13, 44], - trimValue: true + trimValue: true, }); if (data.users && data.users.length) { @@ -237,10 +235,10 @@ define('forum/chats', [ if (event.item === app.user.username) { return; } - socket.emit('modules.chats.addUserToRoom', {roomId: data.roomId, username: event.item}, function (err) { + socket.emit('modules.chats.addUserToRoom', { roomId: data.roomId, username: event.item }, function (err) { if (err) { app.alertError(err.message); - tagEl.tagsinput('remove', event.item, {nouser: true}); + tagEl.tagsinput('remove', event.item, { nouser: true }); } }); }); @@ -264,7 +262,7 @@ define('forum/chats', [ if (event.options && event.options.nouser) { return; } - socket.emit('modules.chats.removeUserFromRoom', {roomId: data.roomId, username: event.item}, function (err) { + socket.emit('modules.chats.removeUserFromRoom', { roomId: data.roomId, username: event.item }, function (err) { if (err) { return app.alertError(err.message); } @@ -313,22 +311,20 @@ define('forum/chats', [ data.message.self = data.self; messages.appendChatMessage($('.expanded-chat .chat-content'), data.message); - } else { - if (ajaxify.currentPage.startsWith("chats")) { - var roomEl = $('[data-roomid=' + data.roomId + ']'); + } else if (ajaxify.currentPage.startsWith('chats')) { + var roomEl = $('[data-roomid=' + data.roomId + ']'); - if (roomEl.length > 0) { - roomEl.addClass("unread"); - } else { - var recentEl = components.get('chat/recent'); - templates.parse('partials/chats/recent_room', { - rooms: { "roomId": data.roomId, "lastUser": data.message.fromUser, "usernames": data.message.fromUser.username, "unread": true } - }, function (html) { - translator.translate(html, function (translated) { - recentEl.prepend(translated); - }); + if (roomEl.length > 0) { + roomEl.addClass('unread'); + } else { + var recentEl = components.get('chat/recent'); + templates.parse('partials/chats/recent_room', { + rooms: { roomId: data.roomId, lastUser: data.message.fromUser, usernames: data.message.fromUser.username, unread: true }, + }, function (html) { + translator.translate(html, function (translated) { + recentEl.prepend(translated); }); - } + }); } } }); @@ -356,7 +352,7 @@ define('forum/chats', [ messagesList.height($(window).height() - (fromTop + inputHeight + (margin * 4))); components.get('chat/recent').height($('.expanded-chat').height() - (searchHeight + searchListHeight)); - $('[component="chat/search/list"]').css('max-height', components.get('chat/recent').height() / 2 + 'px'); + $('[component="chat/search/list"]').css('max-height', (components.get('chat/recent').height() / 2) + 'px'); } Chats.setActive(); diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 3cb8328847..c8300c485c 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, socket, app, ajaxify, templates, bootbox */ define('forum/chats/messages', ['components', 'sounds', 'translator'], function (components, sounds, translator) { - var messages = {}; messages.sendMessage = function (roomId, inputEl) { @@ -24,13 +22,13 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function $(window).trigger('action:chat.sent', { roomId: roomId, message: msg, - mid: mid + mid: mid, }); - + if (!mid) { socket.emit('modules.chats.send', { roomId: roomId, - message: msg + message: msg, }, function (err) { if (err) { inputEl.val(msg); @@ -46,7 +44,7 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function socket.emit('modules.chats.edit', { roomId: roomId, mid: mid, - message: msg + message: msg, }, function (err) { if (err) { inputEl.val(msg); @@ -58,7 +56,6 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function }; messages.appendChatMessage = function (chatContentEl, data) { - var lastSpeaker = parseInt(chatContentEl.find('.chat-message').last().attr('data-uid'), 10); if (!Array.isArray(data)) { data.newSet = lastSpeaker !== data.fromuid; @@ -81,7 +78,7 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function messages.parseMessage = function (data, callback) { templates.parse('partials/chats/message' + (Array.isArray(data) ? 's' : ''), { - messages: data + messages: data, }, function (html) { translator.translate(html, callback); }); @@ -114,10 +111,10 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function messages.onChatMessageEdit = function () { socket.on('event:chats.edit', function (data) { data.messages.forEach(function (message) { - var self = parseInt(message.fromuid, 10) === parseInt(app.user.uid); + var self = parseInt(message.fromuid, 10) === parseInt(app.user.uid, 10); message.self = self ? 1 : 0; messages.parseMessage(message, function (html) { - var body = components.get('chat/message', message.messageId); + var body = components.get('chat/message', message.messageId); if (body.length) { body.replaceWith(html); components.get('chat/message', message.messageId).find('.timeago').timeago(); @@ -136,7 +133,7 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function socket.emit('modules.chats.delete', { messageId: messageId, - roomId: roomId + roomId: roomId, }, function (err) { if (err) { return app.alertError(err.message); diff --git a/public/src/client/chats/recent.js b/public/src/client/chats/recent.js index b4b9ba115b..f52f95fbbf 100644 --- a/public/src/client/chats/recent.js +++ b/public/src/client/chats/recent.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, socket, app */ define('forum/chats/recent', function () { - var recent = {}; recent.init = function () { @@ -24,7 +22,7 @@ define('forum/chats/recent', function () { recentChats.attr('loading', 1); socket.emit('modules.chats.getRecentChats', { uid: ajaxify.data.uid, - after: recentChats.attr('data-nextstart') + after: recentChats.attr('data-nextstart'), }, function (err, data) { if (err) { return app.alertError(err.message); @@ -55,4 +53,4 @@ define('forum/chats/recent', function () { return recent; -}); \ No newline at end of file +}); diff --git a/public/src/client/chats/search.js b/public/src/client/chats/search.js index 7ed50deb09..f9504e78a4 100644 --- a/public/src/client/chats/search.js +++ b/public/src/client/chats/search.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, socket, app */ define('forum/chats/search', ['components'], function (components) { - var search = {}; search.init = function () { @@ -29,7 +27,7 @@ define('forum/chats/search', ['components'], function (components) { socket.emit('user.search', { query: username, - searchBy: 'username' + searchBy: 'username', }, function (err, data) { if (err) { return app.alertError(err.message); @@ -41,11 +39,11 @@ define('forum/chats/search', ['components'], function (components) { function displayResults(chatsListEl, data) { chatsListEl.empty(); - + data.users = data.users.filter(function (user) { return parseInt(user.uid, 10) !== parseInt(app.user.uid, 10); }); - + if (!data.users.length) { return chatsListEl.translateHtml('
  • [[users:no-users-found]]
  • '); } diff --git a/public/src/client/compose.js b/public/src/client/compose.js index f1ff7c7acf..e5df728610 100644 --- a/public/src/client/compose.js +++ b/public/src/client/compose.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define */ define('forum/compose', [], function () { var Compose = {}; @@ -10,7 +9,7 @@ define('forum/compose', [], function () { if (container.length) { $(window).trigger('action:composer.enhance', { - container: container + container: container, }); } }; diff --git a/public/src/client/footer.js b/public/src/client/footer.js index d10f47e317..eb921f36c6 100644 --- a/public/src/client/footer.js +++ b/public/src/client/footer.js @@ -1,8 +1,7 @@ -"use strict"; -/*globals define, app, socket*/ +'use strict'; + define('forum/footer', ['notifications', 'chat', 'components', 'translator'], function (Notifications, Chat, components, translator) { - Notifications.prepareDOM(); Chat.prepareDOM(); translator.prepareDOM(); diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 6d0559add3..e7225bb16c 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -1,5 +1,5 @@ -"use strict"; -/* globals define, socket, ajaxify, app, bootbox, utils, config */ +'use strict'; + define('forum/groups/details', [ 'forum/groups/memberlist', @@ -8,9 +8,8 @@ define('forum/groups/details', [ 'coverPhoto', 'pictureCropper', 'translator', - 'vendor/colorpicker/colorpicker' + 'vendor/colorpicker/colorpicker', ], function (memberList, iconSelect, components, coverPhoto, pictureCropper, translator) { - var Details = {}; var groupName; @@ -27,7 +26,7 @@ define('forum/groups/details', [ socket.emit('groups.cover.update', { groupName: groupName, imageData: imageData, - position: position + position: position, }, callback); }, function () { @@ -38,7 +37,7 @@ define('forum/groups/details', [ allowSkippingCrop: true, restrictImageDimension: false, paramName: 'groupName', - paramValue: groupName + paramValue: groupName, }, function (imageUrlOnServer) { components.get('groups/cover').css('background-image', 'url(' + imageUrlOnServer + ')'); }); @@ -54,18 +53,18 @@ define('forum/groups/details', [ components.get('groups/activity').find('.content img:not(.not-responsive)').addClass('img-responsive'); detailsPage.on('click', '[data-action]', function () { - var btnEl = $(this), - userRow = btnEl.parents('[data-uid]'), - ownerFlagEl = userRow.find('.member-name > i'), - isOwner = !ownerFlagEl.hasClass('invisible') ? true : false, - uid = userRow.attr('data-uid'), - action = btnEl.attr('data-action'); + var btnEl = $(this); + var userRow = btnEl.parents('[data-uid]'); + var ownerFlagEl = userRow.find('.member-name > i'); + var isOwner = !ownerFlagEl.hasClass('invisible'); + var uid = userRow.attr('data-uid'); + var action = btnEl.attr('data-action'); switch (action) { case 'toggleOwnership': socket.emit('groups.' + (isOwner ? 'rescind' : 'grant'), { toUid: uid, - groupName: groupName + groupName: groupName, }, function (err) { if (!err) { ownerFlagEl.toggleClass('invisible'); @@ -76,15 +75,23 @@ define('forum/groups/details', [ break; case 'kick': - socket.emit('groups.kick', { - uid: uid, - groupName: groupName - }, function (err) { - if (!err) { - userRow.slideUp().remove(); - } else { - app.alertError(err.message); - } + translator.translate('[[groups:details.kick_confirm]]', function (translated) { + bootbox.confirm(translated, function (confirm) { + if (!confirm) { + return; + } + + socket.emit('groups.kick', { + uid: uid, + groupName: groupName, + }, function (err) { + if (!err) { + userRow.slideUp().remove(); + } else { + app.alertError(err.message); + } + }); + }); }); break; @@ -96,7 +103,7 @@ define('forum/groups/details', [ Details.deleteGroup(); break; - case 'join': // intentional fall-throughs! + case 'join': // intentional fall-throughs! case 'leave': case 'accept': case 'reject': @@ -108,7 +115,7 @@ define('forum/groups/details', [ case 'rejectAll': socket.emit('groups.' + action, { toUid: uid, - groupName: groupName + groupName: groupName, }, function (err) { if (!err) { ajaxify.refresh(); @@ -122,15 +129,15 @@ define('forum/groups/details', [ }; Details.prepareSettings = function () { - var settingsFormEl = components.get('groups/settings'), - colorBtn = settingsFormEl.find('[data-action="color-select"]'), - colorValueEl = settingsFormEl.find('[name="labelColor"]'), - iconBtn = settingsFormEl.find('[data-action="icon-select"]'), - previewEl = settingsFormEl.find('.label'), - previewIcon = previewEl.find('i'), - userTitleEl = settingsFormEl.find('[name="userTitle"]'), - userTitleEnabledEl = settingsFormEl.find('[name="userTitleEnabled"]'), - iconValueEl = settingsFormEl.find('[name="icon"]'); + var settingsFormEl = components.get('groups/settings'); + var colorBtn = settingsFormEl.find('[data-action="color-select"]'); + var colorValueEl = settingsFormEl.find('[name="labelColor"]'); + var iconBtn = settingsFormEl.find('[data-action="icon-select"]'); + var previewEl = settingsFormEl.find('.label'); + var previewIcon = previewEl.find('i'); + var userTitleEl = settingsFormEl.find('[name="userTitle"]'); + var userTitleEnabledEl = settingsFormEl.find('[name="userTitleEnabled"]'); + var iconValueEl = settingsFormEl.find('[name="icon"]'); // Add color picker to settings form colorBtn.ColorPicker({ @@ -141,7 +148,7 @@ define('forum/groups/details', [ }, onShow: function (colpkr) { $(colpkr).css('z-index', 1051); - } + }, }); // Add icon selection interface @@ -173,8 +180,8 @@ define('forum/groups/details', [ }; Details.update = function () { - var settingsFormEl = components.get('groups/settings'), - checkboxes = settingsFormEl.find('input[type="checkbox"][name]'); + var settingsFormEl = components.get('groups/settings'); + var checkboxes = settingsFormEl.find('input[type="checkbox"][name]'); if (settingsFormEl.length) { require(['vendor/jquery/serializeObject/jquery.ba-serializeobject.min'], function () { @@ -190,7 +197,7 @@ define('forum/groups/details', [ socket.emit('groups.update', { groupName: groupName, - values: settings + values: settings, }, function (err) { if (err) { return app.alertError(err.message); @@ -216,7 +223,7 @@ define('forum/groups/details', [ bootbox.prompt('Please enter the name of this group in order to delete it:', function (response) { if (response === groupName) { socket.emit('groups.delete', { - groupName: groupName + groupName: groupName, }, function (err) { if (!err) { app.alertSuccess('[[groups:event.deleted, ' + utils.escapeHTML(groupName) + ']]'); @@ -241,7 +248,7 @@ define('forum/groups/details', [ autocomplete.user(searchInput, function (event, selected) { socket.emit('groups.issueInvite', { toUid: selected.item.user.uid, - groupName: ajaxify.data.group.name + groupName: ajaxify.data.group.name, }, function (err) { if (err) { return app.alertError(err.message); @@ -258,7 +265,7 @@ define('forum/groups/details', [ } socket.emit('groups.issueMassInvite', { usernames: usernames, - groupName: ajaxify.data.group.name + groupName: ajaxify.data.group.name, }, function (err) { if (err) { return app.alertError(err.message); @@ -277,7 +284,7 @@ define('forum/groups/details', [ } socket.emit('groups.cover.remove', { - groupName: ajaxify.data.group.name + groupName: ajaxify.data.group.name, }, function (err) { if (!err) { ajaxify.refresh(); diff --git a/public/src/client/groups/list.js b/public/src/client/groups/list.js index 6e24bf5d78..882d59eef1 100644 --- a/public/src/client/groups/list.js +++ b/public/src/client/groups/list.js @@ -1,12 +1,10 @@ -"use strict"; -/* globals app, define, ajaxify, socket, bootbox, utils, templates */ +'use strict'; + define('forum/groups/list', ['forum/infinitescroll'], function (infinitescroll) { var Groups = {}; Groups.init = function () { - var groupsEl = $('#groups-list'); - infinitescroll.init(Groups.loadMoreGroups); // Group creation @@ -14,7 +12,7 @@ define('forum/groups/list', ['forum/infinitescroll'], function (infinitescroll) bootbox.prompt('[[groups:new-group.group_name]]', function (name) { if (name && name.length) { socket.emit('groups.create', { - name: name + name: name, }, function (err) { if (!err) { ajaxify.go('groups/' + utils.slugify(name)); @@ -43,11 +41,11 @@ define('forum/groups/list', ['forum/infinitescroll'], function (infinitescroll) infinitescroll.loadMore('groups.loadMore', { sort: $('#search-sort').val(), - after: $('[component="groups/container"]').attr('data-nextstart') + after: $('[component="groups/container"]').attr('data-nextstart'), }, function (data, done) { if (data && data.groups.length) { templates.parse('partials/groups/list', { - groups: data.groups + groups: data.groups, }, function (html) { $('#groups-list').append(html); done(); @@ -63,16 +61,16 @@ define('forum/groups/list', ['forum/infinitescroll'], function (infinitescroll) }; Groups.search = function () { - var groupsEl = $('#groups-list'), - queryEl = $('#search-text'), - sortEl = $('#search-sort'); + var groupsEl = $('#groups-list'); + var queryEl = $('#search-text'); + var sortEl = $('#search-sort'); socket.emit('groups.search', { query: queryEl.val(), options: { sort: sortEl.val(), - filterHidden: true - } + filterHidden: true, + }, }, function (err, groups) { if (err) { return app.alertError(err.message); @@ -81,7 +79,7 @@ define('forum/groups/list', ['forum/infinitescroll'], function (infinitescroll) return group.name !== 'registered-users' && group.name !== 'guests'; }); templates.parse('partials/groups/list', { - groups: groups + groups: groups, }, function (html) { groupsEl.empty().append(html); }); diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index e7e6d8b1f1..16874b6b79 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -1,8 +1,7 @@ -"use strict"; -/* globals define, socket, ajaxify, app */ +'use strict'; -define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], function (components, infinitescroll) { +define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], function () { var MemberList = {}; var searchInterval; var groupName; @@ -23,7 +22,7 @@ define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], functi } searchInterval = setTimeout(function () { - socket.emit('groups.searchMembers', {groupName: groupName, query: query}, function (err, results) { + socket.emit('groups.searchMembers', { groupName: groupName, query: query }, function (err, results) { if (err) { return app.alertError(err.message); } @@ -56,7 +55,7 @@ define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], functi members.attr('loading', 1); socket.emit('groups.loadMoreMembers', { groupName: groupName, - after: members.attr('data-nextstart') + after: members.attr('data-nextstart'), }, function (err, data) { if (err) { return app.alertError(err.message); @@ -88,10 +87,10 @@ define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], functi app.parseAndTranslate('groups/details', 'members', { group: { members: users, - isOwner: ajaxify.data.group.isOwner - } + isOwner: ajaxify.data.group.isOwner, + }, }, callback); } return MemberList; -}); \ No newline at end of file +}); diff --git a/public/src/client/infinitescroll.js b/public/src/client/infinitescroll.js index ed43e4da22..e2b52548aa 100644 --- a/public/src/client/infinitescroll.js +++ b/public/src/client/infinitescroll.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, socket, app */ define('forum/infinitescroll', function () { - var scroll = {}; var callback; var previousScrollTop = 0; @@ -34,7 +32,8 @@ define('forum/infinitescroll', function () { var offsetTop = container.offset() ? container.offset().top : 0; var scrollPercent = 100 * (currentScrollTop - offsetTop) / (viewportHeight <= 0 ? wh : viewportHeight); - var top = 20, bottom = 80; + var top = 20; + var bottom = 80; var direction = currentScrollTop > previousScrollTop ? 1 : -1; @@ -55,7 +54,7 @@ define('forum/infinitescroll', function () { } loadingMore = true; - var hookData = {method: method, data: data}; + var hookData = { method: method, data: data }; $(window).trigger('action:infinitescroll.loadmore', hookData); socket.emit(hookData.method, hookData.data, function (err, data) { @@ -76,8 +75,8 @@ define('forum/infinitescroll', function () { var removeCount = els.length - count; if (direction > 0) { - var height = $(document).height(), - scrollTop = $(window).scrollTop(); + var height = $(document).height(); + var scrollTop = $(window).scrollTop(); els.slice(0, removeCount).remove(); @@ -88,4 +87,4 @@ define('forum/infinitescroll', function () { }; return scroll; -}); \ No newline at end of file +}); diff --git a/public/src/client/login.js b/public/src/client/login.js index 1de1218fd0..078b7448f7 100644 --- a/public/src/client/login.js +++ b/public/src/client/login.js @@ -1,13 +1,13 @@ -"use strict"; -/* global define, app, config, RELATIVE_PATH */ +'use strict'; -define('forum/login', ['translator'], function (translator) { + +define('forum/login', [], function () { var Login = {}; Login.init = function () { - var errorEl = $('#login-error-notify'), - submitEl = $('#login'), - formEl = $('#login-form'); + var errorEl = $('#login-error-notify'); + var submitEl = $('#login'); + var formEl = $('#login-form'); submitEl.on('click', function (e) { e.preventDefault(); @@ -33,12 +33,12 @@ define('forum/login', ['translator'], function (translator) { formEl.ajaxSubmit({ headers: { - 'x-csrf-token': config.csrf_token + 'x-csrf-token': config.csrf_token, }, - success: function (data, status) { + success: function (data) { window.location.href = data + '?loggedin'; }, - error: function (data, status) { + error: function (data) { if (data.status === 403 && data.responseText === 'Forbidden') { window.location.href = config.relative_path + '/login?error=csrf-invalid'; } else { @@ -52,7 +52,7 @@ define('forum/login', ['translator'], function (translator) { $('#password').select(); } } - } + }, }); } }); diff --git a/public/src/client/notifications.js b/public/src/client/notifications.js index c4f17f5c97..fb61a53063 100644 --- a/public/src/client/notifications.js +++ b/public/src/client/notifications.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, app */ define('forum/notifications', ['components', 'notifications', 'forum/infinitescroll'], function (components, notifs, infinitescroll) { var Notifications = {}; @@ -46,7 +45,7 @@ define('forum/notifications', ['components', 'notifications', 'forum/infinitescr } var notifList = $('.notifications-list'); infinitescroll.loadMore('notifications.loadMore', { - after: notifList.attr('data-nextstart') + after: notifList.attr('data-nextstart'), }, function (data, done) { if (!data) { return done(); @@ -55,7 +54,7 @@ define('forum/notifications', ['components', 'notifications', 'forum/infinitescr if (!data.notifications || !data.notifications.length) { return done(); } - app.parseAndTranslate('notifications', 'notifications', {notifications: data.notifications}, function (html) { + app.parseAndTranslate('notifications', 'notifications', { notifications: data.notifications }, function (html) { notifList.append(html); html.find('.timeago').timeago(); done(); diff --git a/public/src/client/pagination.js b/public/src/client/pagination.js index 6cbd7102f0..1fba9d354d 100644 --- a/public/src/client/pagination.js +++ b/public/src/client/pagination.js @@ -1,5 +1,5 @@ 'use strict'; -/*global define, utils, ajaxify, bootbox*/ + define('forum/pagination', function () { var pagination = {}; diff --git a/public/src/client/popular.js b/public/src/client/popular.js index 00fb6937e2..02a1348156 100644 --- a/public/src/client/popular.js +++ b/public/src/client/popular.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, socket*/ define('forum/popular', ['components'], function (components) { var Popular = {}; diff --git a/public/src/client/recent.js b/public/src/client/recent.js index 0fbf49c937..981baabd12 100644 --- a/public/src/client/recent.js +++ b/public/src/client/recent.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, socket, utils, ajaxify, config */ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinitescroll, components) { var Recent = {}; @@ -27,7 +26,7 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit infinitescroll.init(Recent.loadMoreTopics); } - $(window).trigger('action:topics.loaded', {topics: ajaxify.data.topics}); + $(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); }; Recent.watchForNewPosts = function () { @@ -47,13 +46,13 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit return; } - ++newTopicCount; + newTopicCount += 1; Recent.updateAlertText(); } function onNewPost(data) { function showAlert() { - ++newPostCount; + newPostCount += 1; Recent.updateAlertText(); } @@ -135,7 +134,7 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit after: $('[component="category"]').attr('data-nextstart'), cid: utils.params().cid, filter: ajaxify.data.selectedFilter.filter, - set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent' + set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent', }, function (data, done) { if (data.topics && data.topics.length) { Recent.onTopicsLoaded('recent', data.topics, false, done); @@ -147,7 +146,6 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit }; Recent.onTopicsLoaded = function (templateName, topics, showSelect, callback) { - topics = topics.filter(function (topic) { return !components.get('category/topic', 'tid', topic.tid).length; }); @@ -156,14 +154,14 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit return callback(); } - app.parseAndTranslate(templateName, 'topics', {topics: topics, showSelect: showSelect}, function (html) { + app.parseAndTranslate(templateName, 'topics', { topics: topics, showSelect: showSelect }, function (html) { $('#category-no-topics').remove(); $('[component="category"]').append(html); html.find('.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); - $(window).trigger('action:topics.loaded', {topics: topics}); + $(window).trigger('action:topics.loaded', { topics: topics }); callback(); }); }; diff --git a/public/src/client/register.js b/public/src/client/register.js index 01dfa4dfc1..329762271e 100644 --- a/public/src/client/register.js +++ b/public/src/client/register.js @@ -1,19 +1,17 @@ 'use strict'; -/* globals define, app, utils, socket, config, ajaxify, bootbox */ - define('forum/register', ['translator'], function (translator) { - var Register = {}, - validationError = false, - successIcon = ''; + var Register = {}; + var validationError = false; + var successIcon = ''; Register.init = function () { - var email = $('#email'), - username = $('#username'), - password = $('#password'), - password_confirm = $('#password-confirm'), - register = $('#register'); + var email = $('#email'); + var username = $('#username'); + var password = $('#password'); + var password_confirm = $('#password-confirm'); + var register = $('#register'); handleLanguageOverride(); @@ -78,7 +76,7 @@ define('forum/register', ['translator'], function (translator) { registerBtn.parents('form').ajaxSubmit({ headers: { - 'x-csrf-token': config.csrf_token + 'x-csrf-token': config.csrf_token, }, success: function (data) { registerBtn.removeClass('disabled'); @@ -106,7 +104,7 @@ define('forum/register', ['translator'], function (translator) { registerBtn.removeClass('disabled'); } }); - } + }, }); }); }); @@ -122,7 +120,7 @@ define('forum/register', ['translator'], function (translator) { } socket.emit('user.emailExists', { - email: email + email: email, }, function (err, exists) { if (err) { app.alertError(err.message); @@ -152,7 +150,7 @@ define('forum/register', ['translator'], function (translator) { showError(username_notify, '[[error:invalid-username]]'); } else { socket.emit('user.exists', { - username: username + username: username, }, function (err, exists) { if (err) { return app.alertError(err.message); @@ -170,8 +168,8 @@ define('forum/register', ['translator'], function (translator) { } function validatePassword(password, password_confirm) { - var password_notify = $('#password-notify'), - password_confirm_notify = $('#password-confirm-notify'); + var password_notify = $('#password-notify'); + var password_confirm_notify = $('#password-confirm-notify'); if (password.length < ajaxify.data.minimumPasswordLength) { showError(password_notify, '[[user:change_password_error_length]]'); @@ -193,8 +191,8 @@ define('forum/register', ['translator'], function (translator) { } function validatePasswordConfirm(password, password_confirm) { - var password_notify = $('#password-notify'), - password_confirm_notify = $('#password-confirm-notify'); + var password_notify = $('#password-notify'); + var password_confirm_notify = $('#password-confirm-notify'); if (!password || password_notify.hasClass('alert-error')) { return; @@ -230,8 +228,8 @@ define('forum/register', ['translator'], function (translator) { function handleLanguageOverride() { if (!app.user.uid && config.defaultLang !== config.userLang) { - var formEl = $('[component="register/local"]'), - langEl = $(''); + var formEl = $('[component="register/local"]'); + var langEl = $(''); formEl.append(langEl); } diff --git a/public/src/client/reset.js b/public/src/client/reset.js index 3e0220957b..06bda6307a 100644 --- a/public/src/client/reset.js +++ b/public/src/client/reset.js @@ -1,18 +1,18 @@ -"use strict"; -/*globals define, app, socket*/ +'use strict'; + define('forum/reset', function () { var ResetPassword = {}; ResetPassword.init = function () { - var inputEl = $('#email'), - errorEl = $('#error'), - successEl = $('#success'); + var inputEl = $('#email'); + var errorEl = $('#error'); + var successEl = $('#success'); $('#reset').on('click', function () { if (inputEl.val() && inputEl.val().indexOf('@') !== -1) { socket.emit('user.reset.send', inputEl.val(), function (err) { - if(err) { + if (err) { return app.alertError(err.message); } diff --git a/public/src/client/reset_code.js b/public/src/client/reset_code.js index 044602144c..b62a682273 100644 --- a/public/src/client/reset_code.js +++ b/public/src/client/reset_code.js @@ -1,5 +1,5 @@ -"use strict"; -/*globals define, app, ajaxify, socket, config*/ +'use strict'; + define('forum/reset_code', function () { var ResetCode = {}; @@ -20,7 +20,7 @@ define('forum/reset_code', function () { resetEl.prop('disabled', true).html(' Changing Password'); socket.emit('user.reset.commit', { code: reset_code, - password: password.val() + password: password.val(), }, function (err) { if (err) { ajaxify.refresh(); diff --git a/public/src/client/search.js b/public/src/client/search.js index 48cf358c0c..4f65935913 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals app, define, utils*/ define('forum/search', ['search', 'autocomplete'], function (searchModule, autocomplete) { var Search = {}; @@ -36,7 +35,7 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc function getSearchData() { var form = $('#advanced-search'); var searchData = { - in: $('#search-in').val() + in: $('#search-in').val(), }; searchData.term = $('#search-input').val(); if (searchData.in === 'posts' || searchData.in === 'titlesposts' || searchData.in === 'titles') { @@ -128,7 +127,8 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc var regex = new RegExp('(' + regexStr + ')', 'gi'); $('.search-result-text p, .search-result-text h4').each(function () { - var result = $(this), nested = []; + var result = $(this); + var nested = []; result.find('*').each(function () { $(this).after(''); @@ -137,7 +137,7 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc result.html(result.html().replace(regex, '$1')); - for (var i = 0, ii = nested.length; i < ii; i++) { + for (var i = 0, ii = nested.length; i < ii; i += 1) { result.html(result.html().replace('', nested[i].html())); } }); @@ -168,7 +168,7 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc var tagEl = $('#has-tags'); tagEl.tagsinput({ confirmKeys: [13, 44], - trimValue: true + trimValue: true, }); autocomplete.tag($('#has-tags').siblings('.bootstrap-tagsinput').find('input')); diff --git a/public/src/client/tag.js b/public/src/client/tag.js index e48252ec76..2b74c17193 100644 --- a/public/src/client/tag.js +++ b/public/src/client/tag.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, ajaxify, socket */ define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function (recent, infinitescroll) { var Tag = {}; @@ -21,13 +20,13 @@ define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function (recent, } function loadMoreTopics(direction) { - if(direction < 0 || !$('[component="category"]').length) { + if (direction < 0 || !$('[component="category"]').length) { return; } infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'tag:' + ajaxify.data.tag + ':topics', - after: $('[component="category"]').attr('data-nextstart') + after: $('[component="category"]').attr('data-nextstart'), }, function (data, done) { if (data.topics && data.topics.length) { recent.onTopicsLoaded('tag', data.topics, false, done); diff --git a/public/src/client/tags.js b/public/src/client/tags.js index 221baee48e..9e1fec98b2 100644 --- a/public/src/client/tags.js +++ b/public/src/client/tags.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, utils, socket */ define('forum/tags', ['forum/infinitescroll'], function (infinitescroll) { var Tags = {}; @@ -20,7 +19,7 @@ define('forum/tags', ['forum/infinitescroll'], function (infinitescroll) { } timeoutId = setTimeout(function () { - socket.emit('topics.searchAndLoadTags', {query: $('#tag-search').val()}, function (err, results) { + socket.emit('topics.searchAndLoadTags', { query: $('#tag-search').val() }, function (err, results) { if (err) { return app.alertError(err.message); } @@ -40,7 +39,7 @@ define('forum/tags', ['forum/infinitescroll'], function (infinitescroll) { } infinitescroll.loadMore('topics.loadMoreTags', { - after: $('.tag-list').attr('data-nextstart') + after: $('.tag-list').attr('data-nextstart'), }, function (data, done) { if (data && data.tags && data.tags.length) { onTagsLoaded(data.tags, false, done); @@ -53,7 +52,7 @@ define('forum/tags', ['forum/infinitescroll'], function (infinitescroll) { function resetSearch() { socket.emit('topics.loadMoreTags', { - after: 0 + after: 0, }, function (err, data) { if (err) { return app.alertError(err.message); @@ -64,7 +63,7 @@ define('forum/tags', ['forum/infinitescroll'], function (infinitescroll) { function onTagsLoaded(tags, replace, callback) { callback = callback || function () {}; - app.parseAndTranslate('tags', 'tags', {tags: tags}, function (html) { + app.parseAndTranslate('tags', 'tags', { tags: tags }, function (html) { $('.tag-list')[replace ? 'html' : 'append'](html); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); callback(); diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 3223e81643..d620da1e70 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -1,21 +1,20 @@ 'use strict'; -/* globals define, app, socket, config, ajaxify, RELATIVE_PATH, utils */ - define('forum/topic', [ 'forum/infinitescroll', 'forum/topic/threadTools', 'forum/topic/postTools', 'forum/topic/events', 'forum/topic/posts', + 'forum/topic/images', 'forum/topic/replies', 'navigator', 'sort', - 'components' -], function (infinitescroll, threadTools, postTools, events, posts, replies, navigator, sort, components) { - var Topic = {}, - currentUrl = ''; + 'components', +], function (infinitescroll, threadTools, postTools, events, posts, images, replies, navigator, sort, components) { + var Topic = {}; + var currentUrl = ''; $(window).on('action:ajaxify.start', function (ev, data) { if (Topic.replaceURLTimeout) { @@ -112,8 +111,8 @@ define('forum/topic', [ mousetrap.bind('ctrl+f', function (e) { if (config.topicSearchEnabled) { // If in topic, open search window and populate, otherwise regular behaviour - var match = ajaxify.currentPage.match(/^topic\/([\d]+)/), - tid; + var match = ajaxify.currentPage.match(/^topic\/([\d]+)/); + var tid; if (match) { e.preventDefault(); tid = match[1]; @@ -157,12 +156,12 @@ define('forum/topic', [ message: '[[topic:bookmark_instructions]]', timeout: 0, type: 'info', - clickfn : function () { + clickfn: function () { navigator.scrollToPost(parseInt(bookmark - 1, 10), true); }, - closefn : function () { + closefn: function () { localStorage.removeItem('topic:' + tid + ':bookmark'); - } + }, }); setTimeout(function () { app.removeAlert('bookmark'); @@ -240,18 +239,16 @@ define('forum/topic', [ return; } - posts.loadImages(threshold); + images.loadImages(threshold); var newUrl = 'topic/' + ajaxify.data.slug + (index > 1 ? ('/' + index) : ''); if (newUrl !== currentUrl) { - if (Topic.replaceURLTimeout) { clearTimeout(Topic.replaceURLTimeout); } Topic.replaceURLTimeout = setTimeout(function () { - if (index >= elementCount && app.user.uid) { socket.emit('topics.markAsRead', [ajaxify.data.tid]); } @@ -266,7 +263,7 @@ define('forum/topic', [ } history.replaceState({ - url: newUrl + search + url: newUrl + search, }, null, window.location.protocol + '//' + window.location.host + RELATIVE_PATH + '/' + newUrl + search); } currentUrl = newUrl; @@ -281,8 +278,8 @@ define('forum/topic', [ if (ajaxify.data.postcount > ajaxify.data.bookmarkThreshold && (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10))) { if (app.user.uid) { socket.emit('topics.bookmark', { - 'tid': ajaxify.data.tid, - 'index': index + tid: ajaxify.data.tid, + index: index, }, function (err) { if (err) { return app.alertError(err.message); @@ -298,7 +295,6 @@ define('forum/topic', [ if (!currentBookmark || parseInt(index, 10) >= parseInt(currentBookmark, 10)) { app.removeAlert('bookmark'); } - } diff --git a/public/src/client/topic/delete-posts.js b/public/src/client/topic/delete-posts.js index ec7a0ca1d5..c2fde4ec25 100644 --- a/public/src/client/topic/delete-posts.js +++ b/public/src/client/topic/delete-posts.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, app, ajaxify, socket */ define('forum/topic/delete-posts', ['components', 'postSelect'], function (components, postSelect) { - var DeletePosts = {}; var modal; var deleteBtn; @@ -49,7 +47,7 @@ define('forum/topic/delete-posts', ['components', 'postSelect'], function (compo btn.attr('disabled', true); socket.emit(command, { tid: ajaxify.data.tid, - pids: postSelect.pids + pids: postSelect.pids, }, function (err) { btn.removeAttr('disabled'); if (err) { diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index b9dd8e9703..22a6c69d6c 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -1,16 +1,15 @@ 'use strict'; -/* globals config, app, ajaxify, define, socket, templates, utils */ define('forum/topic/events', [ 'forum/topic/postTools', 'forum/topic/threadTools', 'forum/topic/posts', + 'forum/topic/images', 'components', - 'translator' -], function (postTools, threadTools, posts, components, translator) { - + 'translator', +], function (postTools, threadTools, posts, images, components, translator) { var Events = {}; var events = { @@ -44,12 +43,12 @@ define('forum/topic/events', [ 'posts.unvote': togglePostVote, 'event:new_notification': onNewNotification, - 'event:new_post': posts.onNewPost + 'event:new_post': posts.onNewPost, }; Events.init = function () { Events.removeListeners(); - for(var eventName in events) { + for (var eventName in events) { if (events.hasOwnProperty(eventName)) { socket.on(eventName, events[eventName]); } @@ -57,7 +56,7 @@ define('forum/topic/events', [ }; Events.removeListeners = function () { - for(var eventName in events) { + for (var eventName in events) { if (events.hasOwnProperty(eventName)) { socket.removeListener(eventName, events[eventName]); } @@ -113,7 +112,7 @@ define('forum/topic/events', [ if (topicTitle.length && data.topic.title && topicTitle.html() !== data.topic.title) { ajaxify.data.title = data.topic.title; var newUrl = 'topic/' + data.topic.slug + (window.location.search ? window.location.search : ''); - history.replaceState({url: newUrl}, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + newUrl); + history.replaceState({ url: newUrl }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + newUrl); topicTitle.fadeOut(250, function () { topicTitle.html(data.topic.title).fadeIn(250); @@ -130,14 +129,14 @@ define('forum/topic/events', [ editedPostEl.html(translator.unescape(data.post.content)); editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); app.replaceSelfLinks(editedPostEl.find('a')); - posts.wrapImagesInLinks(editedPostEl.parent()); - posts.unloadImages(editedPostEl.parent()); - posts.loadImages(); + images.wrapImagesInLinks(editedPostEl.parent()); + images.unloadImages(editedPostEl.parent()); + images.loadImages(); editedPostEl.fadeIn(250); var editData = { editor: data.editor, - editedISO: utils.toISOString(data.post.edited) + editedISO: utils.toISOString(data.post.edited), }; templates.parse('partials/topic/post-editor', editData, function (html) { @@ -151,7 +150,7 @@ define('forum/topic/events', [ }); if (data.topic.tags && tagsUpdated(data.topic.tags)) { - templates.parse('partials/post_bar', 'tags', {tags: data.topic.tags}, function (html) { + templates.parse('partials/post_bar', 'tags', { tags: data.topic.tags }, function (html) { var tags = $('.tags'); tags.fadeOut(250, function () { @@ -166,7 +165,7 @@ define('forum/topic/events', [ return true; } - for (var i = 0; i < tags.length; ++i) { + for (var i = 0; i < tags.length; i += 1) { if (!$('.tags .tag-item[data-tag="' + tags[i].value + '"]').length) { return true; } @@ -179,7 +178,7 @@ define('forum/topic/events', [ $(this).remove(); posts.showBottomPostBar(); }); - ajaxify.data.postcount --; + ajaxify.data.postcount -= 1; postTools.updatePostCount(ajaxify.data.postcount); require(['forum/topic/replies'], function (replies) { replies.onPostPurged(postData); diff --git a/public/src/client/topic/flag.js b/public/src/client/topic/flag.js index 78b1dd5d2a..1d1c68a8c3 100644 --- a/public/src/client/topic/flag.js +++ b/public/src/client/topic/flag.js @@ -1,18 +1,16 @@ 'use strict'; -/* globals define, app, socket, templates */ define('forum/topic/flag', [], function () { - - var Flag = {}, - flagModal, - flagCommit; + var Flag = {}; + var flagModal; + var flagCommit; Flag.showFlagModal = function (pid, username, userslug) { parseModal({ pid: pid, username: username, - userslug: userslug + userslug: userslug, }, function (html) { flagModal = $(html); @@ -48,7 +46,7 @@ define('forum/topic/flag', [], function () { if (!pid || !reason) { return; } - socket.emit('posts.flag', {pid: pid, reason: reason}, function (err) { + socket.emit('posts.flag', { pid: pid, reason: reason }, function (err) { if (err) { return app.alertError(err.message); } diff --git a/public/src/client/topic/fork.js b/public/src/client/topic/fork.js index 80165b589c..b34d50d55f 100644 --- a/public/src/client/topic/fork.js +++ b/public/src/client/topic/fork.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, app, ajaxify, socket */ define('forum/topic/fork', ['components', 'postSelect'], function (components, postSelect) { - var Fork = {}; var forkModal; var forkCommit; @@ -44,7 +42,7 @@ define('forum/topic/fork', ['components', 'postSelect'], function (components, p socket.emit('topics.createTopicFromPosts', { title: forkModal.find('#fork-title').val(), pids: postSelect.pids, - fromTid: ajaxify.data.tid + fromTid: ajaxify.data.tid, }, function (err, newTopic) { function fadeOutAndRemove(pid) { components.get('post', 'pid', pid).fadeOut(500, function () { @@ -63,7 +61,7 @@ define('forum/topic/fork', ['components', 'postSelect'], function (components, p type: 'success', clickfn: function () { ajaxify.go('topic/' + newTopic.slug); - } + }, }); postSelect.pids.forEach(function (pid) { diff --git a/public/src/client/topic/images.js b/public/src/client/topic/images.js new file mode 100644 index 0000000000..cd44dd0914 --- /dev/null +++ b/public/src/client/topic/images.js @@ -0,0 +1,119 @@ +'use strict'; + + +define('forum/topic/images', [ + 'forum/topic/postTools', + 'navigator', + 'components', +], function (postTools, navigator, components) { + var Images = { + _imageLoaderTimeout: undefined, + }; + + Images.unloadImages = function (posts) { + var images = posts.find('[component="post/content"] img:not(.not-responsive)'); + + if (config.delayImageLoading) { + images.each(function () { + $(this).attr('data-src', $(this).attr('src')); + }).attr('data-state', 'unloaded').attr('src', 'about:blank'); + } else { + images.attr('data-state', 'loaded'); + Images.wrapImagesInLinks(posts); + } + }; + + Images.loadImages = function (threshold) { + if (Images._imageLoaderTimeout) { + clearTimeout(Images._imageLoaderTimeout); + } + + Images._imageLoaderTimeout = setTimeout(function () { + /* + If threshold is defined, images loaded above this threshold will modify + the user's scroll position so they are not scrolled away from content + they were reading. Images loaded below this threshold will push down content. + + If no threshold is defined, loaded images will push down content, as per + default + */ + + var images = components.get('post/content').find('img[data-state="unloaded"]'); + var visible = images.filter(function () { + return utils.isElementInViewport(this); + }); + var posts = $.unique(visible.map(function () { + return $(this).parents('[component="post"]').get(0); + })); + var scrollTop = $(window).scrollTop(); + var adjusting = false; + var adjustQueue = []; + var oldHeight; + var newHeight; + + function adjustPosition() { + adjusting = true; + oldHeight = document.body.clientHeight; + + // Display the image + $(this).attr('data-state', 'loaded'); + newHeight = document.body.clientHeight; + + var imageRect = this.getBoundingClientRect(); + if (imageRect.top < threshold) { + scrollTop += newHeight - oldHeight; + $(window).scrollTop(scrollTop); + } + + if (adjustQueue.length) { + adjustQueue.pop()(); + } else { + adjusting = false; + + Images.wrapImagesInLinks(posts); + posts.length = 0; + } + } + + // For each image, reset the source and adjust scrollTop when loaded + visible.attr('data-state', 'loading'); + visible.each(function (index, image) { + image = $(image); + + image.on('load', function () { + if (!adjusting) { + adjustPosition.call(this); + } else { + adjustQueue.push(adjustPosition.bind(this)); + } + }); + + image.attr('src', image.attr('data-src')); + image.removeAttr('data-src'); + }); + }, 250); + }; + + Images.wrapImagesInLinks = function (posts) { + posts.find('[component="post/content"] img:not(.emoji)').each(function () { + var $this = $(this); + var src = $this.attr('src'); + var suffixRegex = /-resized(\.[\w]+)?$/; + + if (src === 'about:blank') { + return; + } + + if (utils.isRelativeUrl(src) && suffixRegex.test(src)) { + src = src.replace(suffixRegex, '$1'); + } + + if (!$this.parent().is('a')) { + $this.wrap(''); + } + }); + }; + + + return Images; +}); diff --git a/public/src/client/topic/move-post.js b/public/src/client/topic/move-post.js index fa1c0f2b47..bd9d542ead 100644 --- a/public/src/client/topic/move-post.js +++ b/public/src/client/topic/move-post.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, app, socket */ define('forum/topic/move-post', [], function () { - var MovePost = {}; @@ -11,8 +9,8 @@ define('forum/topic/move-post', [], function () { app.parseAndTranslate('partials/move_post_modal', {}, function (html) { var moveModal = $(html); - var moveBtn = moveModal.find('#move_post_commit'), - topicId = moveModal.find('#topicId'); + var moveBtn = moveModal.find('#move_post_commit'); + var topicId = moveModal.find('#topicId'); moveModal.on('hidden.bs.modal', function () { moveModal.remove(); @@ -34,20 +32,19 @@ define('forum/topic/move-post', [], function () { topicId.val(''); }); }); - }); }; function showMoveModal(modal) { modal.modal('show') - .css("position", "fixed") - .css("left", Math.max(0, (($(window).width() - modal.outerWidth()) / 2) + $(window).scrollLeft()) + "px") - .css("top", "0px") - .css("z-index", "2000"); + .css('position', 'fixed') + .css('left', Math.max(0, (($(window).width() - modal.outerWidth()) / 2) + $(window).scrollLeft()) + 'px') + .css('top', '0px') + .css('z-index', '2000'); } function movePost(post, pid, tid, callback) { - socket.emit('posts.movePost', {pid: pid, tid: tid}, function (err) { + socket.emit('posts.movePost', { pid: pid, tid: tid }, function (err) { if (err) { app.alertError(err.message); return callback(); diff --git a/public/src/client/topic/move.js b/public/src/client/topic/move.js index de57f2a0d5..5ff9a02c49 100644 --- a/public/src/client/topic/move.js +++ b/public/src/client/topic/move.js @@ -1,18 +1,16 @@ 'use strict'; -/* globals define, app, socket, templates */ define('forum/topic/move', function () { - - var Move = {}, - modal, - selectedEl; + var Move = {}; + var modal; + var selectedEl; Move.init = function (tids, currentCid, onComplete) { Move.tids = tids; Move.currentCid = currentCid; Move.onComplete = onComplete; - Move.moveAll = tids ? false : true; + Move.moveAll = !tids; socket.emit('categories.getMoveCategories', onCategoriesLoaded); }; @@ -23,7 +21,6 @@ define('forum/topic/move', function () { } parseModal(categories, function () { - modal.on('hidden.bs.modal', function () { modal.remove(); }); @@ -45,7 +42,7 @@ define('forum/topic/move', function () { } function parseModal(categories, callback) { - templates.parse('partials/move_thread_modal', {categories: []}, function (html) { + templates.parse('partials/move_thread_modal', { categories: [] }, function (html) { require(['translator'], function (translator) { translator.translate(html, function (html) { modal = $(html); @@ -109,7 +106,7 @@ define('forum/topic/move', function () { socket.emit(Move.moveAll ? 'topics.moveAll' : 'topics.move', { tids: Move.tids, cid: selectedEl.attr('data-cid'), - currentCid: Move.currentCid + currentCid: Move.currentCid, }, function (err) { modal.modal('hide'); diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index ccd72c640d..e012b20186 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, ajaxify, bootbox, socket, templates, utils, config */ define('forum/topic/postTools', [ 'share', @@ -8,9 +7,8 @@ define('forum/topic/postTools', [ 'components', 'translator', 'forum/topic/votes', - 'forum/topic/move-post' + 'forum/topic/move-post', ], function (share, navigator, components, translator, votes, movePost) { - var PostTools = {}; var staleReplyAnyway = false; @@ -40,7 +38,7 @@ define('forum/topic/postTools', [ var pid = postEl.attr('data-pid'); var index = parseInt(postEl.attr('data-index'), 10); - socket.emit('posts.loadPostTools', {pid: pid, cid: ajaxify.data.cid}, function (err, data) { + socket.emit('posts.loadPostTools', { pid: pid, cid: ajaxify.data.cid }, function (err, data) { if (err) { return app.alertError(err.message); } @@ -95,7 +93,7 @@ define('forum/topic/postTools', [ translator.translate('[[topic:link_back, ' + ajaxify.data.titleRaw + ', ' + config.relative_path + '/topic/' + ajaxify.data.slug + ']]', function (body) { $(window).trigger('action:composer.topic.new', { cid: ajaxify.data.cid, - body: body + body: body, }); }); }); @@ -133,7 +131,7 @@ define('forum/topic/postTools', [ if (checkDuration(postEditDuration, timestamp, 'post-edit-duration-expired')) { $(window).trigger('action:composer.post.edit', { - pid: getData(btn, 'data-pid') + pid: getData(btn, 'data-pid'), }); } }); @@ -215,14 +213,14 @@ define('forum/topic/postTools', [ topicName: ajaxify.data.titleRaw, username: username, text: selectedNode.text, - selectedPid: selectedNode.pid + selectedPid: selectedNode.pid, }); } else { $(window).trigger('action:composer.post.new', { tid: tid, pid: toPid, topicName: ajaxify.data.titleRaw, - text: username ? username + ' ' : '' + text: username ? username + ' ' : '', }); } }); @@ -232,6 +230,8 @@ define('forum/topic/postTools', [ var selectedNode = getSelectedNode(); showStaleWarning(function () { + var username = getUserName(button); + var toPid = getData(button, 'data-pid'); function quote(text) { $(window).trigger('action:composer.addQuote', { @@ -239,13 +239,10 @@ define('forum/topic/postTools', [ pid: toPid, username: username, topicName: ajaxify.data.titleRaw, - text: text + text: text, }); } - var username = getUserName(button); - var toPid = getData(button, 'data-pid'); - if (selectedNode.text && toPid && toPid === selectedNode.pid) { return quote(selectedNode.text); } @@ -289,7 +286,7 @@ define('forum/topic/postTools', [ username = getUserName($(content)); range.detach(); } - return {text: selectedText, pid: selectedPid, username: username}; + return { text: selectedText, pid: selectedPid, username: username }; } function bookmarkPost(button, pid) { @@ -297,7 +294,7 @@ define('forum/topic/postTools', [ socket.emit(method, { pid: pid, - room_id: app.currentRoom + room_id: app.currentRoom, }, function (err) { if (err) { app.alertError(err.message); @@ -350,7 +347,7 @@ define('forum/topic/postTools', [ socket.emit('posts.' + action, { pid: pid, - tid: tid + tid: tid, }, function (err) { if (err) { app.alertError(err.message); @@ -375,31 +372,31 @@ define('forum/topic/postTools', [ translator.translate('[[topic:stale.warning]]', function (translated) { var warning = bootbox.dialog({ - title: '[[topic:stale.title]]', - message: translated, - buttons: { - reply: { - label: '[[topic:stale.reply_anyway]]', - className: 'btn-link', - callback: function () { - staleReplyAnyway = true; - callback(); - } + title: '[[topic:stale.title]]', + message: translated, + buttons: { + reply: { + label: '[[topic:stale.reply_anyway]]', + className: 'btn-link', + callback: function () { + staleReplyAnyway = true; + callback(); }, - create: { - label: '[[topic:stale.create]]', - className: 'btn-primary', - callback: function () { - translator.translate('[[topic:link_back, ' + ajaxify.data.title + ', ' + config.relative_path + '/topic/' + ajaxify.data.slug + ']]', function (body) { - $(window).trigger('action:composer.topic.new', { - cid: ajaxify.data.cid, - body: body - }); + }, + create: { + label: '[[topic:stale.create]]', + className: 'btn-primary', + callback: function () { + translator.translate('[[topic:link_back, ' + ajaxify.data.title + ', ' + config.relative_path + '/topic/' + ajaxify.data.slug + ']]', function (body) { + $(window).trigger('action:composer.topic.new', { + cid: ajaxify.data.cid, + body: body, }); - } - } - } - }); + }); + }, + }, + }, + }); warning.modal(); }); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 4103864c0b..72f580b582 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -1,35 +1,28 @@ 'use strict'; -/* globals config, app, ajaxify, define, utils */ define('forum/topic/posts', [ 'forum/pagination', 'forum/infinitescroll', 'forum/topic/postTools', + 'forum/topic/images', 'navigator', - 'components' -], function (pagination, infinitescroll, postTools, navigator, components) { - - var Posts = { - _imageLoaderTimeout: undefined - }; + 'components', +], function (pagination, infinitescroll, postTools, images, navigator, components) { + var Posts = { }; Posts.onNewPost = function (data) { - if (!data || !data.posts || !data.posts.length) { + if (!data || !data.posts || !data.posts.length || parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)) { return; } - if (parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)) { - return; - } - - data.loggedIn = app.user.uid ? true : false; + data.loggedIn = !!app.user.uid; data.privileges = ajaxify.data.privileges; Posts.modifyPostsByPrivileges(data.posts); updatePostCounts(data.posts); - ajaxify.data.postcount ++; + ajaxify.data.postcount += 1; postTools.updatePostCount(ajaxify.data.postcount); if (config.usePagination) { @@ -55,7 +48,7 @@ define('forum/topic/posts', [ }; function updatePostCounts(posts) { - for (var i = 0; i < posts.length; ++i) { + for (var i = 0; i < posts.length; i += 1) { var cmp = components.get('user/postcount', posts[i].uid); cmp.html(parseInt(cmp.attr('data-postcount'), 10) + 1); utils.addCommasToNumbers(cmp); @@ -65,7 +58,7 @@ define('forum/topic/posts', [ function onNewPostPagination(data) { function scrollToPost() { scrollToPostIfSelf(data.posts[0]); - Posts.loadImages(); + images.loadImages(); } var posts = data.posts; @@ -89,8 +82,8 @@ define('forum/topic/posts', [ } function updatePagination() { - $.get(config.relative_path + '/api/topic/pagination/' + ajaxify.data.tid, {page: ajaxify.data.pagination.currentPage}, function (paginationData) { - app.parseAndTranslate('partials/paginator', {pagination: paginationData}, function (html) { + $.get(config.relative_path + '/api/topic/pagination/' + ajaxify.data.tid, { page: ajaxify.data.pagination.currentPage }, function (paginationData) { + app.parseAndTranslate('partials/paginator', { pagination: paginationData }, function (html) { $('[component="pagination"]').after(html).remove(); }); }); @@ -109,7 +102,7 @@ define('forum/topic/posts', [ html.addClass('new'); } scrollToPostIfSelf(data.posts[0]); - Posts.loadImages(); + images.loadImages(); }); } @@ -165,7 +158,8 @@ define('forum/topic/posts', [ return callback(); } - var after, before; + var after; + var before; if (direction > 0 && repliesSelector.length) { after = repliesSelector.last(); @@ -175,10 +169,9 @@ define('forum/topic/posts', [ data.slug = ajaxify.data.slug; - $(window).trigger('action:posts.loading', {posts: data.posts, after: after, before: before}); + $(window).trigger('action:posts.loading', { posts: data.posts, after: after, before: before }); app.parseAndTranslate('topic', 'posts', data, function (html) { - html = html.filter(function () { var pid = $(this).attr('data-pid'); return pid && $('[component="post"][data-pid="' + pid + '"]').length === 0; @@ -188,8 +181,8 @@ define('forum/topic/posts', [ html.insertAfter(after); } else if (before) { // Save document height and position for future reference (about 5 lines down) - var height = $(document).height(), - scrollTop = $(window).scrollTop(); + var height = $(document).height(); + var scrollTop = $(window).scrollTop(); html.insertBefore(before); @@ -201,7 +194,7 @@ define('forum/topic/posts', [ infinitescroll.removeExtra($('[component="post"]'), direction, 40); - $(window).trigger('action:posts.loaded', {posts: data.posts}); + $(window).trigger('action:posts.loaded', { posts: data.posts }); Posts.processPage(html); @@ -235,7 +228,7 @@ define('forum/topic/posts', [ tid: tid, after: after, direction: direction, - topicPostSort: config.topicPostSort + topicPostSort: config.topicPostSort, }, function (data, done) { indicatorEl.fadeOut(); @@ -249,7 +242,7 @@ define('forum/topic/posts', [ }; Posts.processPage = function (posts) { - Posts.unloadImages(posts); + images.unloadImages(posts); Posts.showBottomPostBar(); posts.find('[component="post/content"] img:not(.not-responsive)').addClass('img-responsive'); app.createUserTooltips(posts); @@ -262,108 +255,6 @@ define('forum/topic/posts', [ hidePostToolsForDeletedPosts(posts); }; - Posts.unloadImages = function (posts) { - var images = posts.find('[component="post/content"] img:not(.not-responsive)'); - - if (config.delayImageLoading) { - images.each(function () { - $(this).attr('data-src', $(this).attr('src')); - }).attr('data-state', 'unloaded').attr('src', 'about:blank'); - } else { - images.attr('data-state', 'loaded'); - Posts.wrapImagesInLinks(posts); - } - }; - - Posts.loadImages = function (threshold) { - if (Posts._imageLoaderTimeout) { - clearTimeout(Posts._imageLoaderTimeout); - } - - Posts._imageLoaderTimeout = setTimeout(function () { - /* - If threshold is defined, images loaded above this threshold will modify - the user's scroll position so they are not scrolled away from content - they were reading. Images loaded below this threshold will push down content. - - If no threshold is defined, loaded images will push down content, as per - default - */ - - var images = components.get('post/content').find('img[data-state="unloaded"]'), - visible = images.filter(function () { - return utils.isElementInViewport(this); - }), - posts = $.unique(visible.map(function () { - return $(this).parents('[component="post"]').get(0); - })), - scrollTop = $(window).scrollTop(), - adjusting = false, - adjustQueue = [], - adjustPosition = function () { - adjusting = true; - oldHeight = document.body.clientHeight; - - // Display the image - $(this).attr('data-state', 'loaded'); - newHeight = document.body.clientHeight; - - var imageRect = this.getBoundingClientRect(); - if (imageRect.top < threshold) { - scrollTop = scrollTop + (newHeight - oldHeight); - $(window).scrollTop(scrollTop); - } - - if (adjustQueue.length) { - adjustQueue.pop()(); - } else { - adjusting = false; - - Posts.wrapImagesInLinks(posts); - posts.length = 0; - } - }, - oldHeight, newHeight; - - // For each image, reset the source and adjust scrollTop when loaded - visible.attr('data-state', 'loading'); - visible.each(function (index, image) { - image = $(image); - - image.on('load', function () { - if (!adjusting) { - adjustPosition.call(this); - } else { - adjustQueue.push(adjustPosition.bind(this)); - } - }); - - image.attr('src', image.attr('data-src')); - image.removeAttr('data-src'); - }); - }, 250); - }; - - Posts.wrapImagesInLinks = function (posts) { - posts.find('[component="post/content"] img:not(.emoji)').each(function () { - var $this = $(this), - src = $this.attr('src'), - suffixRegex = /-resized(\.[\w]+)?$/; - - if (src === 'about:blank') { - return; - } - - if (utils.isRelativeUrl(src) && suffixRegex.test(src)) { - src = src.replace(suffixRegex, '$1'); - } - - if (!$this.parent().is('a')) { - $this.wrap(''); - } - }); - }; - Posts.showBottomPostBar = function () { var mainPost = components.get('post', 'index', 0); var placeHolder = $('.post-bar-placeholder'); @@ -394,5 +285,4 @@ define('forum/topic/posts', [ } return Posts; - }); diff --git a/public/src/client/topic/replies.js b/public/src/client/topic/replies.js index ba7fd81f33..56b5981843 100644 --- a/public/src/client/topic/replies.js +++ b/public/src/client/topic/replies.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, app, ajaxify, socket */ define('forum/topic/replies', ['navigator', 'components', 'forum/topic/posts'], function (navigator, components, posts) { - var Replies = {}; Replies.init = function (tid) { @@ -18,7 +16,7 @@ define('forum/topic/replies', ['navigator', 'components', 'forum/topic/posts'], }); } - function onRepliesClicked(button, tid) { + function onRepliesClicked(button) { var post = button.closest('[data-pid]'); var pid = post.data('pid'); var open = button.children('[component="post/replies/open"]'); @@ -45,12 +43,12 @@ define('forum/topic/replies', ['navigator', 'components', 'forum/topic/posts'], 'downvote:disabled': ajaxify.data['downvote:disabled'], 'reputation:disabled': ajaxify.data['reputation:disabled'], loggedIn: !!app.user.uid, - hideReplies: true + hideReplies: true, }; app.parseAndTranslate('topic', 'posts', tplData, function (html) { - $('
    ', {component: 'post/replies'}).html(html).hide().insertAfter(button).slideDown('fast'); + $('
    ', { component: 'post/replies' }).html(html).hide().insertAfter(button).slideDown('fast'); posts.processPage(html); - $(window).trigger('action:posts.loaded', {posts: data}); + $(window).trigger('action:posts.loaded', { posts: data }); }); }); } else if (close.is(':not(.hidden)')) { diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index 7eef6306a3..70065678f0 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -1,19 +1,16 @@ 'use strict'; -/* globals define, app, ajaxify, socket, bootbox, templates */ define('forum/topic/threadTools', [ 'forum/topic/fork', 'forum/topic/move', 'forum/topic/delete-posts', 'components', - 'translator' + 'translator', ], function (fork, move, deletePosts, components, translator) { - var ThreadTools = {}; ThreadTools.init = function (tid) { - renderMenu(); var topicContainer = $('.topic'); @@ -34,22 +31,22 @@ define('forum/topic/threadTools', [ }); topicContainer.on('click', '[component="topic/lock"]', function () { - socket.emit('topics.lock', {tids: [tid], cid: ajaxify.data.cid}); + socket.emit('topics.lock', { tids: [tid], cid: ajaxify.data.cid }); return false; }); topicContainer.on('click', '[component="topic/unlock"]', function () { - socket.emit('topics.unlock', {tids: [tid], cid: ajaxify.data.cid}); + socket.emit('topics.unlock', { tids: [tid], cid: ajaxify.data.cid }); return false; }); topicContainer.on('click', '[component="topic/pin"]', function () { - socket.emit('topics.pin', {tids: [tid], cid: ajaxify.data.cid}); + socket.emit('topics.pin', { tids: [tid], cid: ajaxify.data.cid }); return false; }); topicContainer.on('click', '[component="topic/unpin"]', function () { - socket.emit('topics.unpin', {tids: [tid], cid: ajaxify.data.cid}); + socket.emit('topics.unpin', { tids: [tid], cid: ajaxify.data.cid }); return false; }); @@ -94,14 +91,14 @@ define('forum/topic/threadTools', [ }); function changeWatching(type) { - socket.emit('topics.changeWatching', {tid: tid, type: type}, function (err) { + socket.emit('topics.changeWatching', { tid: tid, type: type }, function (err) { if (err) { return app.alert({ type: 'danger', alert_id: 'topic_follow', title: '[[global:please_log_in]]', message: '[[topic:login_to_subscribe]]', - timeout: 5000 + timeout: 5000, }); } var message = ''; @@ -118,10 +115,10 @@ define('forum/topic/threadTools', [ alert_id: 'follow_thread', message: message, type: 'success', - timeout: 5000 + timeout: 5000, }); - $(window).trigger('action:topics.changeWatching', {tid: tid, type: type}); + $(window).trigger('action:topics.changeWatching', { tid: tid, type: type }); }); return false; @@ -136,7 +133,7 @@ define('forum/topic/threadTools', [ return; } - socket.emit('topics.loadTopicTools', {tid: ajaxify.data.tid, cid: ajaxify.data.cid}, function (err, data) { + socket.emit('topics.loadTopicTools', { tid: ajaxify.data.tid, cid: ajaxify.data.cid }, function (err, data) { if (err) { return app.alertError(err); } @@ -158,7 +155,7 @@ define('forum/topic/threadTools', [ return; } - socket.emit('topics.' + command, {tids: [tid], cid: ajaxify.data.cid}, function (err) { + socket.emit('topics.' + command, { tids: [tid], cid: ajaxify.data.cid }, function (err) { if (err) { app.alertError(err.message); } @@ -237,7 +234,7 @@ define('forum/topic/threadTools', [ components.get('topic/not-following/check').toggleClass('fa-check', state === 'unfollow'); menu = components.get('topic/ignoring/menu'); - menu.toggleClass('hidden', state !== 'ignore' ); + menu.toggleClass('hidden', state !== 'ignore'); components.get('topic/ignoring/check').toggleClass('fa-check', state === 'ignore'); } diff --git a/public/src/client/topic/votes.js b/public/src/client/topic/votes.js index 8bd1b30b6b..d152d9f4a0 100644 --- a/public/src/client/topic/votes.js +++ b/public/src/client/topic/votes.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, app, socket, ajaxify, templates, bootbox */ define('forum/topic/votes', ['components', 'translator'], function (components, translator) { - var Votes = {}; Votes.addVoteHandler = function () { @@ -64,12 +62,12 @@ define('forum/topic/votes', ['components', 'translator'], function (components, Votes.toggleVote = function (button, className, method) { - var post = button.parents('[data-pid]'), - currentState = post.find(className).length; + var post = button.parents('[data-pid]'); + var currentState = post.find(className).length; - socket.emit(currentState ? 'posts.unvote' : method , { + socket.emit(currentState ? 'posts.unvote' : method, { pid: post.attr('data-pid'), - room_id: app.currentRoom + room_id: app.currentRoom, }, function (err) { if (err) { if (err.message === 'self-vote') { @@ -84,7 +82,7 @@ define('forum/topic/votes', ['components', 'translator'], function (components, }; Votes.showVotes = function (pid) { - socket.emit('posts.getVoters', {pid: pid, cid: ajaxify.data.cid}, function (err, data) { + socket.emit('posts.getVoters', { pid: pid, cid: ajaxify.data.cid }, function (err, data) { if (err) { if (err.message === '[[error:no-privileges]]') { return; @@ -100,13 +98,12 @@ define('forum/topic/votes', ['components', 'translator'], function (components, title: 'Voters', message: translated, className: 'vote-modal', - show: true + show: true, }); dialog.on('click', function () { dialog.modal('hide'); }); - }); }); }); diff --git a/public/src/client/unread.js b/public/src/client/unread.js index e185788981..f5b1dd73ed 100644 --- a/public/src/client/unread.js +++ b/public/src/client/unread.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, app, socket */ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', 'components'], function (recent, topicSelect, infinitescroll, components) { var Unread = {}; @@ -20,15 +19,15 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' recent.watchForNewPosts(); - $(window).trigger('action:topics.loaded', {topics: ajaxify.data.topics}); + $(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); $('#markSelectedRead').on('click', function () { var tids = topicSelect.getSelectedTids(); - if(!tids.length) { + if (!tids.length) { return; } socket.emit('topics.markAsRead', tids, function (err) { - if(err) { + if (err) { return app.alertError(err.message); } @@ -38,7 +37,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' $('#markAllRead').on('click', function () { socket.emit('topics.markAllRead', function (err) { - if(err) { + if (err) { return app.alertError(err.message); } @@ -63,7 +62,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' var tids = getCategoryTids(cid); socket.emit('topics.markCategoryTopicsRead', cid, function (err) { - if(err) { + if (err) { return app.alertError(err.message); } @@ -73,7 +72,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' topicSelect.init(); - if ($("body").height() <= $(window).height() && $('[component="category"]').children().length >= 20) { + if ($('body').height() <= $(window).height() && $('[component="category"]').children().length >= 20) { $('#load-more-btn').show(); } @@ -86,7 +85,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' } function loadMoreTopics(direction) { - if(direction < 0 || !$('[component="category"]').length) { + if (direction < 0 || !$('[component="category"]').length) { return; } var params = utils.params(); @@ -94,7 +93,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' infinitescroll.loadMore('topics.loadMoreUnreadTopics', { after: $('[component="category"]').attr('data-nextstart'), cid: cid, - filter: ajaxify.data.selectedFilter.filter + filter: ajaxify.data.selectedFilter.filter, }, function (data, done) { if (data.topics && data.topics.length) { recent.onTopicsLoaded('unread', data.topics, true, done); @@ -119,7 +118,7 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' } function removeTids(tids) { - for(var i = 0; i < tids.length; ++i) { + for (var i = 0; i < tids.length; i += 1) { components.get('category/topic', 'tid', tids[i]).remove(); } } diff --git a/public/src/client/users.js b/public/src/client/users.js index bbf11b46db..ab9ed7f5c5 100644 --- a/public/src/client/users.js +++ b/public/src/client/users.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, app, templates, bootbox, utils */ define('forum/users', ['translator'], function (translator) { var Users = {}; @@ -52,7 +51,7 @@ define('forum/users', ['translator'], function (translator) { var query = { section: activeSection, - page: 1 + page: 1, }; if (!username) { @@ -66,7 +65,7 @@ define('forum/users', ['translator'], function (translator) { query.onlineOnly = true; } if (activeSection === 'banned') { - query.bannedOnly = true; + query.bannedOnly = true; } if (activeSection === 'flagged') { query.flaggedOnly = true; @@ -99,7 +98,7 @@ define('forum/users', ['translator'], function (translator) { } function renderSearchResults(data) { - templates.parse('partials/paginator', {pagination: data.pagination}, function (html) { + templates.parse('partials/paginator', { pagination: data.pagination }, function (html) { $('.pagination-container').replaceWith(html); }); diff --git a/public/src/installer/install.js b/public/src/installer/install.js index cb645771e4..2b789041da 100644 --- a/public/src/installer/install.js +++ b/public/src/installer/install.js @@ -1,5 +1,5 @@ -"use strict"; -/*global utils*/ +'use strict'; + $('document').ready(function () { setupInputs(); @@ -10,14 +10,13 @@ $('document').ready(function () { if ($('#database-error').length) { $('[name="database"]').parents('.input-row').addClass('error'); $('html, body').animate({ - scrollTop: ($('#database-error').offset().top + 100) + 'px' + scrollTop: ($('#database-error').offset().top + 100) + 'px', }, 400); } $('#launch').on('click', launchForum); - function setupInputs() { $('form').on('focus', '.form-control', function () { var parent = $(this).parents('.input-row'); @@ -43,18 +42,17 @@ $('document').ready(function () { if ($('form .admin .error').length) { ev.preventDefault(); - $('html, body').animate({'scrollTop': '0px'}, 400); + $('html, body').animate({ scrollTop: '0px' }, 400); return false; - } else { - $('#submit .fa-spin').removeClass('hide'); } + $('#submit .fa-spin').removeClass('hide'); } function activate(type, el) { - var field = el.val(), - parent = el.parents('.input-row'), - help = parent.children('.help-text'); + var field = el.val(); + var parent = el.parents('.input-row'); + var help = parent.children('.help-text'); function validateUsername(field) { if (!utils.isUserNameValid(field) || !utils.slugify(field)) { @@ -77,7 +75,7 @@ $('document').ready(function () { } } - function validateConfirmPassword(field) { + function validateConfirmPassword() { if ($('[name="admin:password"]').val() !== $('[name="admin:passwordConfirm"]').val()) { parent.addClass('error'); help.html('Passwords do not match.'); @@ -100,16 +98,16 @@ $('document').ready(function () { } switch (type) { - case 'admin:username': - return validateUsername(field); - case 'admin:password': - return validatePassword(field); - case 'admin:passwordConfirm': - return validateConfirmPassword(field); - case 'admin:email': - return validateEmail(field); - case 'database': - return switchDatabase(field); + case 'admin:username': + return validateUsername(field); + case 'admin:password': + return validatePassword(field); + case 'admin:passwordConfirm': + return validateConfirmPassword(field); + case 'admin:email': + return validateEmail(field); + case 'database': + return switchDatabase(field); } } @@ -118,10 +116,10 @@ $('document').ready(function () { $.post('/launch', function () { setInterval(function () { - $.get('/admin').done(function (data) { + $.get('/admin').done(function () { window.location = 'admin'; }); }, 750); }); } -}); \ No newline at end of file +}); diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 1c9b0bd086..3e55ce1ff1 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -1,5 +1,5 @@ 'use strict'; -/* globals define, templates */ + define('alerts', ['translator', 'components'], function (translator, components) { var module = {}; @@ -30,7 +30,7 @@ define('alerts', ['translator', 'components'], function (translator, components) components.get('toaster/tray').prepend(alert); - if(typeof params.closefn === 'function') { + if (typeof params.closefn === 'function') { alert.find('button').on('click', function () { params.closefn(); fadeOut(alert); @@ -46,7 +46,7 @@ define('alerts', ['translator', 'components'], function (translator, components) alert .addClass('pointer') .on('click', function (e) { - if(!$(e.target).is('.close')) { + if (!$(e.target).is('.close')) { params.clickfn(); } fadeOut(alert); @@ -82,7 +82,7 @@ define('alerts', ['translator', 'components'], function (translator, components) alert .addClass('pointer') .on('click', function (e) { - if(!$(e.target).is('.close')) { + if (!$(e.target).is('.close')) { params.clickfn(); } fadeOut(alert); diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index ecaf563d10..68cabdb45b 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -1,7 +1,6 @@ 'use strict'; -/* globals define, socket, app */ define('autocomplete', function () { var module = {}; @@ -15,7 +14,7 @@ define('autocomplete', function () { }, select: onselect, source: function (request, response) { - socket.emit('user.search', {query: request.term}, function (err, result) { + socket.emit('user.search', { query: request.term }, function (err, result) { if (err) { return app.alertError(err.message); } @@ -29,15 +28,15 @@ define('autocomplete', function () { user: { uid: user.uid, name: user.username, - slug: user.userslug - } + slug: user.userslug, + }, }; }); response(names); } $('.ui-autocomplete a').attr('data-ajaxify', 'false'); }); - } + }, }); }); }; @@ -49,7 +48,7 @@ define('autocomplete', function () { select: onselect, source: function (request, response) { socket.emit('groups.search', { - query: request.term + query: request.term, }, function (err, results) { if (err) { return app.alertError(err.message); @@ -62,15 +61,15 @@ define('autocomplete', function () { value: group.name, group: { name: group.name, - slug: group.slug - } + slug: group.slug, + }, }; }); response(names); } $('.ui-autocomplete a').attr('data-ajaxify', 'false'); }); - } + }, }); }); }; @@ -95,7 +94,7 @@ define('autocomplete', function () { source: function (request, response) { socket.emit('topics.autocompleteTags', { query: request.term, - cid: ajaxify.data.cid || 0 + cid: ajaxify.data.cid || 0, }, function (err, tags) { if (err) { return app.alertError(err.message); @@ -105,7 +104,7 @@ define('autocomplete', function () { } $('.ui-autocomplete a').attr('data-ajaxify', 'false'); }); - } + }, }); }); }; diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index e8a108c46f..2a226a28a7 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -1,5 +1,5 @@ -"use strict"; -/* globals app, define, socket, templates, utils, ajaxify */ +'use strict'; + define('chat', [ 'components', @@ -9,9 +9,8 @@ define('chat', [ 'forum/chats', 'forum/chats/messages', 'translator', - 'scrollStop' + 'scrollStop', ], function (components, taskbar, S, sounds, Chats, ChatsMessages, translator, scrollStop) { - var module = {}; var newMessage = false; @@ -72,11 +71,11 @@ define('chat', [ taskbar.push('chat', modal.attr('UUID'), { title: username, touid: data.message.fromUser.uid, - roomId: data.roomId + roomId: data.roomId, }); } } else { - socket.emit('modules.chats.loadRoom', {roomId: data.roomId}, function (err, roomData) { + socket.emit('modules.chats.loadRoom', { roomId: data.roomId }, function (err, roomData) { if (err) { return app.alertError(err.message); } @@ -109,17 +108,17 @@ define('chat', [ }; module.loadChatsDropdown = function (chatsListEl) { - socket.emit('modules.chats.getRecentChats', {uid: app.user.uid, after: 0}, function (err, data) { + socket.emit('modules.chats.getRecentChats', { uid: app.user.uid, after: 0 }, function (err, data) { if (err) { return app.alertError(err.message); } var rooms = data.rooms.filter(function (room) { - return room.teaser; + return room.teaser; }); templates.parse('partials/chats/dropdown', { - rooms: rooms + rooms: rooms, }, function (html) { translator.translate(html, function (translated) { chatsListEl.empty().html(translated); @@ -157,7 +156,6 @@ define('chat', [ module.createModal = function (data, callback) { app.parseAndTranslate('chat', data, function (chatModal) { - var uuid = utils.generateUUID(); var dragged = false; @@ -175,7 +173,7 @@ define('chat', [ chatModal.find('.modal-content').resizable({ handles: 'n, e, s, w, se', minHeight: 250, - minWidth: 400 + minWidth: 400, }); chatModal.find('.modal-content').on('resize', function (event, ui) { @@ -187,17 +185,17 @@ define('chat', [ }); chatModal.draggable({ - start:function () { + start: function () { module.bringModalToTop(chatModal); }, - stop:function () { + stop: function () { chatModal.find('#chat-message-input').focus(); }, distance: 10, - handle: '.modal-header' + handle: '.modal-header', }); }); - + scrollStop.apply(chatModal.find('[component="chat/messages"]')); chatModal.find('#chat-close-btn').on('click', function () { @@ -264,7 +262,7 @@ define('chat', [ title: data.roomName || (data.users.length ? data.users[0].username : ''), roomId: data.roomId, icon: 'fa-comment', - state: '' + state: '', }); $(window).trigger('action:chat.loaded', chatModal); @@ -298,7 +296,7 @@ define('chat', [ hideAfter = true; } chatModal.css('left', Math.max(0, (($(window).width() - $(chatModal).outerWidth()) / 2) + $(window).scrollLeft()) + 'px'); - chatModal.css('top', Math.max(0, $(window).height() / 2 - $(chatModal).outerHeight() / 2) + 'px'); + chatModal.css('top', Math.max(0, ($(window).height() / 2) - ($(chatModal).outerHeight() / 2)) + 'px'); if (hideAfter) { chatModal.addClass('hide'); diff --git a/public/src/modules/components.js b/public/src/modules/components.js index ef936d0f75..29d9e883a1 100644 --- a/public/src/modules/components.js +++ b/public/src/modules/components.js @@ -1,4 +1,5 @@ -"use strict"; +'use strict'; + define('components', function () { var components = {}; @@ -6,14 +7,13 @@ define('components', function () { 'topic/teaser': function (tid) { if (tid) { return $('[component="category/topic"][data-tid="' + tid + '"] [component="topic/teaser"]'); - } else { - return $('[component="topic/teaser"]'); } + return $('[component="topic/teaser"]'); }, - 'topic': function (name, value) { + topic: function (name, value) { return $('[component="topic"][data-' + name + '="' + value + '"]'); }, - 'post': function (name, value) { + post: function (name, value) { return $('[component="post"][data-' + name + '="' + value + '"]'); }, 'post/content': function (pid) { @@ -52,7 +52,7 @@ define('components', function () { }, 'chat/message/body': function (messageId) { return $('[component="chat/message"][data-mid="' + messageId + '"] [component="chat/message/body"]'); - } + }, }; components.get = function () { @@ -60,9 +60,8 @@ define('components', function () { if (components.core[arguments[0]] && args.length) { return components.core[arguments[0]].apply(this, args); - } else { - return $('[component="' + arguments[0] + '"]'); } + return $('[component="' + arguments[0] + '"]'); }; return components; diff --git a/public/src/modules/coverPhoto.js b/public/src/modules/coverPhoto.js index fa6bdc4d7d..8cae013101 100644 --- a/public/src/modules/coverPhoto.js +++ b/public/src/modules/coverPhoto.js @@ -1,13 +1,12 @@ -"use strict"; -/* globals define, app */ +'use strict'; + define('coverPhoto', [ - 'vendor/jquery/draggable-background/backgroundDraggable' + 'vendor/jquery/draggable-background/backgroundDraggable', ], function () { - var coverPhoto = { coverEl: null, - saveFn: null + saveFn: null, }; coverPhoto.init = function (coverEl, saveFn, uploadFn, removeFn) { @@ -38,8 +37,8 @@ define('coverPhoto', [ e.stopPropagation(); e.preventDefault(); - var files = e.originalEvent.dataTransfer.files, - reader = new FileReader(); + var files = e.originalEvent.dataTransfer.files; + var reader = new FileReader(); if (files.length && files[0].type.match('image.*')) { reader.onload = function (e) { @@ -56,14 +55,14 @@ define('coverPhoto', [ coverEl.toggleClass('active', 1) .backgroundDraggable({ axis: 'y', - units: 'percent' + units: 'percent', }); app.alert({ alert_id: 'drag_start', title: '[[modules:cover.dragging_title]]', message: '[[modules:cover.dragging_message]]', - timeout: 5000 + timeout: 5000, }); } @@ -86,4 +85,4 @@ define('coverPhoto', [ }; return coverPhoto; -}); \ No newline at end of file +}); diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index b1ac2e183e..3f02a86758 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -1,5 +1,6 @@ -;(function (exports) { - "use strict"; +'use strict'; + +(function (exports) { /* globals define, utils, config */ // export the class if we are in a Node-like system. @@ -15,9 +16,9 @@ return false; } var properties = item.properties; - + var loggedIn = data.config ? data.config.loggedIn : false; if (properties) { - if ((properties.loggedIn && !data.config.loggedIn) || + if ((properties.loggedIn && !loggedIn) || (properties.globalMod && !data.isGlobalMod && !data.isAdmin) || (properties.adminOnly && !data.isAdmin) || (properties.searchInstalled && !data.searchEnabled)) { @@ -25,11 +26,11 @@ } } - if (item.route.match('/users') && data.privateUserInfo && !data.config.loggedIn) { + if (item.route.match('/users') && data.privateUserInfo && !loggedIn) { return false; } - if (item.route.match('/tags') && data.privateTagListing && !data.config.loggedIn) { + if (item.route.match('/tags') && data.privateTagListing && !loggedIn) { return false; } @@ -37,43 +38,41 @@ }; helpers.buildMetaTag = function (tag) { - var name = tag.name ? 'name="' + tag.name + '" ' : '', - property = tag.property ? 'property="' + tag.property + '" ' : '', - content = tag.content ? 'content="' + tag.content.replace(/\n/g, ' ') + '" ' : ''; + var name = tag.name ? 'name="' + tag.name + '" ' : ''; + var property = tag.property ? 'property="' + tag.property + '" ' : ''; + var content = tag.content ? 'content="' + tag.content.replace(/\n/g, ' ') + '" ' : ''; return '\n\t'; }; helpers.buildLinkTag = function (tag) { - var link = tag.link ? 'link="' + tag.link + '" ' : '', - rel = tag.rel ? 'rel="' + tag.rel + '" ' : '', - type = tag.type ? 'type="' + tag.type + '" ' : '', - href = tag.href ? 'href="' + tag.href + '" ' : '', - sizes = tag.sizes ? 'sizes="' + tag.sizes + '" ' : ''; + var link = tag.link ? 'link="' + tag.link + '" ' : ''; + var rel = tag.rel ? 'rel="' + tag.rel + '" ' : ''; + var type = tag.type ? 'type="' + tag.type + '" ' : ''; + var href = tag.href ? 'href="' + tag.href + '" ' : ''; + var sizes = tag.sizes ? 'sizes="' + tag.sizes + '" ' : ''; return '\n\t'; }; helpers.stringify = function (obj) { // Turns the incoming object into a JSON string - return JSON.stringify(obj).replace(/&/gm,"&").replace(//gm,">").replace(/"/g, '"'); + return JSON.stringify(obj).replace(/&/gm, '&').replace(//gm, '>').replace(/"/g, '"'); }; helpers.escape = function (str) { if (typeof utils !== 'undefined') { return utils.escapeHTML(str); - } else { - return require('../utils').escapeHTML(str); } + return require('../utils').escapeHTML(str); }; helpers.stripTags = function (str) { - if (typeof S !== 'undefined') { - return S(String(str)).stripTags().s; - } else { - var S = require('string'); - return S(String(str)).stripTags().s; + if (typeof window !== 'undefined' && window.S) { + return window.S(String(str)).stripTags().s; } + var S = require('string'); + return S(String(str)).stripTags().s; }; helpers.generateCategoryBackground = function (category) { @@ -103,19 +102,18 @@ helpers.generateChildrenCategories = function (category) { var html = ''; var relative_path = (typeof config !== 'undefined' ? config.relative_path : require('nconf').get('relative_path')); - if (!category || !category.children) { + if (!category || !category.children || !category.children.length) { return html; } category.children.forEach(function (child) { - if (!child) { - return; + if (child) { + var link = child.link ? child.link : (relative_path + '/category/' + child.slug); + html += '' + + '' + + '' + + '' + + '' + child.name + ' '; } - var link = child.link ? child.link : (relative_path + '/category/' + child.slug); - html += '' + - '' + - '' + - '' + - '' + child.name + ' '; }); html = html ? ('' + html + '') : html; return html; @@ -143,10 +141,6 @@ return style.join(' '); }; - helpers.getBookmarkFromIndex = function (topic) { - return (topic.index || 0) + 1; - }; - helpers.displayUserSearch = function (data, allowGuestUserSearching) { return data.loggedIn || allowGuestUserSearching === 'true'; }; @@ -163,18 +157,17 @@ return ''; } else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') { return ''; - } else { - return ''; } + return ''; }; helpers.spawnPrivilegeStates = function (member, privileges) { var states = []; - for(var priv in privileges) { + for (var priv in privileges) { if (privileges.hasOwnProperty(priv)) { states.push({ name: priv, - state: privileges[priv] + state: privileges[priv], }); } } @@ -190,74 +183,70 @@ helpers.renderTopicImage = function (topicObj) { if (topicObj.thumb) { return ''; - } else { - return ''; } + return ''; }; helpers.renderDigestAvatar = function (block) { if (block.teaser) { if (block.teaser.user.picture) { return ''; - } else { - return '
    ' + block.teaser.user['icon:text'] + '
    '; - } - } else { - if (block.user.picture) { - return ''; - } else { - return '
    ' + block.user['icon:text'] + '
    '; } + return '
    ' + block.teaser.user['icon:text'] + '
    '; } + if (block.user.picture) { + return ''; + } + return '
    ' + block.user['icon:text'] + '
    '; }; helpers.userAgentIcons = function (data) { var icons = ''; - switch(data.platform) { - case 'Linux': - icons += ''; - break; - case 'Microsoft Windows': - icons += ''; - break; - case 'Apple Mac': - icons += ''; - break; - case 'Android': - icons += ''; - break; - case 'iPad': - icons += ''; - break; - case 'iPod': // intentional fall-through - case 'iPhone': - icons += ''; - break; - default: - icons += ''; - break; + switch (data.platform) { + case 'Linux': + icons += ''; + break; + case 'Microsoft Windows': + icons += ''; + break; + case 'Apple Mac': + icons += ''; + break; + case 'Android': + icons += ''; + break; + case 'iPad': + icons += ''; + break; + case 'iPod': // intentional fall-through + case 'iPhone': + icons += ''; + break; + default: + icons += ''; + break; } - switch(data.browser) { - case 'Chrome': - icons += ''; - break; - case 'Firefox': - icons += ''; - break; - case 'Safari': - icons += ''; - break; - case 'IE': - icons += ''; - break; - case 'Edge': - icons += ''; - break; - default: - icons += ''; - break; + switch (data.browser) { + case 'Chrome': + icons += ''; + break; + case 'Firefox': + icons += ''; + break; + case 'Safari': + icons += ''; + break; + case 'IE': + icons += ''; + break; + case 'Edge': + icons += ''; + break; + default: + icons += ''; + break; } return icons; @@ -277,13 +266,13 @@ }); }; - // Use the define() function if we're in AMD land - if (typeof define === 'function' && define.amd) { - define('helpers', exports); + // export the class if we are in a Node-like system. + if (typeof module === 'object' && module.exports === exports) { + exports = module.exports/* = SemVer*/; + } else if (typeof define === 'function' && define.amd) { + // Use the define() function if we're in AMD land + define('helpers', exports); + } else if (typeof window === 'object') { + window.helpers = exports; } - -}( - typeof exports === 'object' ? exports : - typeof define === 'function' && define.amd ? {} : - helpers = {} -)); +}(typeof exports === 'object' ? exports : {})); diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js index 5f04baf59f..96a38e0df6 100644 --- a/public/src/modules/iconSelect.js +++ b/public/src/modules/iconSelect.js @@ -1,6 +1,5 @@ -"use strict"; +'use strict'; -/* globals define, bootbox, templates */ define('iconSelect', function () { var iconSelect = {}; @@ -17,7 +16,7 @@ define('iconSelect', function () { $('#icons .fa-icons .fa.' + selected).addClass('selected'); } catch (err) { selected = ''; - } + } } templates.parse('partials/fontawesome', {}, function (html) { @@ -25,45 +24,45 @@ define('iconSelect', function () { html.find('.fa-icons').prepend($('')); var picker = bootbox.dialog({ - onEscape: true, - backdrop: true, - show: false, - message: html, - title: 'Select an Icon', - buttons: { - noIcon: { - label: 'No Icon', - className: 'btn-default', - callback: function () { - el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '')); - el.val(''); - el.attr('value', ''); + onEscape: true, + backdrop: true, + show: false, + message: html, + title: 'Select an Icon', + buttons: { + noIcon: { + label: 'No Icon', + className: 'btn-default', + callback: function () { + el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '')); + el.val(''); + el.attr('value', ''); - onModified(el); - } + onModified(el); }, - success: { - label: 'Select', - className: 'btn-primary', - callback: function (confirm) { - var iconClass = $('.bootbox .selected').attr('class'); - var categoryIconClass = $('
    ').addClass(iconClass).removeClass('fa').removeClass('selected').attr('class'); + }, + success: { + label: 'Select', + className: 'btn-primary', + callback: function () { + var iconClass = $('.bootbox .selected').attr('class'); + var categoryIconClass = $('
    ').addClass(iconClass).removeClass('fa').removeClass('selected').attr('class'); - if (categoryIconClass) { - el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '') + categoryIconClass); - el.val(categoryIconClass); - el.attr('value', categoryIconClass); - } - - onModified(el); + if (categoryIconClass) { + el.attr('class', 'fa ' + (doubleSize ? 'fa-2x ' : '') + categoryIconClass); + el.val(categoryIconClass); + el.attr('value', categoryIconClass); } - } - } - }); + + onModified(el); + }, + }, + }, + }); picker.on('show.bs.modal', function () { - var modalEl = $(this), - searchEl = modalEl.find('input'); + var modalEl = $(this); + var searchEl = modalEl.find('input'); if (selected) { modalEl.find('.' + selected).addClass('selected'); @@ -72,10 +71,10 @@ define('iconSelect', function () { }).modal('show'); picker.on('shown.bs.modal', function () { - var modalEl = $(this), - searchEl = modalEl.find('input'), - icons = modalEl.find('.fa-icons i'), - submitEl = modalEl.find('button.btn-primary'); + var modalEl = $(this); + var searchEl = modalEl.find('input'); + var icons = modalEl.find('.fa-icons i'); + var submitEl = modalEl.find('button.btn-primary'); function changeSelection(newSelection) { modalEl.find('i.selected').removeClass('selected'); diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index b281a46fff..68c0359755 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -1,11 +1,8 @@ 'use strict'; -/* globals define, ajaxify, utils, config */ - define('navigator', ['forum/pagination', 'components'], function (pagination, components) { - var navigator = {}; var index = 1; var count = 0; @@ -78,7 +75,8 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co navigator.disable = function () { count = 0; index = 1; - navigator.selector = navigator.callback = null; + navigator.callback = null; + navigator.selector = null; $(window).off('scroll', navigator.update); toggle(false); @@ -116,7 +114,7 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co var scrollTop = $(window).scrollTop(); var windowHeight = $(window).height(); var documentHeight = $(document).height(); - var middleOfViewport = scrollTop + windowHeight / 2; + var middleOfViewport = scrollTop + (windowHeight / 2); var previousDistance = Number.MAX_VALUE; els.each(function () { var distanceToMiddle = Math.abs(middleOfViewport - $(this).offset().top); @@ -173,13 +171,13 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co navigator.scrollUp = function () { $('body,html').animate({ - scrollTop: $(window).scrollTop() - $(window).height() + scrollTop: $(window).scrollTop() - $(window).height(), }); }; navigator.scrollDown = function () { $('body,html').animate({ - scrollTop: $(window).scrollTop() + $(window).height() + scrollTop: $(window).scrollTop() + $(window).height(), }); }; @@ -266,7 +264,7 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co } $('html, body').animate({ - scrollTop: scrollTop + 'px' + scrollTop: scrollTop + 'px', }, duration, function () { if (done) { // Re-enable onScroll behaviour diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index f9972ca5a9..ecbfaadd1b 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, app, ajaxify, templates, Tinycon*/ define('notifications', ['sounds', 'translator', 'components'], function (sounds, translator, components) { var Notifications = {}; @@ -8,10 +7,10 @@ define('notifications', ['sounds', 'translator', 'components'], function (sounds var unreadNotifs = {}; Notifications.prepareDOM = function () { - var notifContainer = components.get('notifications'), - notifTrigger = notifContainer.children('a'), - notifList = components.get('notifications/list'), - notifIcon = components.get('notifications/icon'); + var notifContainer = components.get('notifications'); + var notifTrigger = notifContainer.children('a'); + var notifList = components.get('notifications/list'); + var notifIcon = components.get('notifications/icon'); notifTrigger .on('click', function (e) { @@ -71,7 +70,7 @@ define('notifications', ['sounds', 'translator', 'components'], function (sounds var payload = { alert_id: 'new_notif', title: '[[notifications:new_notification]]', - timeout: 2000 + timeout: 2000, }; if (notifData.path) { @@ -126,12 +125,12 @@ define('notifications', ['sounds', 'translator', 'components'], function (sounds }); translator.toggleTimeagoShorthand(); - for(var i = 0; i < notifs.length; ++i) { + for (var i = 0; i < notifs.length; i += 1) { notifs[i].timeago = $.timeago(new Date(parseInt(notifs[i].datetime, 10))); } translator.toggleTimeagoShorthand(); - templates.parse('partials/notifications_list', {notifications: notifs}, function (html) { + templates.parse('partials/notifications_list', { notifications: notifs }, function (html) { notifList.translateHtml(html); }); }); @@ -151,7 +150,7 @@ define('notifications', ['sounds', 'translator', 'components'], function (sounds var payload = { count: count, - updateFavicon: true + updateFavicon: true, }; $(window).trigger('action:notification.updateCount', payload); diff --git a/public/src/modules/pictureCropper.js b/public/src/modules/pictureCropper.js index 60dd073532..bbe0a76735 100644 --- a/public/src/modules/pictureCropper.js +++ b/public/src/modules/pictureCropper.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define, socket, app, templates */ define('pictureCropper', ['translator', 'cropper'], function (translator, cropper) { var module = {}; @@ -13,7 +12,7 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe title: data.title || '[[global:upload_file]]', description: data.description || '', button: data.button || '[[global:upload]]', - accept: data.accept ? data.accept.replace(/,/g, ', ') : '' + accept: data.accept ? data.accept.replace(/,/g, ', ') : '', }, function (uploadModal) { uploadModal = $(uploadModal); @@ -34,7 +33,7 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe module.handleImageCrop = function (data, callback) { $('#crop-picture-modal').remove(); templates.parse('modals/crop_picture', { - url: data.url + url: data.url, }, function (cropperHtml) { translator.translate(cropperHtml, function (translated) { var cropperModal = $(translated); @@ -43,17 +42,18 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe var img = document.getElementById('cropped-image'); var cropperTool = new cropper.default(img, { aspectRatio: data.aspectRatio, + autoCropArea: 1, viewMode: 1, cropmove: function () { if (data.restrictImageDimension) { if (cropperTool.cropBoxData.width > data.imageDimension) { cropperTool.setCropBoxData({ - width: data.imageDimension + width: data.imageDimension, }); } if (cropperTool.cropBoxData.height > data.imageDimension) { cropperTool.setCropBoxData({ - height: data.imageDimension + height: data.imageDimension, }); } } @@ -64,20 +64,24 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe var dimension = (origDimension > data.imageDimension) ? data.imageDimension : origDimension; cropperTool.setCropBoxData({ width: dimension, - height: dimension + height: dimension, }); } cropperModal.find('.rotate').on('click', function () { - var degrees = this.getAttribute("data-degrees"); + var degrees = this.getAttribute('data-degrees'); cropperTool.rotate(degrees); }); cropperModal.find('.flip').on('click', function () { - var option = this.getAttribute("data-option"); - var method = this.getAttribute("data-method"); - method === 'scaleX' ? cropperTool.scaleX(option) : cropperTool.scaleY(option); - this.setAttribute("data-option", option * -1); + var option = this.getAttribute('data-option'); + var method = this.getAttribute('data-method'); + if (method === 'scaleX') { + cropperTool.scaleX(option); + } else { + cropperTool.scaleY(option); + } + this.setAttribute('data-option', option * -1); }); cropperModal.find('.reset').on('click', function () { @@ -93,7 +97,7 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe var socketData = {}; socketData[data.paramName] = data.paramValue; - socketData['imageData'] = imageData; + socketData.imageData = imageData; socket.emit(data.socketMethod, socketData, function (err, imageData) { if (err) { @@ -117,10 +121,10 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe autoCropArea: 1, ready: function () { cropperModal.find('.crop-btn').trigger('click'); - } + }, }); }); - } + }, }); }); }); @@ -145,7 +149,7 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe var imageUrl; var imageType = file.type; - reader.addEventListener("load", function () { + reader.addEventListener('load', function () { imageUrl = reader.result; data.uploadModal.modal('hide'); @@ -159,7 +163,7 @@ define('pictureCropper', ['translator', 'cropper'], function (translator, croppe restrictImageDimension: data.restrictImageDimension, imageDimension: data.imageDimension, paramName: data.paramName, - paramValue: data.paramValue + paramValue: data.paramValue, }, callback); }, false); diff --git a/public/src/modules/postSelect.js b/public/src/modules/postSelect.js index 6001488708..5dae2995ea 100644 --- a/public/src/modules/postSelect.js +++ b/public/src/modules/postSelect.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define*/ define('postSelect', ['components'], function (components) { var PostSelect = {}; @@ -25,7 +24,7 @@ define('postSelect', ['components'], function (components) { if (newPid) { var index = PostSelect.pids.indexOf(newPid); - if(index === -1) { + if (index === -1) { PostSelect.pids.push(newPid); post.toggleClass('bg-success', true); } else { @@ -34,7 +33,7 @@ define('postSelect', ['components'], function (components) { } if (PostSelect.pids.length) { - PostSelect.pids.sort(function (a,b) { return a - b; }); + PostSelect.pids.sort(function (a, b) { return a - b; }); } callback(); } @@ -54,6 +53,5 @@ define('postSelect', ['components'], function (components) { }; - return PostSelect; -}); \ No newline at end of file +}); diff --git a/public/src/modules/scrollStop.js b/public/src/modules/scrollStop.js index 13d722402c..82d2df4de8 100644 --- a/public/src/modules/scrollStop.js +++ b/public/src/modules/scrollStop.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals console, define */ /* The point of this library is to enhance(tm) a textarea so that if scrolled, @@ -18,7 +17,7 @@ define('scrollStop', function () { var scrollTop = this.scrollTop; var scrollHeight = this.scrollHeight; var elementHeight = this.getBoundingClientRect().height; - + if ( (e.originalEvent.deltaY < 0 && scrollTop === 0) || // scroll up (e.originalEvent.deltaY > 0 && (elementHeight + scrollTop) >= scrollHeight) // scroll down @@ -29,4 +28,4 @@ define('scrollStop', function () { }; return Module; -}); \ No newline at end of file +}); diff --git a/public/src/modules/search.js b/public/src/modules/search.js index 990c9dec97..1401bf8619 100644 --- a/public/src/modules/search.js +++ b/public/src/modules/search.js @@ -1,10 +1,9 @@ -"use strict"; -/* globals socket, ajaxify, app, define, config */ +'use strict'; + define('search', ['navigator', 'translator'], function (nav, translator) { - var Search = { - current: {} + current: {}, }; Search.query = function (data, callback) { @@ -18,7 +17,7 @@ define('search', ['navigator', 'translator'], function (nav, translator) { try { term = encodeURIComponent(term); - } catch(e) { + } catch (e) { return app.alertError('[[error:invalid-search-term]]'); } @@ -35,11 +34,11 @@ define('search', ['navigator', 'translator'], function (nav, translator) { }; function createQueryString(data) { - var searchIn = data['in'] || 'titlesposts'; + var searchIn = data.in || 'titlesposts'; var postedBy = data.by || ''; var query = { term: data.term, - 'in': searchIn + in: searchIn, }; if (postedBy && (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts')) { @@ -81,15 +80,15 @@ define('search', ['navigator', 'translator'], function (nav, translator) { Search.getSearchPreferences = function () { try { return JSON.parse(localStorage.getItem('search-preferences') || '{}'); - } catch(e) { + } catch (e) { return {}; } }; - Search.queryTopic = function (tid, term, callback) { + Search.queryTopic = function (tid, term) { socket.emit('topics.search', { tid: tid, - term: term + term: term, }, function (err, pids) { if (err) { return app.alertError(err.message); @@ -102,7 +101,7 @@ define('search', ['navigator', 'translator'], function (nav, translator) { return a - b; }), tid: tid, - term: term + term: term, }; Search.checkPagePresence(tid, function () { @@ -121,7 +120,7 @@ define('search', ['navigator', 'translator'], function (nav, translator) { }; Search.topicDOM = { - active: false + active: false, }; Search.topicDOM.prev = function () { @@ -144,7 +143,7 @@ define('search', ['navigator', 'translator'], function (nav, translator) { var data = { pid: Search.current.results[index], tid: Search.current.tid, - topicPostSort: config.topicPostSort + topicPostSort: config.topicPostSort, }; socket.emit('posts.getPidIndex', data, function (err, postIndex) { if (err) { diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 090c83e2d0..ecd99a9521 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -1,8 +1,7 @@ -"use strict"; -/*global define, app, socket*/ +'use strict'; + define('settings', function () { - var DEFAULT_PLUGINS = [ 'settings/checkbox', 'settings/number', @@ -10,13 +9,13 @@ define('settings', function () { 'settings/select', 'settings/array', 'settings/key', - 'settings/object' + 'settings/object', ]; - var Settings, - onReady = [], - waitingJobs = 0, - helper; + var Settings; + var onReady = []; + var waitingJobs = 0; + var helper; /** Returns the hook of given name that matches the given type or element. @@ -24,21 +23,21 @@ define('settings', function () { @param name The name of the hook. */ function getHook(type, name) { - var hook, plugin; + var hook; + var plugin; if (typeof type !== 'string') { type = $(type); type = type.data('type') || type.attr('type') || type.prop('tagName'); } plugin = Settings.plugins[type.toLowerCase()]; if (plugin == null) { - return void 0; + return; } hook = plugin[name]; if (typeof hook === 'function') { return hook; - } else { - return null; } + return null; } helper = { @@ -48,9 +47,8 @@ define('settings', function () { deepClone: function (obj) { if (typeof obj === 'object') { return JSON.parse(JSON.stringify(obj)); - } else { - return obj; } + return obj; }, /** Creates a new Element with given data. @@ -99,7 +97,8 @@ define('settings', function () { @returns JQuery The created element. */ createElementOfType: function (type, tagName, data) { - var element, hook = getHook(type, 'create'); + var element; + var hook = getHook(type, 'create'); if (hook != null) { element = $(hook.call(Settings, type, tagName, data)); } else { @@ -127,12 +126,16 @@ define('settings', function () { if (!trim && empty) { return array; } - for (var i = 0; i < array.length; i++) { + for (var i = 0; i < array.length; i += 1) { var value = array[i]; if (trim) { - value = value === true ? 1 : value === false ? 0 : typeof value.trim === 'function' ? value.trim() : value; + if (value === !!value) { + value = +value; + } else if (value && typeof value.trim === 'function') { + value = value.trim(); + } } - if (empty || (value != null ? value.length : void 0)) { + if (empty || (value != null && value.length)) { cleaned.push(value); } } @@ -151,29 +154,26 @@ define('settings', function () { @returns Object The value of the element. */ readValue: function (element) { - var empty = !helper.isFalse(element.data('empty')), - trim = !helper.isFalse(element.data('trim')), - split = element.data('split'), - hook = getHook(element, 'get'), - value; + var empty = !helper.isFalse(element.data('empty')); + var trim = !helper.isFalse(element.data('trim')); + var split = element.data('split'); + var hook = getHook(element, 'get'); + var value; if (hook != null) { return hook.call(Settings, element, trim, empty); } if (split != null) { empty = helper.isTrue(element.data('empty')); // default empty-value is false for arrays value = element.val(); - var array = (value != null ? value.split(split || ',') : void 0) || []; + var array = (value != null && value.split(split || ',')) || []; return helper.cleanArray(array, trim, empty); - } else { - value = element.val(); - if (trim && value != null && typeof value.trim === 'function') { - value = value.trim(); - } - if (empty || value !== void 0 && (value == null || value.length !== 0)) { - return value; - } else { - return void 0; - } + } + value = element.val(); + if (trim && value != null && typeof value.trim === 'function') { + value = value.trim(); + } + if (empty || (value !== undefined && (value == null || value.length !== 0))) { + return value; } }, /** @@ -183,8 +183,8 @@ define('settings', function () { @param value The value to set. */ fillField: function (element, value) { - var hook = getHook(element, 'set'), - trim = element.data('trim'); + var hook = getHook(element, 'set'); + var trim = element.data('trim'); trim = trim !== 'false' && +trim !== 0; if (hook != null) { return hook.call(Settings, element, value, trim); @@ -207,7 +207,7 @@ define('settings', function () { } else { value = ''; } - if (value !== void 0) { + if (value !== undefined) { element.val(value); } }, @@ -218,13 +218,13 @@ define('settings', function () { initFields: function (wrapper) { $('[data-key]', wrapper).each(function (ignored, field) { field = $(field); - var hook = getHook(field, 'init'), - keyParts = field.data('key').split('.'), - value = Settings.get(); + var hook = getHook(field, 'init'); + var keyParts = field.data('key').split('.'); + var value = Settings.get(); if (hook != null) { hook.call(Settings, field); } - for (var i = 0; i < keyParts.length; i++) { + for (var i = 0; i < keyParts.length; i += 1) { var part = keyParts[i]; if (part && value != null) { value = value[part]; @@ -238,7 +238,8 @@ define('settings', function () { @param amount The amount of jobs to register. */ registerReadyJobs: function (amount) { - return waitingJobs += amount; + waitingJobs += amount; + return waitingJobs; }, /** Decreases the amount of jobs before settings are ready by given amount or 1. @@ -252,7 +253,7 @@ define('settings', function () { if (waitingJobs > 0) { waitingJobs -= amount; if (waitingJobs <= 0) { - for (var i = 0; i < onReady.length; i++) { + for (var i = 0; i < onReady.length; i += 1) { onReady[i](); } onReady = []; @@ -284,22 +285,22 @@ define('settings', function () { } socket.emit('admin.settings.set', { hash: hash, - values: settings + values: settings, }, function (err) { if (notify) { if (err) { app.alert({ title: 'Settings Not Saved', type: 'danger', - message: "NodeBB failed to save the settings.", - timeout: 5000 + message: 'NodeBB failed to save the settings.', + timeout: 5000, }); } else { app.alert({ title: 'Settings Saved', type: 'success', - message: "Settings have been successfully saved", - timeout: 2500 + message: 'Settings have been successfully saved', + timeout: 2500, }); } } @@ -317,7 +318,7 @@ define('settings', function () { settings._ = JSON.parse(settings._); } catch (_error) {} Settings.cfg = settings; - } + }, }; @@ -331,7 +332,7 @@ define('settings', function () { @returns Object The settings. */ get: function () { - if (Settings.cfg != null && Settings.cfg._ !== void 0) { + if (Settings.cfg != null && Settings.cfg._ !== undefined) { return Settings.cfg._; } return Settings.cfg; @@ -350,7 +351,7 @@ define('settings', function () { if (typeof service.use === 'function') { service.use.call(Settings); } - for (var i = 0; i < types.length; i++) { + for (var i = 0; i < types.length; i += 1) { var type = types[i].toLowerCase(); if (Settings.plugins[type] == null) { Settings.plugins[type] = service; @@ -383,7 +384,7 @@ define('settings', function () { */ sync: function (hash, wrapper, callback) { socket.emit('admin.settings.get', { - hash: hash + hash: hash, }, function (err, values) { if (err) { if (typeof callback === 'function') { @@ -408,19 +409,19 @@ define('settings', function () { @param notify Whether to send notification when settings got saved. */ persist: function (hash, wrapper, callback, notify) { - var notSaved = [], - fields = $('[data-key]', wrapper || 'form').toArray(); + var notSaved = []; + var fields = $('[data-key]', wrapper || 'form').toArray(); if (notify == null) { notify = true; } - for (var i = 0; i < fields.length; i++) { - var field = $(fields[i]), - value = helper.readValue(field), - parentCfg = Settings.get(), - keyParts = field.data('key').split('.'), - lastKey = keyParts[keyParts.length - 1]; + for (var i = 0; i < fields.length; i += 1) { + var field = $(fields[i]); + var value = helper.readValue(field); + var parentCfg = Settings.get(); + var keyParts = field.data('key').split('.'); + var lastKey = keyParts[keyParts.length - 1]; if (keyParts.length > 1) { - for (var j = 0; j < keyParts.length - 1; j++) { + for (var j = 0; j < keyParts.length - 1; j += 1) { var part = keyParts[j]; if (part && parentCfg != null) { parentCfg = parentCfg[part]; @@ -442,7 +443,7 @@ define('settings', function () { title: 'Attributes Not Saved', message: "'" + (notSaved.join(', ')) + "' could not be saved. Please contact the plugin-author!", type: 'danger', - timeout: 5000 + timeout: 5000, }); } helper.persistSettings(hash, Settings.cfg, notify, callback); @@ -450,14 +451,14 @@ define('settings', function () { load: function (hash, formEl, callback) { callback = callback || function () {}; socket.emit('admin.settings.get', { - hash: hash + hash: hash, }, function (err, values) { if (err) { return callback(err); } // Parse all values. If they are json, return json - for(var key in values) { + for (var key in values) { if (values.hasOwnProperty(key)) { try { values[key] = JSON.parse(values[key]); @@ -502,42 +503,39 @@ define('settings', function () { socket.emit('admin.settings.set', { hash: hash, - values: values + values: values, }, function (err) { // Remove unsaved flag to re-enable ajaxify app.flags._unsaved = false; if (typeof callback === 'function') { callback(err); + } else if (err) { + app.alert({ + title: 'Error while saving settings', + type: 'error', + timeout: 2500, + }); } else { - if (err) { - app.alert({ - title: 'Error while saving settings', - type: 'error', - timeout: 2500 - }); - } else { - app.alert({ - title: 'Settings Saved', - type: 'success', - timeout: 2500 - }); - } + app.alert({ + title: 'Settings Saved', + type: 'success', + timeout: 2500, + }); } }); } - } + }, }; helper.registerReadyJobs(1); require(DEFAULT_PLUGINS, function () { - for (var i = 0; i < arguments.length; i++) { + for (var i = 0; i < arguments.length; i += 1) { Settings.registerPlugin(arguments[i]); } helper.beforeReadyJobsDecreased(); }); return Settings; - }); diff --git a/public/src/modules/settings/array.js b/public/src/modules/settings/array.js index fd94ed8226..9b51aee582 100644 --- a/public/src/modules/settings/array.js +++ b/public/src/modules/settings/array.js @@ -1,8 +1,8 @@ -define('settings/array', function () { +'use strict'; - var Settings = null, - SettingsArray, - helper = null; +define('settings/array', function () { + var SettingsArray; + var helper = null; /** Creates a new button that removes itself and the given elements on click. @@ -12,8 +12,8 @@ define('settings/array', function () { */ function createRemoveButton(elements) { var rm = $(helper.createElement('button', { - "class": 'btn btn-xs btn-primary remove', - title: 'Remove Item' + class: 'btn btn-xs btn-primary remove', + title: 'Remove Item', }, '-')); rm.click(function (event) { event.preventDefault(); @@ -41,23 +41,25 @@ define('settings/array', function () { */ function addArrayChildElement(field, key, attributes, value, separator, insertCb) { attributes = helper.deepClone(attributes); - var type = attributes['data-type'] || attributes.type || 'text', - element = $(helper.createElementOfType(type, attributes.tagName, attributes)); + var type = attributes['data-type'] || attributes.type || 'text'; + var element = $(helper.createElementOfType(type, attributes.tagName, attributes)); element.attr('data-parent', '_' + key); delete attributes['data-type']; - delete attributes['tagName']; + delete attributes.tagName; for (var name in attributes) { - var val = attributes[name]; - if (name.search('data-') === 0) { - element.data(name.substring(5), val); - } else if (name.search('prop-') === 0) { - element.prop(name.substring(5), val); - } else { - element.attr(name, val); + if (attributes.hasOwnProperty(name)) { + var val = attributes[name]; + if (name.search('data-') === 0) { + element.data(name.substring(5), val); + } else if (name.search('prop-') === 0) { + element.prop(name.substring(5), val); + } else { + element.attr(name, val); + } } } helper.fillField(element, value); - if ($("[data-parent=\"_" + key + "\"]", field).length) { + if ($('[data-parent="_' + key + '"]', field).length) { insertCb(separator); } insertCb(element); @@ -72,12 +74,12 @@ define('settings/array', function () { @param separator The separator to forward to {@link addArrayChildElement}. */ function addAddButton(element, key, attributes, separator) { - var addSpace = $(document.createTextNode(' ')), - newValue = element.data('new') || '', - add = $(helper.createElement('button', { - "class": 'btn btn-sm btn-primary add', - title: 'Expand Array' - }, '+')); + var addSpace = $(document.createTextNode(' ')); + var newValue = element.data('new') || ''; + var add = $(helper.createElement('button', { + class: 'btn btn-sm btn-primary add', + title: 'Expand Array', + }, '+')); add.click(function (event) { event.preventDefault(); addArrayChildElement(element, key, attributes, newValue, separator.clone(), function (el) { @@ -92,15 +94,15 @@ define('settings/array', function () { SettingsArray = { types: ['array', 'div'], use: function () { - helper = (Settings = this).helper; + helper = this.helper; }, create: function (ignored, tagName) { return helper.createElement(tagName || 'div'); }, set: function (element, value) { - var attributes = element.data('attributes'), - key = element.data('key') || element.data('parent'), - separator = element.data('split') || ', '; + var attributes = element.data('attributes'); + var key = element.data('key') || element.data('parent'); + var separator = element.data('split') || ', '; separator = (function () { try { return $(separator); @@ -115,7 +117,7 @@ define('settings/array', function () { if (!(value instanceof Array)) { value = []; } - for (var i = 0; i < value.length; i++) { + for (var i = 0; i < value.length; i += 1) { addArrayChildElement(element, key, attributes, value[i], separator.clone(), function (el) { element.append(el); }); @@ -123,25 +125,22 @@ define('settings/array', function () { addAddButton(element, key, attributes, separator); }, get: function (element, trim, empty) { - var key = element.data('key') || element.data('parent'), - children = $("[data-parent=\"_" + key + "\"]", element), - values = []; + var key = element.data('key') || element.data('parent'); + var children = $('[data-parent="_' + key + '"]', element); + var values = []; children.each(function (i, child) { child = $(child); - var val = helper.readValue(child), - empty = helper.isTrue(child.data('empty')); - if (empty || val !== void 0 && (val == null || val.length !== 0)) { + var val = helper.readValue(child); + var empty = helper.isTrue(child.data('empty')); + if (empty || (val !== undefined && (val == null || val.length !== 0))) { return values.push(val); } }); if (empty || values.length) { return values; - } else { - return void 0; } - } + }, }; return SettingsArray; - }); diff --git a/public/src/modules/settings/checkbox.js b/public/src/modules/settings/checkbox.js index 865e89c0f3..d64212d4e0 100644 --- a/public/src/modules/settings/checkbox.js +++ b/public/src/modules/settings/checkbox.js @@ -1,7 +1,8 @@ -define('settings/checkbox', function () { +'use strict'; - var Settings = null, - SettingsCheckbox; +define('settings/checkbox', function () { + var Settings = null; + var SettingsCheckbox; SettingsCheckbox = { types: ['checkbox'], @@ -10,7 +11,7 @@ define('settings/checkbox', function () { }, create: function () { return Settings.helper.createElement('input', { - type: 'checkbox' + type: 'checkbox', }); }, set: function (element, value) { @@ -20,18 +21,20 @@ define('settings/checkbox', function () { get: function (element, trim, empty) { var value = element.prop('checked'); if (value == null) { - return void 0; + return; } if (!empty) { - return value || void 0; + if (value) { + return value; + } + return; } if (trim) { return value ? 1 : 0; } return value; - } + }, }; return SettingsCheckbox; - }); diff --git a/public/src/modules/settings/key.js b/public/src/modules/settings/key.js index c5cac01103..df3ade0a32 100644 --- a/public/src/modules/settings/key.js +++ b/public/src/modules/settings/key.js @@ -1,31 +1,31 @@ -define('settings/key', function () { +'use strict'; - var Settings = null, - SettingsKey, - helper = null, - lastKey = null, - oldKey = null, - keyMap = Object.freeze({ - 0: '', - 8: 'Backspace', - 9: 'Tab', - 13: 'Enter', - 27: 'Escape', - 32: 'Space', - 37: 'Left', - 38: 'Up', - 39: 'Right', - 40: 'Down', - 45: 'Insert', - 46: 'Delete', - 187: '=', - 189: '-', - 190: '.', - 191: '/', - 219: '[', - 220: '\\', - 221: ']' - }); +define('settings/key', function () { + var SettingsKey; + var helper = null; + var lastKey = null; + var oldKey = null; + var keyMap = Object.freeze({ + 0: '', + 8: 'Backspace', + 9: 'Tab', + 13: 'Enter', + 27: 'Escape', + 32: 'Space', + 37: 'Left', + 38: 'Up', + 39: 'Right', + 40: 'Down', + 45: 'Insert', + 46: 'Delete', + 187: '=', + 189: '-', + 190: '.', + 191: '/', + 219: '[', + 220: '\\', + 221: ']', + }); function Key() { this.c = false; @@ -42,9 +42,9 @@ define('settings/key', function () { @returns Key | null The Key-Object the focused element should be set to. */ function getKey(event) { - var anyModChange = event.ctrlKey !== lastKey.c || event.altKey !== lastKey.a || event.shiftKey !== lastKey.s || event.metaKey !== lastKey.m, - modChange = event.ctrlKey + event.altKey + event.shiftKey + event.metaKey - lastKey.c - lastKey.a - lastKey.s - lastKey.m, - key = new Key(); + var anyModChange = event.ctrlKey !== lastKey.c || event.altKey !== lastKey.a || event.shiftKey !== lastKey.s || event.metaKey !== lastKey.m; + var modChange = event.ctrlKey + event.altKey + event.shiftKey + event.metaKey - lastKey.c - lastKey.a - lastKey.s - lastKey.m; + var key = new Key(); key.c = event.ctrlKey; key.a = event.altKey; key.s = event.shiftKey; @@ -60,7 +60,8 @@ define('settings/key', function () { key.code = event.which; key.char = convertKeyCodeToChar(key.code); } - return oldKey = key; + oldKey = key; + return key; } /** @@ -75,10 +76,9 @@ define('settings/key', function () { } else if (code >= 48 && code <= 90) { return String.fromCharCode(code).toUpperCase(); } else if (code >= 112 && code <= 123) { - return "F" + (code - 111); - } else { - return keyMap[code] || ("#" + code); + return 'F' + (code - 111); } + return keyMap[code] || ('#' + code); } /** @@ -97,9 +97,8 @@ define('settings/key', function () { if (!key.char) { if (human) { return 'Enter a key'; - } else { - return ''; } + return ''; } if (!separator || /CtrlAShifMea#/.test(separator)) { separator = human ? ' + ' : '+'; @@ -116,7 +115,15 @@ define('settings/key', function () { if (key.m) { str += (short ? 'M' : 'Meta') + separator; } - return str + (human ? key.char : key.code ? '#' + key.code : ''); + + var out; + if (human) { + out = key.char; + } else if (key.code) { + out = '#' + key.code || ''; + } + + return str + out; } /** @@ -128,10 +135,10 @@ define('settings/key', function () { if (str instanceof Key) { return str; } - var key = new Key(), - sep = /([^CtrlAShifMea#\d]+)(?:#|\d)/.exec(str), - parts = sep != null ? str.split(sep[1]) : [str]; - for (var i = 0; i < parts.length; i++) { + var key = new Key(); + var sep = /([^CtrlAShifMea#\d]+)(?:#|\d)/.exec(str); + var parts = sep != null ? str.split(sep[1]) : [str]; + for (var i = 0; i < parts.length; i += 1) { var part = parts[i]; switch (part) { case 'C': @@ -174,7 +181,7 @@ define('settings/key', function () { SettingsKey = { types: ['key'], use: function () { - helper = (Settings = this).helper; + helper = this.helper; }, init: function (element) { element.focus(function () { @@ -199,23 +206,18 @@ define('settings/key', function () { element.val(getKeyString(key, true, false, ' + ')); }, get: function (element, trim, empty) { - var key = element.data('keyData'), - separator = element.data('split') || element.data('separator') || '+', - short = !helper.isFalse(element.data('short')); + var key = element.data('keyData'); + var separator = element.data('split') || element.data('separator') || '+'; + var short = !helper.isFalse(element.data('short')); if (trim) { if (empty || (key != null && key.char)) { return getKeyString(key, false, short, separator); - } else { - return void 0; } } else if (empty || (key != null && key.code)) { return key; - } else { - return void 0; } - } + }, }; return SettingsKey; - }); diff --git a/public/src/modules/settings/number.js b/public/src/modules/settings/number.js index ed96008038..12ff231076 100644 --- a/public/src/modules/settings/number.js +++ b/public/src/modules/settings/number.js @@ -1,14 +1,17 @@ -define('settings/number', function () { +'use strict'; +define('settings/number', function () { return { types: ['number'], get: function (element, trim, empty) { var value = element.val(); if (!empty) { - return value ? +value : void 0; + if (value) { + return +value; + } + return; } return value ? +value : 0; - } + }, }; - }); diff --git a/public/src/modules/settings/object.js b/public/src/modules/settings/object.js index 05971d6d73..7e79e54cc3 100644 --- a/public/src/modules/settings/object.js +++ b/public/src/modules/settings/object.js @@ -1,8 +1,8 @@ -define('settings/object', function () { +'use strict'; - var Settings = null, - SettingsObject, - helper = null; +define('settings/object', function () { + var SettingsObject; + var helper = null; /** Creates a new child-element of given property with given data and calls given callback with elements to add. @@ -15,26 +15,29 @@ define('settings/object', function () { @param insertCb The callback to insert the elements. */ function addObjectPropertyElement(field, key, attributes, prop, value, separator, insertCb) { - var prepend = attributes['data-prepend'], - append = attributes['data-append'], - type, element; + var prepend = attributes['data-prepend']; + var append = attributes['data-append']; + var type; + var element; delete attributes['data-prepend']; delete attributes['data-append']; attributes = helper.deepClone(attributes); - type = attributes['data-type'] || attributes.type || 'text', + type = attributes['data-type'] || attributes.type || 'text'; element = $(helper.createElementOfType(type, attributes.tagName, attributes)); element.attr('data-parent', '_' + key); element.attr('data-prop', prop); delete attributes['data-type']; - delete attributes['tagName']; + delete attributes.tagName; for (var name in attributes) { - var val = attributes[name]; - if (name.search('data-') === 0) { - element.data(name.substring(5), val); - } else if (name.search('prop-') === 0) { - element.prop(name.substring(5), val); - } else { - element.attr(name, val); + if (attributes.hasOwnProperty(name)) { + var val = attributes[name]; + if (name.search('data-') === 0) { + element.data(name.substring(5), val); + } else if (name.search('prop-') === 0) { + element.prop(name.substring(5), val); + } else { + element.attr(name, val); + } } } helper.fillField(element, value); @@ -53,16 +56,18 @@ define('settings/object', function () { SettingsObject = { types: ['object'], use: function () { - helper = (Settings = this).helper; + helper = this.helper; }, create: function (ignored, tagName) { return helper.createElement(tagName || 'div'); }, set: function (element, value) { - var properties = element.data('attributes') || element.data('properties'), - key = element.data('key') || element.data('parent'), - separator = element.data('split') || ', ', - propertyIndex, propertyName, attributes; + var properties = element.data('attributes') || element.data('properties'); + var key = element.data('key') || element.data('parent'); + var separator = element.data('split') || ', '; + var propertyIndex; + var propertyName; + var attributes; separator = (function () { try { return $(separator); @@ -76,41 +81,41 @@ define('settings/object', function () { } if (Array.isArray(properties)) { for (propertyIndex in properties) { - attributes = properties[propertyIndex]; - if (typeof attributes !== 'object') { - attributes = {}; + if (properties.hasOwnProperty(propertyIndex)) { + attributes = properties[propertyIndex]; + if (typeof attributes !== 'object') { + attributes = {}; + } + propertyName = attributes['data-prop'] || attributes['data-property'] || propertyIndex; + if (value[propertyName] === undefined && attributes['data-new'] !== undefined) { + value[propertyName] = attributes['data-new']; + } + addObjectPropertyElement(element, key, attributes, propertyName, value[propertyName], separator.clone(), function (el) { + element.append(el); + }); } - propertyName = attributes['data-prop'] || attributes['data-property'] || propertyIndex; - if (value[propertyName] === void 0 && attributes['data-new'] !== void 0) { - value[propertyName] = attributes['data-new']; - } - addObjectPropertyElement(element, key, attributes, propertyName, value[propertyName], separator.clone(), function (el) { - element.append(el); - }); } } }, get: function (element, trim, empty) { - var key = element.data('key') || element.data('parent'), - properties = $('[data-parent="_' + key + '"]', element), - value = {}; + var key = element.data('key') || element.data('parent'); + var properties = $('[data-parent="_' + key + '"]', element); + var value = {}; properties.each(function (i, property) { property = $(property); - var val = helper.readValue(property), - prop = property.data('prop'), - empty = helper.isTrue(property.data('empty')); - if (empty || val !== void 0 && (val == null || val.length !== 0)) { - return value[prop] = val; + var val = helper.readValue(property); + var prop = property.data('prop'); + var empty = helper.isTrue(property.data('empty')); + if (empty || (val !== undefined && (val == null || val.length !== 0))) { + value[prop] = val; + return val; } }); if (empty || Object.keys(value).length) { return value; - } else { - return void 0; } - } + }, }; return SettingsObject; - }); diff --git a/public/src/modules/settings/select.js b/public/src/modules/settings/select.js index 5e62b27226..1b28774871 100644 --- a/public/src/modules/settings/select.js +++ b/public/src/modules/settings/select.js @@ -1,12 +1,13 @@ -define('settings/select', function () { +'use strict'; - var Settings = null, - SettingsSelect; +define('settings/select', function () { + var Settings = null; + var SettingsSelect; function addOptions(element, options) { - for (var i = 0; i < options.length; i++) { - var optionData = options[i], - value = optionData.text || optionData.value; + for (var i = 0; i < options.length; i += 1) { + var optionData = options[i]; + var value = optionData.text || optionData.value; delete optionData.text; element.append($(Settings.helper.createElement('option', optionData)).text(value)); } @@ -38,12 +39,9 @@ define('settings/select', function () { var value = element.val(); if (empty || value) { return value; - } else { - return void 0; } - } + }, }; return SettingsSelect; - }); diff --git a/public/src/modules/settings/textarea.js b/public/src/modules/settings/textarea.js index 8f1bcd90ca..cc36e90762 100644 --- a/public/src/modules/settings/textarea.js +++ b/public/src/modules/settings/textarea.js @@ -1,7 +1,8 @@ -define('settings/textarea', function () { +'use strict'; - var Settings = null, - SettingsArea; +define('settings/textarea', function () { + var Settings = null; + var SettingsArea; SettingsArea = { types: ['textarea'], @@ -20,16 +21,17 @@ define('settings/textarea', function () { get: function (element, trim, empty) { var value = element.val(); if (trim) { - value = value == null ? void 0 : value.trim(); + if (value == null) { + value = undefined; + } else { + value = value.trim(); + } } if (empty || value) { return value; - } else { - return void 0; } - } + }, }; return SettingsArea; - }); diff --git a/public/src/modules/share.js b/public/src/modules/share.js index ec850ed1c9..fe45f26d0f 100644 --- a/public/src/modules/share.js +++ b/public/src/modules/share.js @@ -1,13 +1,10 @@ 'use strict'; -/* globals define, config */ define('share', function () { - var module = {}; module.addShareHandlers = function (name) { - var baseUrl = window.location.protocol + '//' + window.location.host; function openShare(url, urlToPost, width, height) { @@ -16,7 +13,6 @@ define('share', function () { } $('#content').off('shown.bs.dropdown', '.share-dropdown').on('shown.bs.dropdown', '.share-dropdown', function () { - var postLink = $(this).find('.post-link'); postLink.val(baseUrl + getPostUrl($(this))); @@ -43,7 +39,7 @@ define('share', function () { return openShare('https://plus.google.com/share?url=', getPostUrl($(this)), 500, 570); }); - $(window).trigger('action:share.addHandlers', {openShare: openShare}); + $(window).trigger('action:share.addHandlers', { openShare: openShare }); }; function addHandler(selector, callback) { diff --git a/public/src/modules/sort.js b/public/src/modules/sort.js index c9e80020af..8242df566b 100644 --- a/public/src/modules/sort.js +++ b/public/src/modules/sort.js @@ -1,5 +1,5 @@ 'use strict'; -/* globals define, config, socket, app, ajaxify, templates */ + define('sort', ['components'], function (components) { var module = {}; diff --git a/public/src/modules/sounds.js b/public/src/modules/sounds.js index 26d64079ca..e81ee889f3 100644 --- a/public/src/modules/sounds.js +++ b/public/src/modules/sounds.js @@ -1,5 +1,5 @@ -"use strict"; -/* global app, define, socket, config */ +'use strict'; + define('sounds', function () { var Sounds = {}; @@ -31,7 +31,7 @@ define('sounds', function () { if (fileMap) { outstanding -= 1; } else { - $.getJSON(config.relative_path + '/assets/sounds/fileMap.json', function (map) { + $.getJSON(config.relative_path + '/assets/sounds/fileMap.json', function (map) { fileMap = map; after(); }); @@ -49,9 +49,10 @@ define('sounds', function () { if (!fileMap[soundName]) { return; } - var audio = cache[soundName] = cache[soundName] || new Audio(config.relative_path + '/assets/sounds/' + fileMap[soundName]); + var audio = cache[soundName] || new Audio(config.relative_path + '/assets/sounds/' + fileMap[soundName]); + cache[soundName] = audio; audio.pause(); - audio.currentTime = 0; + audio.currentTime = 0; audio.play(); } @@ -63,7 +64,7 @@ define('sounds', function () { if (!soundMap[type]) { return; } - + if (id) { var item = 'sounds.handled:' + id; if (sessionStorage.getItem(item)) { diff --git a/public/src/modules/taskbar.js b/public/src/modules/taskbar.js index 7a0b3c39ea..3897fbe6a1 100644 --- a/public/src/modules/taskbar.js +++ b/public/src/modules/taskbar.js @@ -1,5 +1,5 @@ -"use strict"; -/*global define, app, templates*/ +'use strict'; + define('taskbar', function () { var taskbar = {}; @@ -13,9 +13,9 @@ define('taskbar', function () { $(document.body).append(self.taskbar); self.taskbar.on('click', 'li', function () { - var $btn = $(this), - module = $btn.attr('data-module'), - uuid = $btn.attr('data-uuid'); + var $btn = $(this); + var module = $btn.attr('data-module'); + var uuid = $btn.attr('data-uuid'); require([module], function (module) { if (!$btn.hasClass('active')) { @@ -39,7 +39,7 @@ define('taskbar', function () { taskbar.discard = function (module, uuid) { var btnEl = taskbar.tasklist.find('[data-module="' + module + '"][data-uuid="' + uuid + '"]'); btnEl.remove(); - + update(); }; @@ -50,7 +50,7 @@ define('taskbar', function () { module: module, uuid: uuid, options: options, - element: element + element: element, }; $(window).trigger('filter:taskbar.push', data); @@ -119,7 +119,7 @@ define('taskbar', function () { '') .attr({ 'data-module': data.module, - 'data-uuid': data.uuid + 'data-uuid': data.uuid, }) .addClass(data.options.state !== undefined ? data.options.state : 'active'); diff --git a/public/src/modules/topicSelect.js b/public/src/modules/topicSelect.js index 4368b97237..185e5e36a0 100644 --- a/public/src/modules/topicSelect.js +++ b/public/src/modules/topicSelect.js @@ -1,6 +1,5 @@ 'use strict'; -/* globals define*/ define('topicSelect', ['components'], function (components) { var TopicSelect = {}; @@ -52,8 +51,7 @@ define('topicSelect', ['components'], function (components) { }; function selectRange(clickedTid) { - - if(!lastSelected) { + if (!lastSelected) { lastSelected = $('[component="category/topic"]').first().find('[component="topic/select"]'); } @@ -71,7 +69,7 @@ define('topicSelect', ['components'], function (components) { end = tmp; } - for(var i = start; i <= end; ++i) { + for (var i = start; i <= end; i += 1) { var topic = $('[component="category/topic"]').eq(i); toggleSelect(topic.find('[component="topic/select"]'), isSelected); } diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index aa719ff1a2..ce49f222f5 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -1,7 +1,6 @@ -/* global define, jQuery, config, utils, window, Promise */ +'use strict'; (function (factory) { - 'use strict'; function loadClient(language, namespace) { return Promise.resolve(jQuery.getJSON(config.relative_path + '/assets/language/' + language + '/' + namespace + '.json?' + config['cache-buster'])); } @@ -44,9 +43,8 @@ window.translator = factory(window.string, loadClient, warn); } }(function (string, load, warn) { - 'use strict'; var assign = Object.assign || jQuery.extend; - function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var Translator = (function () { /** @@ -155,7 +153,7 @@ while (cursor + 2 <= len) { sliced = str.slice(cursor, cursor + 2); - // found some text after the double bracket, + // found some text after the double bracket, // so this is probably a translation string if (!textBeforeColonFound && validTextRegex.test(sliced[0])) { textBeforeColonFound = true; @@ -174,7 +172,7 @@ cursor += 1; // a space or comma was found before the name // this isn't a translation string, so back out - } else if (!(textBeforeColonFound && colonFound && textAfterColonFound && commaAfterNameFound) && + } else if (!(textBeforeColonFound && colonFound && textAfterColonFound && commaAfterNameFound) && invalidTextRegex.test(sliced[0])) { cursor += 1; lastBreak -= 2; @@ -291,7 +289,8 @@ warn('[translator] Parameter `namespace` is ' + namespace + (namespace === '' ? '(empty string)' : '')); translation = Promise.resolve({}); } else { - translation = this.translations[namespace] = this.translations[namespace] || this.load(this.lang, namespace).catch(function () { return {}; }); + this.translations[namespace] = this.translations[namespace] || this.load(this.lang, namespace).catch(function () { return {}; }); + translation = this.translations[namespace]; } if (key) { @@ -491,28 +490,28 @@ prepareDOM: function prepareDOM() { // Load the appropriate timeago locale file, // and correct NodeBB language codes to timeago codes, if necessary - var languageCode = void 0; + var languageCode; switch (config.userLang) { - case 'en-GB': - case 'en-US': - languageCode = 'en'; - break; + case 'en-GB': + case 'en-US': + languageCode = 'en'; + break; - case 'fa-IR': - languageCode = 'fa'; - break; + case 'fa-IR': + languageCode = 'fa'; + break; - case 'pt-BR': - languageCode = 'pt-br'; - break; + case 'pt-BR': + languageCode = 'pt-br'; + break; - case 'nb': - languageCode = 'no'; - break; + case 'nb': + languageCode = 'no'; + break; - default: - languageCode = config.userLang; - break; + default: + languageCode = config.userLang; + break; } jQuery.getScript(config.relative_path + '/assets/vendor/jquery/timeago/locales/jquery.timeago.' + languageCode + '.js').done(function () { @@ -532,7 +531,7 @@ jQuery('html').css('direction', value).attr('data-dir', value); } }); - } + }, }; return adaptor; diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index 0e2a7e7ec8..aca2460ee5 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -1,9 +1,7 @@ 'use strict'; -/* globals define, templates */ define('uploader', ['translator'], function (translator) { - var module = {}; module.open = function (route, params, fileSize, callback) { @@ -11,7 +9,7 @@ define('uploader', ['translator'], function (translator) { module.show({ route: route, params: params, - fileSize: fileSize + fileSize: fileSize, }, callback); }; @@ -23,12 +21,12 @@ define('uploader', ['translator'], function (translator) { title: data.title || '[[global:upload_file]]', description: data.description || '', button: data.button || '[[global:upload]]', - accept: data.accept ? data.accept.replace(/,/g, ', ') : '' + accept: data.accept ? data.accept.replace(/,/g, ', ') : '', }, function (uploadModal) { uploadModal = $(uploadModal); uploadModal.modal('show'); - uploadModal.on('hidden.bs.modal', function () { + uploadModal.on('hidden.bs.modal', function () { uploadModal.remove(); }); @@ -76,7 +74,7 @@ define('uploader', ['translator'], function (translator) { uploadModal.find('#uploadForm').ajaxSubmit({ headers: { - 'x-csrf-token': config.csrf_token + 'x-csrf-token': config.csrf_token, }, error: function (xhr) { xhr = maybeParse(xhr); @@ -99,7 +97,7 @@ define('uploader', ['translator'], function (translator) { module.hideAlerts(uploadModal); uploadModal.modal('hide'); }, 750); - } + }, }); } @@ -114,7 +112,7 @@ define('uploader', ['translator'], function (translator) { try { return $.parseJSON(response); } catch (e) { - return {error: '[[error:parse-error]]'}; + return { error: '[[error:parse-error]]' }; } } return response; @@ -128,4 +126,4 @@ define('uploader', ['translator'], function (translator) { } return module; -}); \ No newline at end of file +}); diff --git a/public/src/overrides.js b/public/src/overrides.js index 95c9c3d69e..b74d93efba 100644 --- a/public/src/overrides.js +++ b/public/src/overrides.js @@ -1,19 +1,17 @@ 'use strict'; -/* global bootbox */ -var overrides = overrides || {}; +var overrides = window.overrides || {}; -if ('undefined' !== typeof window) { - - (function ($, undefined) { +if (typeof window !== 'undefined') { + (function ($) { require(['translator'], function (translator) { $.fn.getCursorPosition = function () { var el = $(this).get(0); var pos = 0; - if('selectionStart' in el) { + if ('selectionStart' in el) { pos = el.selectionStart; - } else if('selection' in document) { + } else if ('selection' in document) { el.focus(); var Sel = document.selection.createRange(); var SelLength = document.selection.createRange().text.length; @@ -24,7 +22,7 @@ if ('undefined' !== typeof window) { }; $.fn.selectRange = function (start, end) { - if(!end) { + if (!end) { end = start; } return this.each(function () { @@ -41,7 +39,7 @@ if ('undefined' !== typeof window) { }); }; - //http://stackoverflow.com/questions/511088/use-javascript-to-place-cursor-at-end-of-text-in-text-input-element + // http://stackoverflow.com/questions/511088/use-javascript-to-place-cursor-at-end-of-text-in-text-input-element $.fn.putCursorAtEnd = function () { return this.each(function () { $(this).focus(); @@ -86,17 +84,17 @@ if ('undefined' !== typeof window) { }); } }); - }(jQuery || {fn:{}})); + }(jQuery || { fn: {} })); (function () { // FIX FOR #1245 - https://github.com/NodeBB/NodeBB/issues/1245 // from http://stackoverflow.com/questions/15931962/bootstrap-dropdown-disappear-with-right-click-on-firefox // obtain a reference to the original handler - var _clearMenus = $._data(document, "events").click.filter(function (el) { + var _clearMenus = $._data(document, 'events').click.filter(function (el) { return el.namespace === 'bs.data-api.dropdown' && el.selector === undefined; }); - if(_clearMenus.length) { + if (_clearMenus.length) { _clearMenus = _clearMenus[0].handler; } @@ -136,5 +134,4 @@ if ('undefined' !== typeof window) { timeagoFn.apply(this, arguments); }; }; - } diff --git a/public/src/require-config.js b/public/src/require-config.js index 0e021f6be0..a7c70ac70e 100644 --- a/public/src/require-config.js +++ b/public/src/require-config.js @@ -1,11 +1,13 @@ +'use strict'; + require.config({ baseUrl: config.relative_path + '/assets/src/modules', waitSeconds: 7, urlArgs: config['cache-buster'], paths: { - 'forum': '../client', - 'admin': '../admin', - 'vendor': '../../vendor', - 'plugins': '../../plugins' - } + forum: '../client', + admin: '../admin', + vendor: '../../vendor', + plugins: '../../plugins', + }, }); diff --git a/public/src/sockets.js b/public/src/sockets.js index c255287c58..6b22ce9ac9 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -1,7 +1,7 @@ 'use strict'; -/* globals config, io, ajaxify */ -var app = app || {}; + +var app = window.app || {}; var socket; app.isConnected = false; @@ -12,7 +12,7 @@ app.isConnected = false; reconnectionAttempts: config.maxReconnectionAttempts, reconnectionDelay: config.reconnectionDelay, transports: config.socketioTransports, - path: config.relative_path + '/socket.io' + path: config.relative_path + '/socket.io', }; socket = io(config.websocketAddress, ioParams); @@ -71,30 +71,30 @@ app.isConnected = false; var url_parts = window.location.pathname.slice(config.relative_path.length).split('/').slice(1); var room; - switch(url_parts[0]) { - case 'user': - room = 'user/' + (ajaxify.data ? ajaxify.data.theirid : 0); + switch (url_parts[0]) { + case 'user': + room = 'user/' + (ajaxify.data ? ajaxify.data.theirid : 0); break; - case 'topic': - room = 'topic_' + url_parts[1]; + case 'topic': + room = 'topic_' + url_parts[1]; break; - case 'category': - room = 'category_' + url_parts[1]; + case 'category': + room = 'category_' + url_parts[1]; break; - case 'recent': - room = 'recent_topics'; + case 'recent': + room = 'recent_topics'; break; - case 'unread': - room = 'unread_topics'; + case 'unread': + room = 'unread_topics'; break; - case 'popular': - room = 'popular_topics'; + case 'popular': + room = 'popular_topics'; break; - case 'admin': - room = 'admin'; + case 'admin': + room = 'admin'; break; - case 'categories': - room = 'categories'; + case 'categories': + room = 'categories'; break; } app.currentRoom = ''; @@ -112,7 +112,7 @@ app.isConnected = false; } reconnectEl.addClass('active').removeClass('hide').tooltip({ - placement: 'bottom' + placement: 'bottom', }); } @@ -124,5 +124,4 @@ app.isConnected = false; function onEventBanned() { window.location.href = config.relative_path + '/'; } - -}()); \ No newline at end of file +}()); diff --git a/public/src/utils.js b/public/src/utils.js index 42d4b6f3ad..171e3d86db 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -1,9 +1,11 @@ +'use strict'; + (function (module) { - 'use strict'; + var utils; + var fs; + var XRegExp; - var utils, fs, XRegExp; - - if ('undefined' === typeof window) { + if (typeof window === 'undefined') { fs = require('fs'); XRegExp = require('xregexp'); @@ -13,24 +15,23 @@ process.elapsedTimeSince = function (start) { var diff = process.hrtime(start); - return diff[0] * 1e3 + diff[1] / 1e6; + return (diff[0] * 1e3) + (diff[1] / 1e6); }; - } else { XRegExp = window.XRegExp; } - module.exports = utils = { + utils = { generateUUID: function () { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c === 'x' ? r : (r & 0x3 | 0x8); + var r = Math.random() * 16 | 0; + var v = c === 'x' ? r : ((r & 0x3) | 0x8); return v.toString(16); }); }, - //Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search + // Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search walk: function (dir, done) { var results = []; @@ -56,13 +57,15 @@ } results = results.concat(res); - if (!--pending) { + pending -= 1; + if (!pending) { done(null, results); } }); } else { results.push(file); - if (!--pending) { + pending -= 1; + if (!pending) { done(null, results); } } @@ -81,13 +84,13 @@ isLatin: /^[\w\d\s.,\-@]+$/, languageKeyRegex: /\[\[[\w]+:.+\]\]/, - //http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript/ + // http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript/ slugify: function (str, preserveCase) { if (!str) { return ''; } str = str.replace(utils.trimRegex, ''); - if(utils.isLatin.test(str)) { + if (utils.isLatin.test(str)) { str = str.replace(utils.invalidLatinChars, '-'); } else { str = XRegExp.replace(str, utils.invalidUnicodeChars, '-'); @@ -108,7 +111,7 @@ tag = tag.trim().toLowerCase(); // see https://github.com/NodeBB/NodeBB/issues/4378 tag = tag.replace(/\u202E/gi, ''); - tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, ''); + tag = tag.replace(/[,/#!$%^*;:{}=_`<>'"~()?|]/g, ''); tag = tag.substr(0, maxLength || 15).trim(); var matches = tag.match(/^[.-]*(.+?)[.-]*$/); if (matches && matches.length > 1) { @@ -118,7 +121,7 @@ }, removePunctuation: function (str) { - return str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`<>'"~()?]/g, ''); + return str.replace(/[.,-/#!$%^&*;:{}=\-_`<>'"~()?]/g, ''); }, isEmailValid: function (email) { @@ -126,7 +129,7 @@ }, isUserNameValid: function (name) { - return (name && name !== '' && (/^['"\s\-\+.*0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name))); + return (name && name !== '' && (/^['"\s\-+.*0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name))); }, isPasswordValid: function (password) { @@ -143,11 +146,13 @@ // shallow objects merge merge: function () { - var result = {}, obj, keys; - for (var i = 0; i < arguments.length; i++) { + var result = {}; + var obj; + var keys; + for (var i = 0; i < arguments.length; i += 1) { obj = arguments[i] || {}; keys = Object.keys(obj); - for (var j = 0; j < keys.length; j++) { + for (var j = 0; j < keys.length; j += 1) { result[keys[j]] = obj[keys[j]]; } } @@ -159,29 +164,29 @@ }, extensionMimeTypeMap: { - "bmp": "image/bmp", - "cmx": "image/x-cmx", - "cod": "image/cis-cod", - "gif": "image/gif", - "ico": "image/x-icon", - "ief": "image/ief", - "jfif": "image/pipeg", - "jpe": "image/jpeg", - "jpeg": "image/jpeg", - "jpg": "image/jpeg", - "png": "image/png", - "pbm": "image/x-portable-bitmap", - "pgm": "image/x-portable-graymap", - "pnm": "image/x-portable-anymap", - "ppm": "image/x-portable-pixmap", - "ras": "image/x-cmu-raster", - "rgb": "image/x-rgb", - "svg": "image/svg+xml", - "tif": "image/tiff", - "tiff": "image/tiff", - "xbm": "image/x-xbitmap", - "xpm": "image/x-xpixmap", - "xwd": "image/x-xwindowdump" + bmp: 'image/bmp', + cmx: 'image/x-cmx', + cod: 'image/cis-cod', + gif: 'image/gif', + ico: 'image/x-icon', + ief: 'image/ief', + jfif: 'image/pipeg', + jpe: 'image/jpeg', + jpeg: 'image/jpeg', + jpg: 'image/jpeg', + png: 'image/png', + pbm: 'image/x-portable-bitmap', + pgm: 'image/x-portable-graymap', + pnm: 'image/x-portable-anymap', + ppm: 'image/x-portable-pixmap', + ras: 'image/x-cmu-raster', + rgb: 'image/x-rgb', + svg: 'image/svg+xml', + tif: 'image/tiff', + tiff: 'image/tiff', + xbm: 'image/x-xbitmap', + xpm: 'image/x-xpixmap', + xwd: 'image/x-xwindowdump', }, fileMimeType: function (path) { @@ -205,13 +210,12 @@ makeNumberHumanReadable: function (num) { var n = parseInt(num, 10); - if(!n) { + if (!n) { return num; } if (n > 999999) { return (n / 1000000).toFixed(1) + 'm'; - } - else if(n > 999) { + } else if (n > 999) { return (n / 1000).toFixed(1) + 'k'; } return n; @@ -225,7 +229,7 @@ // takes a string like 1000 and returns 1,000 addCommas: function (text) { - return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"); + return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'); }, toISOString: function (timestamp) { @@ -236,9 +240,9 @@ return Date.prototype.toISOString ? new Date(parseInt(timestamp, 10)).toISOString() : timestamp; }, - tags : ['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], + tags: ['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], - stripTags : ['abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'base', 'basefont', + stripTags: ['abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'base', 'basefont', 'bdi', 'bdo', 'big', 'blink', 'body', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', @@ -249,11 +253,11 @@ 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'], escapeRegexChars: function (text) { - return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); }, escapeHTML: function (raw) { - return raw.replace(/&/gm,"&").replace(//gm,">"); + return raw.replace(/&/gm, '&').replace(//gm, '>'); }, isAndroidBrowser: function () { @@ -267,13 +271,13 @@ }, findBootstrapEnvironment: function () { - //http://stackoverflow.com/questions/14441456/how-to-detect-which-device-view-youre-on-using-twitter-bootstrap-api - var envs = ['xs', 'sm', 'md', 'lg'], - $el = $('
    '); + // http://stackoverflow.com/questions/14441456/how-to-detect-which-device-view-youre-on-using-twitter-bootstrap-api + var envs = ['xs', 'sm', 'md', 'lg']; + var $el = $('
    '); $el.appendTo($('body')); - for (var i = envs.length - 1; i >= 0; i--) { + for (var i = envs.length - 1; i >= 0; i -= 1) { var env = envs[i]; $el.addClass('hidden-' + env); @@ -292,10 +296,10 @@ }, getHoursArray: function () { - var currentHour = new Date().getHours(), - labels = []; + var currentHour = new Date().getHours(); + var labels = []; - for (var i = currentHour, ii = currentHour - 24; i > ii; i--) { + for (var i = currentHour, ii = currentHour - 24; i > ii; i -= 1) { var hour = i < 0 ? 24 + i : i; labels.push(hour + ':00'); } @@ -304,12 +308,12 @@ }, getDaysArray: function (from) { - var currentDay = new Date(from || Date.now()).getTime(), - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - labels = [], - tmpDate; + var currentDay = new Date(from || Date.now()).getTime(); + var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + var labels = []; + var tmpDate; - for(var x = 29; x >= 0; x--) { + for (var x = 29; x >= 0; x -= 1) { tmpDate = new Date(currentDay - (1000 * 60 * 60 * 24 * x)); labels.push(months[tmpDate.getMonth()] + ' ' + tmpDate.getDate()); } @@ -319,8 +323,8 @@ /* Retrieved from http://stackoverflow.com/a/7557433 @ 27 Mar 2016 */ isElementInViewport: function (el) { - //special bonus for those using jQuery - if (typeof jQuery === "function" && el instanceof jQuery) { + // special bonus for those using jQuery + if (typeof jQuery === 'function' && el instanceof jQuery) { el = el[0]; } @@ -329,14 +333,16 @@ return ( rect.top >= 0 && rect.left >= 0 && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ - rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */ + rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ ); }, // get all the url params in a single key/value hash params: function (options) { - var a, hash = {}, params; + var a; + var hash = {}; + var params; options = options || {}; options.skipToType = options.skipToType || {}; @@ -344,12 +350,12 @@ if (options.url) { a = utils.urlToLocation(options.url); } - params = (a ? a.search : window.location.search).substring(1).split("&"); + params = (a ? a.search : window.location.search).substring(1).split('&'); params.forEach(function (param) { - var val = param.split('='), - key = decodeURI(val[0]), - value = options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1])); + var val = param.split('='); + var key = decodeURI(val[0]); + var value = options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1])); if (key) { if (key.substr(-2, 2) === '[]') { @@ -383,25 +389,24 @@ toType: function (str) { var type = typeof str; if (type !== 'string') { - return str; - } else { - var nb = parseFloat(str); - if (!isNaN(nb) && isFinite(str)) { - return nb; - } - if (str === 'false') { - return false; - } - if (str === 'true') { - return true; - } - - try { - str = JSON.parse(str); - } catch (e) {} - return str; } + var nb = parseFloat(str); + if (!isNaN(nb) && isFinite(str)) { + return nb; + } + if (str === 'false') { + return false; + } + if (str === 'true') { + return true; + } + + try { + str = JSON.parse(str); + } catch (e) {} + + return str; }, // Safely get/set chained properties on an object @@ -410,23 +415,23 @@ // get example: utils.props(A, 'a.b.c.foo.bar') // returns undefined without throwing a TypeError // credits to github.com/gkindel props: function (obj, props, value) { - if(obj === undefined) { + if (obj === undefined) { obj = window; } - if(props == null) { + if (props == null) { return undefined; } var i = props.indexOf('.'); - if( i == -1 ) { - if(value !== undefined) { + if (i === -1) { + if (value !== undefined) { obj[props] = value; } return obj[props]; } - var prop = props.slice(0, i), - newProps = props.slice(i + 1); + var prop = props.slice(0, i); + var newProps = props.slice(i + 1); - if(props !== undefined && !(obj[prop] instanceof Object) ) { + if (props !== undefined && !(obj[prop] instanceof Object)) { obj[prop] = {}; } @@ -439,47 +444,43 @@ targetLocation.host === referenceLocation.host && targetLocation.protocol === referenceLocation.protocol && // Otherwise need to check if protocol and host match (relative_path.length > 0 ? targetLocation.pathname.indexOf(relative_path) === 0 : true) // Subfolder installs need this additional check ); - } + }, }; - if (typeof String.prototype.startsWith != 'function') { + module.exports = utils; + if (typeof window !== 'undefined') { + window.utils = module.exports; + } + + /* eslint "no-extend-native": "off" */ + if (typeof String.prototype.startsWith !== 'function') { String.prototype.startsWith = function (prefix) { if (this.length < prefix.length) { return false; } - for (var i = prefix.length - 1; (i >= 0) && (this[i] === prefix[i]); --i) { - continue; - } - return i < 0; + return this.slice(0, prefix.length) === prefix; }; } - if (typeof String.prototype.endsWith != 'function') { + if (typeof String.prototype.endsWith !== 'function') { String.prototype.endsWith = function (suffix) { if (this.length < suffix.length) { return false; } - var len = this.length; - var suffixLen = suffix.length; - for (var i = 1; (i <= suffixLen && this[len - i] === suffix[suffixLen - i]); ++i) { - continue; + if (suffix.length === 0) { + return true; } - return i > suffixLen; + return this.slice(-suffix.length) === suffix; }; } - if (typeof String.prototype.rtrim != 'function') { + if (typeof String.prototype.rtrim !== 'function') { String.prototype.rtrim = function () { return this.replace(/\s+$/g, ''); }; } - - if ('undefined' !== typeof window) { - window.utils = module.exports; - } - -}('undefined' === typeof module ? { +}(typeof module === 'undefined' ? { module: { - exports: {} - } + exports: {}, + }, } : module)); diff --git a/public/src/widgets.js b/public/src/widgets.js index 377ccb2c53..f5f667d2a7 100644 --- a/public/src/widgets.js +++ b/public/src/widgets.js @@ -1,5 +1,5 @@ -"use strict"; -/*global ajaxify, templates, config, utils*/ +'use strict'; + (function (ajaxify) { ajaxify.widgets = {}; @@ -29,19 +29,19 @@ } }); - $.get(config.relative_path + '/api/widgets/render' + '?' + config['cache-buster'], { + $.get(config.relative_path + '/api/widgets/render?' + config['cache-buster'], { locations: widgetLocations, template: template + '.tpl', url: url, cid: ajaxify.data.cid, - isMobile: utils.isMobile() + isMobile: utils.isMobile(), }, function (renderedAreas) { - for (var x = 0; x < renderedAreas.length; ++x) { + for (var x = 0; x < renderedAreas.length; x += 1) { var renderedWidgets = renderedAreas[x].widgets; var location = renderedAreas[x].location; var html = ''; - for (var i = 0; i < renderedWidgets.length; ++i) { + for (var i = 0; i < renderedWidgets.length; i += 1) { html += templates.parse(renderedWidgets[i].html, {}); } @@ -79,7 +79,7 @@ widgetAreas.find('img[title].teaser-pic,img[title].user-img').each(function () { $(this).tooltip({ placement: 'top', - title: $(this).attr('title') + title: $(this).attr('title'), }); }); $(window).trigger('action:widgets.loaded', {}); diff --git a/public/vendor/fontawesome/fonts/FontAwesome.otf b/public/vendor/fontawesome/fonts/FontAwesome.otf index d4de13e832..401ec0f36e 100644 Binary files a/public/vendor/fontawesome/fonts/FontAwesome.otf and b/public/vendor/fontawesome/fonts/FontAwesome.otf differ diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.eot b/public/vendor/fontawesome/fonts/fontawesome-webfont.eot index c7b00d2ba8..e9f60ca953 100644 Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.eot and b/public/vendor/fontawesome/fonts/fontawesome-webfont.eot differ diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.svg b/public/vendor/fontawesome/fonts/fontawesome-webfont.svg index 8b66187fe0..855c845e53 100644 --- a/public/vendor/fontawesome/fonts/fontawesome-webfont.svg +++ b/public/vendor/fontawesome/fonts/fontawesome-webfont.svg @@ -1,685 +1,2671 @@ - - + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf b/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf index f221e50a2e..35acda2fa1 100644 Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf and b/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf differ diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff index 6e7483cf61..400014a4b0 100644 Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff and b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff differ diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 index 7eb74fd127..4d13fc6040 100644 Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 and b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 differ diff --git a/public/vendor/fontawesome/less/font-awesome.less b/public/vendor/fontawesome/less/font-awesome.less index c44e5f466a..c3677def31 100644 --- a/public/vendor/fontawesome/less/font-awesome.less +++ b/public/vendor/fontawesome/less/font-awesome.less @@ -1,5 +1,5 @@ /*! - * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ diff --git a/public/vendor/fontawesome/less/icons.less b/public/vendor/fontawesome/less/icons.less index ba21b222d6..159d600425 100644 --- a/public/vendor/fontawesome/less/icons.less +++ b/public/vendor/fontawesome/less/icons.less @@ -605,6 +605,7 @@ .@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } .@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } .@{fa-css-prefix}-battery-4:before, +.@{fa-css-prefix}-battery:before, .@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } .@{fa-css-prefix}-battery-3:before, .@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } @@ -731,3 +732,58 @@ .@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; } .@{fa-css-prefix}-fa:before, .@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; } +.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; } +.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; } +.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; } +.@{fa-css-prefix}-linode:before { content: @fa-var-linode; } +.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; } +.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; } +.@{fa-css-prefix}-vcard:before, +.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; } +.@{fa-css-prefix}-vcard-o:before, +.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; } +.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; } +.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; } +.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; } +.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; } +.@{fa-css-prefix}-drivers-license:before, +.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; } +.@{fa-css-prefix}-drivers-license-o:before, +.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; } +.@{fa-css-prefix}-quora:before { content: @fa-var-quora; } +.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; } +.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; } +.@{fa-css-prefix}-thermometer-4:before, +.@{fa-css-prefix}-thermometer:before, +.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; } +.@{fa-css-prefix}-thermometer-3:before, +.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; } +.@{fa-css-prefix}-thermometer-2:before, +.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; } +.@{fa-css-prefix}-thermometer-1:before, +.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; } +.@{fa-css-prefix}-thermometer-0:before, +.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; } +.@{fa-css-prefix}-shower:before { content: @fa-var-shower; } +.@{fa-css-prefix}-bathtub:before, +.@{fa-css-prefix}-s15:before, +.@{fa-css-prefix}-bath:before { content: @fa-var-bath; } +.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; } +.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; } +.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; } +.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; } +.@{fa-css-prefix}-times-rectangle:before, +.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; } +.@{fa-css-prefix}-times-rectangle-o:before, +.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; } +.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; } +.@{fa-css-prefix}-grav:before { content: @fa-var-grav; } +.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; } +.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; } +.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; } +.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; } +.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; } +.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; } +.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; } +.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; } +.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; } diff --git a/public/vendor/fontawesome/less/variables.less b/public/vendor/fontawesome/less/variables.less index a2019dcadc..1620d22dd7 100644 --- a/public/vendor/fontawesome/less/variables.less +++ b/public/vendor/fontawesome/less/variables.less @@ -4,14 +4,18 @@ @fa-font-path: "./vendor/fontawesome/fonts"; @fa-font-size-base: 14px; @fa-line-height-base: 1; -//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts"; // for referencing Bootstrap CDN font files directly +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly @fa-css-prefix: fa; -@fa-version: "4.6.3"; +@fa-version: "4.7.0"; @fa-border-color: #eee; @fa-inverse: #fff; @fa-li-width: (30em / 14); @fa-var-500px: "\f26e"; +@fa-var-address-book: "\f2b9"; +@fa-var-address-book-o: "\f2ba"; +@fa-var-address-card: "\f2bb"; +@fa-var-address-card-o: "\f2bc"; @fa-var-adjust: "\f042"; @fa-var-adn: "\f170"; @fa-var-align-center: "\f037"; @@ -60,11 +64,15 @@ @fa-var-backward: "\f04a"; @fa-var-balance-scale: "\f24e"; @fa-var-ban: "\f05e"; +@fa-var-bandcamp: "\f2d5"; @fa-var-bank: "\f19c"; @fa-var-bar-chart: "\f080"; @fa-var-bar-chart-o: "\f080"; @fa-var-barcode: "\f02a"; @fa-var-bars: "\f0c9"; +@fa-var-bath: "\f2cd"; +@fa-var-bathtub: "\f2cd"; +@fa-var-battery: "\f240"; @fa-var-battery-0: "\f244"; @fa-var-battery-1: "\f243"; @fa-var-battery-2: "\f242"; @@ -214,19 +222,25 @@ @fa-var-dot-circle-o: "\f192"; @fa-var-download: "\f019"; @fa-var-dribbble: "\f17d"; +@fa-var-drivers-license: "\f2c2"; +@fa-var-drivers-license-o: "\f2c3"; @fa-var-dropbox: "\f16b"; @fa-var-drupal: "\f1a9"; @fa-var-edge: "\f282"; @fa-var-edit: "\f044"; +@fa-var-eercast: "\f2da"; @fa-var-eject: "\f052"; @fa-var-ellipsis-h: "\f141"; @fa-var-ellipsis-v: "\f142"; @fa-var-empire: "\f1d1"; @fa-var-envelope: "\f0e0"; @fa-var-envelope-o: "\f003"; +@fa-var-envelope-open: "\f2b6"; +@fa-var-envelope-open-o: "\f2b7"; @fa-var-envelope-square: "\f199"; @fa-var-envira: "\f299"; @fa-var-eraser: "\f12d"; +@fa-var-etsy: "\f2d7"; @fa-var-eur: "\f153"; @fa-var-euro: "\f153"; @fa-var-exchange: "\f0ec"; @@ -294,6 +308,7 @@ @fa-var-forumbee: "\f211"; @fa-var-forward: "\f04e"; @fa-var-foursquare: "\f180"; +@fa-var-free-code-camp: "\f2c5"; @fa-var-frown-o: "\f119"; @fa-var-futbol-o: "\f1e3"; @fa-var-gamepad: "\f11b"; @@ -326,6 +341,7 @@ @fa-var-google-wallet: "\f1ee"; @fa-var-graduation-cap: "\f19d"; @fa-var-gratipay: "\f184"; +@fa-var-grav: "\f2d6"; @fa-var-group: "\f0c0"; @fa-var-h-square: "\f0fd"; @fa-var-hacker-news: "\f1d4"; @@ -342,6 +358,7 @@ @fa-var-hand-scissors-o: "\f257"; @fa-var-hand-spock-o: "\f259"; @fa-var-hand-stop-o: "\f256"; +@fa-var-handshake-o: "\f2b5"; @fa-var-hard-of-hearing: "\f2a4"; @fa-var-hashtag: "\f292"; @fa-var-hdd-o: "\f0a0"; @@ -365,8 +382,12 @@ @fa-var-houzz: "\f27c"; @fa-var-html5: "\f13b"; @fa-var-i-cursor: "\f246"; +@fa-var-id-badge: "\f2c1"; +@fa-var-id-card: "\f2c2"; +@fa-var-id-card-o: "\f2c3"; @fa-var-ils: "\f20b"; @fa-var-image: "\f03e"; +@fa-var-imdb: "\f2d8"; @fa-var-inbox: "\f01c"; @fa-var-indent: "\f03c"; @fa-var-industry: "\f275"; @@ -404,6 +425,7 @@ @fa-var-link: "\f0c1"; @fa-var-linkedin: "\f0e1"; @fa-var-linkedin-square: "\f08c"; +@fa-var-linode: "\f2b8"; @fa-var-linux: "\f17c"; @fa-var-list: "\f03a"; @fa-var-list-alt: "\f022"; @@ -436,8 +458,10 @@ @fa-var-meanpath: "\f20c"; @fa-var-medium: "\f23a"; @fa-var-medkit: "\f0fa"; +@fa-var-meetup: "\f2e0"; @fa-var-meh-o: "\f11a"; @fa-var-mercury: "\f223"; +@fa-var-microchip: "\f2db"; @fa-var-microphone: "\f130"; @fa-var-microphone-slash: "\f131"; @fa-var-minus: "\f068"; @@ -502,6 +526,7 @@ @fa-var-plus-circle: "\f055"; @fa-var-plus-square: "\f0fe"; @fa-var-plus-square-o: "\f196"; +@fa-var-podcast: "\f2ce"; @fa-var-power-off: "\f011"; @fa-var-print: "\f02f"; @fa-var-product-hunt: "\f288"; @@ -511,10 +536,12 @@ @fa-var-question: "\f128"; @fa-var-question-circle: "\f059"; @fa-var-question-circle-o: "\f29c"; +@fa-var-quora: "\f2c4"; @fa-var-quote-left: "\f10d"; @fa-var-quote-right: "\f10e"; @fa-var-ra: "\f1d0"; @fa-var-random: "\f074"; +@fa-var-ravelry: "\f2d9"; @fa-var-rebel: "\f1d0"; @fa-var-recycle: "\f1b8"; @fa-var-reddit: "\f1a1"; @@ -541,6 +568,7 @@ @fa-var-rub: "\f158"; @fa-var-ruble: "\f158"; @fa-var-rupee: "\f156"; +@fa-var-s15: "\f2cd"; @fa-var-safari: "\f267"; @fa-var-save: "\f0c7"; @fa-var-scissors: "\f0c4"; @@ -565,6 +593,7 @@ @fa-var-shopping-bag: "\f290"; @fa-var-shopping-basket: "\f291"; @fa-var-shopping-cart: "\f07a"; +@fa-var-shower: "\f2cc"; @fa-var-sign-in: "\f090"; @fa-var-sign-language: "\f2a7"; @fa-var-sign-out: "\f08b"; @@ -581,6 +610,7 @@ @fa-var-snapchat: "\f2ab"; @fa-var-snapchat-ghost: "\f2ac"; @fa-var-snapchat-square: "\f2ad"; +@fa-var-snowflake-o: "\f2dc"; @fa-var-soccer-ball-o: "\f1e3"; @fa-var-sort: "\f0dc"; @fa-var-sort-alpha-asc: "\f15d"; @@ -626,6 +656,7 @@ @fa-var-subway: "\f239"; @fa-var-suitcase: "\f0f2"; @fa-var-sun-o: "\f185"; +@fa-var-superpowers: "\f2dd"; @fa-var-superscript: "\f12b"; @fa-var-support: "\f1cd"; @fa-var-table: "\f0ce"; @@ -635,6 +666,7 @@ @fa-var-tags: "\f02c"; @fa-var-tasks: "\f0ae"; @fa-var-taxi: "\f1ba"; +@fa-var-telegram: "\f2c6"; @fa-var-television: "\f26c"; @fa-var-tencent-weibo: "\f1d5"; @fa-var-terminal: "\f120"; @@ -644,6 +676,17 @@ @fa-var-th-large: "\f009"; @fa-var-th-list: "\f00b"; @fa-var-themeisle: "\f2b2"; +@fa-var-thermometer: "\f2c7"; +@fa-var-thermometer-0: "\f2cb"; +@fa-var-thermometer-1: "\f2ca"; +@fa-var-thermometer-2: "\f2c9"; +@fa-var-thermometer-3: "\f2c8"; +@fa-var-thermometer-4: "\f2c7"; +@fa-var-thermometer-empty: "\f2cb"; +@fa-var-thermometer-full: "\f2c7"; +@fa-var-thermometer-half: "\f2c9"; +@fa-var-thermometer-quarter: "\f2ca"; +@fa-var-thermometer-three-quarters: "\f2c8"; @fa-var-thumb-tack: "\f08d"; @fa-var-thumbs-down: "\f165"; @fa-var-thumbs-o-down: "\f088"; @@ -653,6 +696,8 @@ @fa-var-times: "\f00d"; @fa-var-times-circle: "\f057"; @fa-var-times-circle-o: "\f05c"; +@fa-var-times-rectangle: "\f2d3"; +@fa-var-times-rectangle-o: "\f2d4"; @fa-var-tint: "\f043"; @fa-var-toggle-down: "\f150"; @fa-var-toggle-left: "\f191"; @@ -693,11 +738,16 @@ @fa-var-usb: "\f287"; @fa-var-usd: "\f155"; @fa-var-user: "\f007"; +@fa-var-user-circle: "\f2bd"; +@fa-var-user-circle-o: "\f2be"; @fa-var-user-md: "\f0f0"; +@fa-var-user-o: "\f2c0"; @fa-var-user-plus: "\f234"; @fa-var-user-secret: "\f21b"; @fa-var-user-times: "\f235"; @fa-var-users: "\f0c0"; +@fa-var-vcard: "\f2bb"; +@fa-var-vcard-o: "\f2bc"; @fa-var-venus: "\f221"; @fa-var-venus-double: "\f226"; @fa-var-venus-mars: "\f228"; @@ -722,10 +772,16 @@ @fa-var-wheelchair-alt: "\f29b"; @fa-var-wifi: "\f1eb"; @fa-var-wikipedia-w: "\f266"; +@fa-var-window-close: "\f2d3"; +@fa-var-window-close-o: "\f2d4"; +@fa-var-window-maximize: "\f2d0"; +@fa-var-window-minimize: "\f2d1"; +@fa-var-window-restore: "\f2d2"; @fa-var-windows: "\f17a"; @fa-var-won: "\f159"; @fa-var-wordpress: "\f19a"; @fa-var-wpbeginner: "\f297"; +@fa-var-wpexplorer: "\f2de"; @fa-var-wpforms: "\f298"; @fa-var-wrench: "\f0ad"; @fa-var-xing: "\f168"; diff --git a/src/admin/search.js b/src/admin/search.js index 4c53815e48..3a6f52cfd0 100644 --- a/src/admin/search.js +++ b/src/admin/search.js @@ -19,7 +19,7 @@ function filterDirectories(directories) { // exclude category.tpl, group.tpl, category-analytics.tpl return !dir.includes('/partials/') && /\/.*\//.test(dir) && - !/manage\/(category|group|category\-analytics)$/.test(dir); + !/manage\/(category|group|category-analytics)$/.test(dir); }); } @@ -45,7 +45,7 @@ function sanitize(html) { function simplify(translations) { return translations // remove all mustaches - .replace(/(?:\{{1,2}[^\}]*?\}{1,2})/g, '') + .replace(/(?:\{{1,2}[^}]*?\}{1,2})/g, '') // collapse whitespace .replace(/(?:[ \t]*[\n\r]+[ \t]*)+/g, '\n') .replace(/[\t ]+/g, ' '); @@ -137,7 +137,7 @@ function initDict(language, callback) { title = '[[admin/menu:general/dashboard]]'; } else { title = title.match(/admin\/(.+?)\/(.+?)$/); - title = '[[admin/menu:section-' + + title = '[[admin/menu:section-' + (title[1] === 'development' ? 'advanced' : title[1]) + ']]' + (title[2] ? (' > [[admin/menu:' + title[1] + '/' + title[2] + ']]') : ''); diff --git a/src/analytics.js b/src/analytics.js index 6b248057da..6a733b1a5f 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -25,12 +25,12 @@ Analytics.increment = function (keys) { keys.forEach(function (key) { counters[key] = counters[key] || 0; - ++counters[key]; + counters[key] += 1; }); }; Analytics.pageView = function (payload) { - ++pageViews; + pageViews += 1; if (payload.ip) { db.sortedSetScore('ip:recent', payload.ip, function (err, score) { @@ -38,20 +38,20 @@ Analytics.pageView = function (payload) { return; } if (!score) { - ++uniqueIPCount; + uniqueIPCount += 1; } var today = new Date(); today.setHours(today.getHours(), 0, 0, 0); if (!score || score < today.getTime()) { - ++uniquevisitors; + uniquevisitors += 1; db.sortedSetAdd('ip:recent', Date.now(), payload.ip); } }); } if (payload.path) { - var categoryMatch = payload.path.match(isCategory), - cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null; + var categoryMatch = payload.path.match(isCategory); + var cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null; if (cid) { Analytics.increment(['pageviews:byCid:' + cid]); @@ -86,7 +86,7 @@ Analytics.writeData = function (callback) { } if (Object.keys(counters).length > 0) { - for(var key in counters) { + for (var key in counters) { if (counters.hasOwnProperty(key)) { dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime())); delete counters[key]; @@ -103,13 +103,13 @@ Analytics.writeData = function (callback) { }; Analytics.getHourlyStatsForSet = function (set, hour, numHours, callback) { - var terms = {}, - hoursArr = []; + var terms = {}; + var hoursArr = []; hour = new Date(hour); hour.setHours(hour.getHours(), 0, 0, 0); - for (var i = 0, ii = numHours; i < ii; i++) { + for (var i = 0, ii = numHours; i < ii; i += 1) { hoursArr.push(hour.getTime()); hour.setHours(hour.getHours() - 1, 0, 0, 0); } @@ -142,7 +142,8 @@ Analytics.getDailyStatsForSet = function (set, day, numDays, callback) { day.setHours(0, 0, 0, 0); async.whilst(function () { - return numDays--; + numDays -= 1; + return numDays + 1; }, function (next) { Analytics.getHourlyStatsForSet(set, day.getTime() - (1000 * 60 * 60 * 24 * numDays), 24, function (err, day) { if (err) { @@ -177,7 +178,7 @@ Analytics.getMonthlyPageViews = function (callback) { if (err) { return callback(err); } - callback(null, {thisMonth: scores[0] || 0, lastMonth: scores[1] || 0}); + callback(null, { thisMonth: scores[0] || 0, lastMonth: scores[1] || 0 }); }); }; @@ -193,7 +194,7 @@ Analytics.getCategoryAnalytics = function (cid, callback) { Analytics.getErrorAnalytics = function (callback) { async.parallel({ 'not-found': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:404', Date.now(), 7), - 'toobusy': async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:503', Date.now(), 7) + toobusy: async.apply(Analytics.getDailyStatsForSet, 'analytics:errors:503', Date.now(), 7), }, callback); }; diff --git a/src/batch.js b/src/batch.js index 19595df07e..cb3fd298a1 100644 --- a/src/batch.js +++ b/src/batch.js @@ -95,7 +95,7 @@ exports.processArray = function (array, process, options, callback) { if (err) { return next(err); } - start = start + batch; + start += batch; if (options.interval) { setTimeout(next, options.interval); } else { diff --git a/src/categories.js b/src/categories.js index 5bb5222d38..815049ad4c 100644 --- a/src/categories.js +++ b/src/categories.js @@ -10,7 +10,6 @@ var plugins = require('./plugins'); var privileges = require('./privileges'); (function (Categories) { - require('./categories/data')(Categories); require('./categories/create')(Categories); require('./categories/delete')(Categories); @@ -49,7 +48,7 @@ var privileges = require('./privileges'); }, isIgnored: function (next) { Categories.isIgnored([data.cid], data.uid, next); - } + }, }, next); }, function (results, next) { @@ -58,11 +57,11 @@ var privileges = require('./privileges'); category.isIgnored = results.isIgnored[0]; category.topic_count = results.topicCount; - plugins.fireHook('filter:category.get', {category: category, uid: data.uid}, next); + plugins.fireHook('filter:category.get', { category: category, uid: data.uid }, next); }, function (data, next) { next(null, data.category); - } + }, ], callback); }; @@ -73,7 +72,7 @@ var privileges = require('./privileges'); Categories.getPageCount = function (cid, uid, callback) { async.parallel({ topicCount: async.apply(Categories.getCategoryField, cid, 'topic_count'), - settings: async.apply(user.getSettings, uid) + settings: async.apply(user.getSettings, uid), }, function (err, results) { if (err) { return callback(err); @@ -107,7 +106,7 @@ var privileges = require('./privileges'); }, function (cids, next) { Categories.getCategories(cids, uid, next); - } + }, ], callback); }; @@ -146,7 +145,7 @@ var privileges = require('./privileges'); }, hasRead: function (next) { Categories.hasReadCategories(cids, uid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -214,7 +213,7 @@ var privileges = require('./privileges'); }); if (!parentCids.length) { - return callback(null, cids.map(function () {return null;})); + return callback(null, cids.map(function () { return null; })); } Categories.getCategoriesData(parentCids, next); @@ -224,13 +223,13 @@ var privileges = require('./privileges'); return parentData[parentCids.indexOf(parseInt(category.parentCid, 10))]; }); next(null, parentData); - } + }, ], callback); }; Categories.getChildren = function (cids, uid, callback) { var categories = cids.map(function (cid) { - return {cid: cid}; + return { cid: cid }; }); async.each(categories, function (category, next) { @@ -266,7 +265,7 @@ var privileges = require('./privileges'); async.each(category.children, function (child, next) { getChildrenRecursive(child, uid, next); }, next); - } + }, ], callback); } @@ -293,9 +292,12 @@ var privileges = require('./privileges'); * @param parentCid {number} start from 0 to build full tree */ Categories.getTree = function (categories, parentCid) { - var tree = [], i = 0, len = categories.length, category; + var tree = []; + var i = 0; + var len = categories.length; + var category; - for (i; i < len; ++i) { + for (i; i < len; i += 1) { category = categories[i]; if (!category.hasOwnProperty('parentCid') || category.parentCid === null) { category.parentCid = 0; @@ -357,9 +359,7 @@ var privileges = require('./privileges'); return uid && !isIgnoring[index]; }); next(null, readingUids); - } + }, ], callback); }; - - }(exports)); diff --git a/src/categories/activeusers.js b/src/categories/activeusers.js index 15673939ae..5ce28c4b11 100644 --- a/src/categories/activeusers.js +++ b/src/categories/activeusers.js @@ -5,7 +5,6 @@ var posts = require('../posts'); var db = require('../database'); module.exports = function (Categories) { - Categories.getActiveUsers = function (cid, callback) { async.waterfall([ function (next) { @@ -22,7 +21,7 @@ module.exports = function (Categories) { }); next(null, uids); - } + }, ], callback); }; }; diff --git a/src/categories/create.js b/src/categories/create.js index 508d8ab348..7be163bd5b 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -9,7 +9,6 @@ var privileges = require('../privileges'); var utils = require('../../public/src/utils'); module.exports = function (Categories) { - Categories.create = function (data, callback) { var category; var parentCid = data.parentCid ? data.parentCid : 0; @@ -40,11 +39,11 @@ module.exports = function (Categories) { order: order, link: '', numRecentReplies: 1, - class: ( data.class ? data.class : 'col-md-3 col-xs-6' ), - imageClass: 'cover' + class: (data.class ? data.class : 'col-md-3 col-xs-6'), + imageClass: 'cover', }; - plugins.fireHook('filter:category.create', {category: category, data: data}, next); + plugins.fireHook('filter:category.create', { category: category, data: data }, next); }, function (data, next) { category = data.category; @@ -63,7 +62,7 @@ module.exports = function (Categories) { async.apply(db.sortedSetAdd, 'cid:' + parentCid + ':children', category.order, category.cid), async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'administrators'), async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'registered-users'), - async.apply(privileges.categories.give, ['find', 'read', 'topics:read'], category.cid, 'guests') + async.apply(privileges.categories.give, ['find', 'read', 'topics:read'], category.cid, 'guests'), ], next); }, function (results, next) { @@ -75,7 +74,7 @@ module.exports = function (Categories) { function (category, next) { plugins.fireHook('action:category.create', category); next(null, category); - } + }, ], callback); }; @@ -93,7 +92,7 @@ module.exports = function (Categories) { function (next) { async.parallel({ source: async.apply(db.getObject, 'category:' + fromCid), - destination: async.apply(db.getObject, 'category:' + toCid) + destination: async.apply(db.getObject, 'category:' + toCid), }, next); }, function (results, next) { @@ -132,7 +131,7 @@ module.exports = function (Categories) { }, function (results, next) { Categories.copyPrivilegesFrom(fromCid, toCid, next); - } + }, ], function (err) { callback(err, destination); }); @@ -165,8 +164,7 @@ module.exports = function (Categories) { async.eachSeries(members, function (member, next) { groups.join('cid:' + toCid + ':privileges:' + privilege, member, next); }, next); - } + }, ], callback); } - }; diff --git a/src/categories/data.js b/src/categories/data.js index ccc31343d9..25b7021610 100644 --- a/src/categories/data.js +++ b/src/categories/data.js @@ -7,7 +7,6 @@ var winston = require('winston'); var db = require('../database'); module.exports = function (Categories) { - Categories.getCategoryData = function (cid, callback) { db.getObject('category:' + cid, function (err, category) { if (err) { @@ -46,11 +45,13 @@ module.exports = function (Categories) { category.disabled = category.hasOwnProperty('disabled') ? parseInt(category.disabled, 10) === 1 : undefined; category.icon = category.icon || 'hidden'; if (category.hasOwnProperty('post_count')) { - category.post_count = category.totalPostCount = category.post_count || 0; + category.post_count = category.post_count || 0; + category.totalPostCount = category.post_count; } if (category.hasOwnProperty('topic_count')) { - category.topic_count = category.totalTopicCount = category.topic_count || 0; + category.topic_count = category.topic_count || 0; + category.totalTopicCount = category.topic_count; } if (category.image) { @@ -96,7 +97,7 @@ module.exports = function (Categories) { async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), function (cids, next) { Categories.getCategoriesFields(cids, fields, next); - } + }, ], callback); }; @@ -111,5 +112,4 @@ module.exports = function (Categories) { Categories.incrementCategoryFieldBy = function (cid, field, value, callback) { db.incrObjectFieldBy('category:' + cid, field, value, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/categories/delete.js b/src/categories/delete.js index 06d4931132..4aad25846f 100644 --- a/src/categories/delete.js +++ b/src/categories/delete.js @@ -9,7 +9,6 @@ var groups = require('../groups'); var privileges = require('../privileges'); module.exports = function (Categories) { - Categories.purge = function (cid, uid, callback) { async.waterfall([ function (next) { @@ -17,7 +16,7 @@ module.exports = function (Categories) { async.eachLimit(tids, 10, function (tid, next) { topics.purgePostsAndTopic(tid, uid, next); }, next); - }, {alwaysStartAt: 0}, next); + }, { alwaysStartAt: 0 }, next); }, function (next) { Categories.getPinnedTids('cid:' + cid + ':tids:pinned', 0, -1, next); @@ -33,7 +32,7 @@ module.exports = function (Categories) { function (next) { plugins.fireHook('action:category.delete', cid); next(); - } + }, ], callback); }; @@ -55,14 +54,14 @@ module.exports = function (Categories) { 'cid:' + cid + ':ignorers', 'cid:' + cid + ':children', 'cid:' + cid + ':tag:whitelist', - 'category:' + cid + 'category:' + cid, ], next); }, function (next) { async.each(privileges.privilegeList, function (privilege, next) { groups.destroy('cid:' + cid + ':privileges:' + privilege, next); }, next); - } + }, ], function (err) { callback(err); }); @@ -77,7 +76,7 @@ module.exports = function (Categories) { }, children: function (next) { db.getSortedSetRange('cid:' + cid + ':children', 0, -1, next); - } + }, }, next); }, function (results, next) { @@ -94,14 +93,14 @@ module.exports = function (Categories) { }, function (next) { db.sortedSetAdd('cid:0:children', cid, cid, next); - } + }, ], next); }, next); - } + }, ], next); - } + }, ], function (err) { callback(err); }); } -}; \ No newline at end of file +}; diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index 831991d61a..c38fec527e 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -14,7 +14,6 @@ var batch = require('../batch'); module.exports = function (Categories) { - Categories.getRecentReplies = function (cid, uid, count, callback) { if (!parseInt(count, 10)) { return callback(null, []); @@ -28,8 +27,8 @@ module.exports = function (Categories) { privileges.posts.filter('read', pids, uid, next); }, function (pids, next) { - posts.getPostSummaryByPids(pids, uid, {stripTags: true}, next); - } + posts.getPostSummaryByPids(pids, uid, { stripTags: true }, next); + }, ], callback); }; @@ -40,7 +39,7 @@ module.exports = function (Categories) { }, numRecentReplies: function (next) { db.getObjectField('category:' + cid, 'numRecentReplies', next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -61,7 +60,7 @@ module.exports = function (Categories) { }, function (next) { db.sortedSetAdd('cid:' + cid + ':recent_tids', Date.now(), tid, next); - } + }, ], callback); }); }; @@ -95,7 +94,7 @@ module.exports = function (Categories) { bubbleUpChildrenPosts(categoryData); next(); - } + }, ], callback); }; @@ -131,17 +130,19 @@ module.exports = function (Categories) { results.teasers.forEach(function (teaser, index) { if (teaser) { teaser.cid = topicData[index].cid; - teaser.parentCid = parseInt(parentCids[teaser.cid]) || 0; - teaser.tid = teaser.uid = teaser.user.uid = undefined; + teaser.parentCid = parseInt(parentCids[teaser.cid], 10) || 0; + teaser.tid = undefined; + teaser.uid = undefined; + teaser.user.uid = undefined; teaser.topic = { slug: topicData[index].slug, - title: validator.escape(String(topicData[index].title)) + title: validator.escape(String(topicData[index].title)), }; } }); results.teasers = results.teasers.filter(Boolean); next(null, results.teasers); - } + }, ], callback); } @@ -211,9 +212,9 @@ module.exports = function (Categories) { }, function (next) { db.sortedSetAdd('cid:' + cid + ':pids', timestamps, pids, next); - } + }, ], next); - } + }, ], next); }, function (err) { if (err) { @@ -238,7 +239,7 @@ module.exports = function (Categories) { }, function (next) { db.incrObjectFieldBy('category:' + newCid, 'post_count', postCount, next); - } + }, ], function (err) { if (err) { winston.error(err.message); @@ -248,4 +249,3 @@ module.exports = function (Categories) { } }; - diff --git a/src/categories/topics.js b/src/categories/topics.js index 9e477e51ef..a346307e9c 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -7,7 +7,6 @@ var topics = require('../topics'); var plugins = require('../plugins'); module.exports = function (Categories) { - Categories.getCategoryTopics = function (data, callback) { async.waterfall([ function (next) { @@ -21,23 +20,23 @@ module.exports = function (Categories) { }, function (topics, next) { if (!Array.isArray(topics) || !topics.length) { - return next(null, {topics: [], uid: data.uid}); + return next(null, { topics: [], uid: data.uid }); } - for (var i = 0; i < topics.length; ++i) { + for (var i = 0; i < topics.length; i += 1) { topics[i].index = data.start + i; } - plugins.fireHook('filter:category.topics.get', {cid: data.cid, topics: topics, uid: data.uid}, next); + plugins.fireHook('filter:category.topics.get', { cid: data.cid, topics: topics, uid: data.uid }, next); }, function (results, next) { - next(null, {topics: results.topics, nextStart: data.stop + 1}); - } + next(null, { topics: results.topics, nextStart: data.stop + 1 }); + }, ], callback); }; Categories.getTopicIds = function (cid, set, reverse, start, stop, callback) { - var pinnedTids; + var pinnedTids; var pinnedCount; var totalPinnedCount; @@ -65,7 +64,7 @@ module.exports = function (Categories) { stop = stop === -1 ? stop : start + normalTidsToGet - 1; if (Array.isArray(set)) { - db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({sets: set, start: start, stop: stop}, next); + db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next); } else { db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next); } @@ -76,7 +75,7 @@ module.exports = function (Categories) { }); next(null, pinnedTids.concat(normalTids)); - } + }, ], callback); }; @@ -132,15 +131,14 @@ module.exports = function (Categories) { }, function (next) { db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next); - } + }, ], function (err) { next(err); }); }, function (next) { Categories.updateRecentTid(cid, postData.tid, next); - } + }, ], callback); }; - }; diff --git a/src/categories/unread.js b/src/categories/unread.js index 3a1ba27277..1ef6ee40b5 100644 --- a/src/categories/unread.js +++ b/src/categories/unread.js @@ -1,11 +1,8 @@ +'use strict'; -"use strict"; - -var async = require('async'); var db = require('../database'); module.exports = function (Categories) { - Categories.markAsRead = function (cids, uid, callback) { callback = callback || function () {}; if (!Array.isArray(cids) || !cids.length) { @@ -43,7 +40,7 @@ module.exports = function (Categories) { Categories.hasReadCategories = function (cids, uid, callback) { var sets = []; - for (var i = 0, ii = cids.length; i < ii; i++) { + for (var i = 0, ii = cids.length; i < ii; i += 1) { sets.push('cid:' + cids[i] + ':read_by_uid'); } @@ -53,5 +50,4 @@ module.exports = function (Categories) { Categories.hasReadCategory = function (cid, uid, callback) { db.isSetMember('cid:' + cid + ':read_by_uid', uid, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/categories/update.js b/src/categories/update.js index afaad6d974..04bf0e2235 100644 --- a/src/categories/update.js +++ b/src/categories/update.js @@ -10,9 +10,7 @@ var translator = require('../../public/src/modules/translator'); var plugins = require('../plugins'); module.exports = function (Categories) { - Categories.update = function (modified, callback) { - var cids = Object.keys(modified); async.each(cids, function (cid, next) { @@ -43,7 +41,7 @@ module.exports = function (Categories) { } }, function (next) { - plugins.fireHook('filter:category.update', {category: modifiedFields}, next); + plugins.fireHook('filter:category.update', { category: modifiedFields }, next); }, function (categoryData, next) { category = categoryData.category; @@ -59,9 +57,9 @@ module.exports = function (Categories) { }, next); }, function (next) { - plugins.fireHook('action:category.update', {cid: cid, modified: category}); + plugins.fireHook('action:category.update', { cid: cid, modified: category }); next(); - } + }, ], callback); } @@ -84,7 +82,7 @@ module.exports = function (Categories) { } else { next(); } - } + }, ], callback); } @@ -108,9 +106,9 @@ module.exports = function (Categories) { }, function (next) { db.setObjectField('category:' + cid, 'parentCid', newParent, next); - } + }, ], next); - } + }, ], function (err) { callback(err); }); @@ -131,7 +129,7 @@ module.exports = function (Categories) { return index; }); db.sortedSetAdd('cid:' + cid + ':tag:whitelist', scores, tags, next); - } + }, ], callback); } @@ -148,9 +146,9 @@ module.exports = function (Categories) { function (next) { parentCid = parseInt(parentCid, 10) || 0; db.sortedSetAdd('cid:' + parentCid + ':children', order, cid, next); - } + }, ], next); - } + }, ], function (err) { callback(err); }); @@ -163,8 +161,7 @@ module.exports = function (Categories) { }, function (parsedDescription, next) { Categories.setCategoryField(cid, 'descriptionParsed', parsedDescription, next); - } + }, ], callback); }; - }; diff --git a/src/controllers/404.js b/src/controllers/404.js new file mode 100644 index 0000000000..bc4e2e1d00 --- /dev/null +++ b/src/controllers/404.js @@ -0,0 +1,47 @@ +'use strict'; + +var nconf = require('nconf'); +var winston = require('winston'); +var validator = require('validator'); + +var meta = require('../meta'); +var plugins = require('../plugins'); + +exports.handle404 = function (req, res) { + var relativePath = nconf.get('relative_path'); + var isClientScript = new RegExp('^' + relativePath + '\\/assets\\/src\\/.+\\.js'); + + if (plugins.hasListeners('action:meta.override404')) { + return plugins.fireHook('action:meta.override404', { + req: req, + res: res, + error: {}, + }); + } + + if (isClientScript.test(req.url)) { + res.type('text/javascript').status(200).send(''); + } else if (req.path.startsWith(relativePath + '/assets/uploads') || (req.get('accept') && req.get('accept').indexOf('text/html') === -1) || req.path === '/favicon.ico') { + meta.errors.log404(req.path || ''); + res.sendStatus(404); + } else if (req.accepts('html')) { + if (process.env.NODE_ENV === 'development') { + winston.warn('Route requested but not found: ' + req.url); + } + + meta.errors.log404(req.path.replace(/^\/api/, '') || ''); + res.status(404); + + var path = String(req.path || ''); + + if (res.locals.isAPI) { + return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' }); + } + var middleware = require('../middleware'); + middleware.buildHeader(req, res, function () { + res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' }); + }); + } else { + res.status(404).type('txt').send('Not found'); + } +}; diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 2c99a981c3..a7aa1716b4 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -10,7 +10,7 @@ var accountsController = { posts: require('./accounts/posts'), notifications: require('./accounts/notifications'), chats: require('./accounts/chats'), - session: require('./accounts/session') + session: require('./accounts/session'), }; module.exports = accountsController; diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js index c951bafdbd..8ffac0a4dc 100644 --- a/src/controllers/accounts/chats.js +++ b/src/controllers/accounts/chats.js @@ -21,7 +21,7 @@ chatsController.get = function (req, res, callback) { function (next) { async.parallel({ uid: async.apply(user.getUidByUserslug, req.params.userslug), - username: async.apply(user.getUsernameByUserslug, req.params.userslug) + username: async.apply(user.getUsernameByUserslug, req.params.userslug), }, next); }, function (results, next) { @@ -45,7 +45,7 @@ chatsController.get = function (req, res, callback) { nextStart: recentChats.nextStart, allowed: true, title: '[[pages:chats]]', - breadcrumbs: helpers.buildBreadcrumbs([{text: username, url: '/user/' + req.params.userslug}, {text: '[[pages:chats]]'}]) + breadcrumbs: helpers.buildBreadcrumbs([{ text: username, url: '/user/' + req.params.userslug }, { text: '[[pages:chats]]' }]), }); } messaging.isUserInRoom(req.uid, req.params.roomid, next); @@ -62,10 +62,10 @@ chatsController.get = function (req, res, callback) { callerUid: req.uid, uid: uid, roomId: req.params.roomid, - isNew: false - }) + isNew: false, + }), }, next); - } + }, ], function (err, data) { if (err) { return callback(err); @@ -87,9 +87,9 @@ chatsController.get = function (req, res, callback) { room.usernames = messaging.generateUsernames(room.users, req.uid); room.title = room.roomName || room.usernames || '[[pages:chats]]'; room.breadcrumbs = helpers.buildBreadcrumbs([ - {text: username, url: '/user/' + req.params.userslug}, - {text: '[[pages:chats]]', url: '/user/' + req.params.userslug + '/chats'}, - {text: room.roomName || room.usernames || '[[pages:chats]]'} + { text: username, url: '/user/' + req.params.userslug }, + { text: '[[pages:chats]]', url: '/user/' + req.params.userslug + '/chats' }, + { text: room.roomName || room.usernames || '[[pages:chats]]' }, ]); room.maximumUsersInChatRoom = parseInt(meta.config.maximumUsersInChatRoom, 10) || 0; room.maximumChatMessageLength = parseInt(meta.config.maximumChatMessageLength, 10) || 1000; @@ -114,5 +114,4 @@ chatsController.redirectToChat = function (req, res, next) { }; - -module.exports = chatsController; \ No newline at end of file +module.exports = chatsController; diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 58409060e4..3c2e57bec4 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -2,7 +2,6 @@ var async = require('async'); var fs = require('fs'); -var nconf = require('nconf'); var winston = require('winston'); var db = require('../../database'); @@ -25,7 +24,7 @@ editController.get = function (req, res, callback) { userData.maximumSignatureLength = parseInt(meta.config.maximumSignatureLength, 10) || 255; userData.maximumAboutMeLength = parseInt(meta.config.maximumAboutMeLength, 10) || 1000; userData.maximumProfileImageSize = parseInt(meta.config.maximumProfileImageSize, 10); - userData.allowProfileImageUploads = parseInt(meta.config.allowProfileImageUploads) === 1; + userData.allowProfileImageUploads = parseInt(meta.config.allowProfileImageUploads, 10) === 1; userData.allowAccountDelete = parseInt(meta.config.allowAccountDelete, 10) === 1; userData.profileImageDimension = parseInt(meta.config.profileImageDimension, 10) || 128; @@ -37,12 +36,15 @@ editController.get = function (req, res, callback) { }); userData.title = '[[pages:account/edit, ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{ - text: userData.username, - url: '/user/' + userData.userslug - }, { - text: '[[user:edit]]' - }]); + userData.breadcrumbs = helpers.buildBreadcrumbs([ + { + text: userData.username, + url: '/user/' + userData.userslug, + }, + { + text: '[[user:edit]]', + }, + ]); userData.editButtons = []; plugins.fireHook('filter:user.account.edit', userData, function (err, userData) { @@ -81,15 +83,19 @@ function renderRoute(name, req, res, next) { } userData.title = '[[pages:account/edit/' + name + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{ - text: userData.username, - url: '/user/' + userData.userslug - }, { - text: '[[user:edit]]', - url: '/user/' + userData.userslug + '/edit' - }, { - text: '[[user:' + name + ']]' - }]); + userData.breadcrumbs = helpers.buildBreadcrumbs([ + { + text: userData.username, + url: '/user/' + userData.userslug, + }, + { + text: '[[user:edit]]', + url: '/user/' + userData.userslug + '/edit', + }, + { + text: '[[user:' + name + ']]', + }, + ]); res.render('account/edit/' + name, userData); }); @@ -107,7 +113,7 @@ function getUserData(req, next, callback) { return callback(); } db.getObjectField('user:' + userData.uid, 'password', next); - } + }, ], function (err, password) { if (err) { return callback(err); @@ -138,7 +144,7 @@ editController.uploadPicture = function (req, res, next) { } user.uploadPicture(updateUid, userPhoto, next); - } + }, ], function (err, image) { fs.unlink(userPhoto.path, function (err) { if (err) { @@ -151,7 +157,7 @@ editController.uploadPicture = function (req, res, next) { res.json([{ name: userPhoto.name, - url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url + url: image.url, }]); }); }; @@ -161,14 +167,14 @@ editController.uploadCoverPicture = function (req, res, next) { user.updateCoverPicture({ file: req.files.files[0], - uid: params.uid + uid: params.uid, }, function (err, image) { if (err) { return next(err); } res.json([{ - url: image.url + url: image.url, }]); }); }; diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js index 7d1e91b5e2..eac274136d 100644 --- a/src/controllers/accounts/follow.js +++ b/src/controllers/accounts/follow.js @@ -36,7 +36,7 @@ function getFollow(tpl, name, req, res, callback) { } var method = name === 'following' ? 'getFollowing' : 'getFollowers'; user[method](userData.uid, start, stop, next); - } + }, ], function (err, users) { if (err) { return callback(err); @@ -47,10 +47,10 @@ function getFollow(tpl, name, req, res, callback) { var count = name === 'following' ? userData.followingCount : userData.followerCount; var pageCount = Math.ceil(count / resultsPerPage); userData.pagination = pagination.create(page, pageCount); - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:' + name + ']]'}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:' + name + ']]' }]); res.render(tpl, userData); }); } -module.exports = followController; \ No newline at end of file +module.exports = followController; diff --git a/src/controllers/accounts/groups.js b/src/controllers/accounts/groups.js index 038d63de1d..650c510fc9 100644 --- a/src/controllers/accounts/groups.js +++ b/src/controllers/accounts/groups.js @@ -38,7 +38,7 @@ groupsController.get = function (req, res, callback) { group.members = members[index]; }); next(); - } + }, ], function (err) { if (err) { return callback(err); @@ -46,9 +46,9 @@ groupsController.get = function (req, res, callback) { userData.groups = groupsData; userData.title = '[[pages:account/groups, ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[global:header.groups]]'}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[global:header.groups]]' }]); res.render('account/groups', userData); }); }; -module.exports = groupsController; \ No newline at end of file +module.exports = groupsController; diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 2ef476a4ef..1ee9a08678 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -52,14 +52,14 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { plugins.fireHook('filter:user.profileLinks', [], next); }, profile_menu: function (next) { - plugins.fireHook('filter:user.profileMenu', {uid: uid, callerUID: callerUID, links: []}, next); + plugins.fireHook('filter:user.profileMenu', { uid: uid, callerUID: callerUID, links: [] }, next); }, groups: function (next) { groups.getUserGroups([uid], next); }, sso: function (next) { - plugins.fireHook('filter:auth.list', {uid: uid, associations: []}, next); - } + plugins.fireHook('filter:auth.list', { uid: uid, associations: [] }, next); + }, }, next); }, function (results, next) { @@ -144,7 +144,7 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { userData['email:disableEdit'] = !userData.isAdmin && parseInt(meta.config['email:disableEdit'], 10) === 1; next(null, userData); - } + }, ], callback); }; diff --git a/src/controllers/accounts/info.js b/src/controllers/accounts/info.js index 77ab2f275e..e852ebc3df 100644 --- a/src/controllers/accounts/info.js +++ b/src/controllers/accounts/info.js @@ -23,9 +23,9 @@ infoController.get = function (req, res, callback) { history: async.apply(user.getModerationHistory, userData.uid), sessions: async.apply(user.auth.getSessions, userData.uid, req.sessionID), usernames: async.apply(user.getHistory, 'user:' + userData.uid + ':usernames'), - emails: async.apply(user.getHistory, 'user:' + userData.uid + ':emails') + emails: async.apply(user.getHistory, 'user:' + userData.uid + ':emails'), }, next); - } + }, ], function (err, data) { if (err) { return callback(err); @@ -36,10 +36,10 @@ infoController.get = function (req, res, callback) { userData.usernames = data.usernames; userData.emails = data.emails; userData.title = '[[pages:account/info]]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:account_info]]'}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:account_info]]' }]); res.render('account/info', userData); }); }; -module.exports = infoController; \ No newline at end of file +module.exports = infoController; diff --git a/src/controllers/accounts/notifications.js b/src/controllers/accounts/notifications.js index 50a5a5913b..6184ec056d 100644 --- a/src/controllers/accounts/notifications.js +++ b/src/controllers/accounts/notifications.js @@ -14,7 +14,7 @@ notificationsController.get = function (req, res, next) { notifications: notifications, nextStart: 40, title: '[[pages:notifications]]', - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:notifications]]'}]) + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:notifications]]' }]), }); }); }; diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index 9875387997..2f603b8015 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -18,44 +18,44 @@ var templateToData = { set: 'bookmarks', type: 'posts', noItemsFoundKey: '[[topic:bookmarks.has_no_bookmarks]]', - crumb: '[[user:bookmarks]]' + crumb: '[[user:bookmarks]]', }, 'account/posts': { set: 'posts', type: 'posts', noItemsFoundKey: '[[user:has_no_posts]]', - crumb: '[[global:posts]]' + crumb: '[[global:posts]]', }, 'account/upvoted': { set: 'upvote', type: 'posts', noItemsFoundKey: '[[user:has_no_upvoted_posts]]', - crumb: '[[global:upvoted]]' + crumb: '[[global:upvoted]]', }, 'account/downvoted': { set: 'downvote', type: 'posts', noItemsFoundKey: '[[user:has_no_downvoted_posts]]', - crumb: '[[global:downvoted]]' + crumb: '[[global:downvoted]]', }, 'account/best': { set: 'posts:votes', type: 'posts', noItemsFoundKey: '[[user:has_no_voted_posts]]', - crumb: '[[global:best]]' + crumb: '[[global:best]]', }, 'account/watched': { set: 'followed_tids', type: 'topics', noItemsFoundKey: '[[user:has_no_watched_topics]]', - crumb: '[[user:watched]]' + crumb: '[[user:watched]]', }, 'account/topics': { set: 'topics', type: 'topics', noItemsFoundKey: '[[user:has_no_topics]]', - crumb: '[[global:topics]]' - } + crumb: '[[global:topics]]', + }, }; postsController.getBookmarks = function (req, res, next) { @@ -101,7 +101,7 @@ function getFromUserSet(template, req, res, callback) { }, userData: function (next) { accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); - } + }, }, next); }, function (results, next) { @@ -127,9 +127,9 @@ function getFromUserSet(template, req, res, callback) { var start = (page - 1) * itemsPerPage; var stop = start + itemsPerPage - 1; data.method(setName, req.uid, start, stop, next); - } + }, }, next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -143,10 +143,10 @@ function getFromUserSet(template, req, res, callback) { userData.noItemsFoundKey = data.noItemsFoundKey; userData.title = '[[pages:' + data.template + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: data.crumb}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: data.crumb }]); res.render(data.template, userData); }); } -module.exports = postsController; \ No newline at end of file +module.exports = postsController; diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index e95fedd0d1..1fc092a5f4 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -62,7 +62,7 @@ profileController.get = function (req, res, callback) { } else { next(); } - } + }, }, next); }, function (results, next) { @@ -76,7 +76,7 @@ profileController.get = function (req, res, callback) { userData.hasPrivateChat = results.hasPrivateChat; userData.aboutme = results.aboutme; userData.nextStart = results.posts.nextStart; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username }]); userData.title = userData.username; var pageCount = Math.ceil(userData.postcount / itemsPerPage); userData.pagination = pagination.create(page, pageCount, req.query); @@ -92,21 +92,21 @@ profileController.get = function (req, res, callback) { res.locals.metaTags = [ { - name: "title", - content: userData.fullname || userData.username + name: 'title', + content: userData.fullname || userData.username, }, { - name: "description", - content: plainAboutMe + name: 'description', + content: plainAboutMe, }, { property: 'og:title', - content: userData.fullname || userData.username + content: userData.fullname || userData.username, }, { property: 'og:description', - content: plainAboutMe - } + content: plainAboutMe, + }, ]; if (userData.picture) { @@ -114,12 +114,12 @@ profileController.get = function (req, res, callback) { { property: 'og:image', content: userData.picture, - noEscape: true + noEscape: true, }, { - property: "og:image:url", + property: 'og:image:url', content: userData.picture, - noEscape: true + noEscape: true, } ); } @@ -127,8 +127,8 @@ profileController.get = function (req, res, callback) { return group && group.name === userData.groupTitle; }); - plugins.fireHook('filter:user.account', {userData: userData, uid: req.uid}, next); - } + plugins.fireHook('filter:user.account', { userData: userData, uid: req.uid }, next); + }, ], function (err, results) { if (err) { return callback(err); @@ -137,4 +137,4 @@ profileController.get = function (req, res, callback) { }); }; -module.exports = profileController; \ No newline at end of file +module.exports = profileController; diff --git a/src/controllers/accounts/session.js b/src/controllers/accounts/session.js index e8123820ee..809cdb6dad 100644 --- a/src/controllers/accounts/session.js +++ b/src/controllers/accounts/session.js @@ -42,14 +42,13 @@ sessionController.revoke = function (req, res, next) { } user.auth.revokeSession(_id, uid, next); - } + }, ], function (err) { if (err) { return res.status(500).send(err.message); - } else { - return res.sendStatus(200); } + return res.sendStatus(200); }); }; -module.exports = sessionController; \ No newline at end of file +module.exports = sessionController; diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 68cef8be5f..2f360f883c 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -39,7 +39,7 @@ settingsController.get = function (req, res, callback) { }, soundsMapping: function (next) { meta.sounds.getUserSoundMap(userData.uid, next); - } + }, }, next); }, function (results, next) { @@ -53,7 +53,7 @@ settingsController.get = function (req, res, callback) { 'chat-outgoing', ]; var aliases = { - 'notification': 'notificationSound', + notification: 'notificationSound', 'chat-incoming': 'incomingChatSound', 'chat-outgoing': 'outgoingChatSound', }; @@ -93,38 +93,39 @@ settingsController.get = function (req, res, callback) { userData.customSettings = data.customSettings; userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; next(); - } + }, ], function (err) { if (err) { return callback(err); } userData.dailyDigestFreqOptions = [ - { value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq }, - { value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq }, - { value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq }, - { value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq } + { value: 'off', name: '[[user:digest_off]]', selected: userData.settings.dailyDigestFreq === 'off' }, + { value: 'day', name: '[[user:digest_daily]]', selected: userData.settings.dailyDigestFreq === 'day' }, + { value: 'week', name: '[[user:digest_weekly]]', selected: userData.settings.dailyDigestFreq === 'week' }, + { value: 'month', name: '[[user:digest_monthly]]', selected: userData.settings.dailyDigestFreq === 'month' }, ]; userData.bootswatchSkinOptions = [ - { "name": "Default", "value": "default" }, - { "name": "Cerulean", "value": "cerulean" }, - { "name": "Cosmo", "value": "cosmo" }, - { "name": "Cyborg", "value": "cyborg" }, - { "name": "Darkly", "value": "darkly" }, - { "name": "Flatly", "value": "flatly" }, - { "name": "Journal", "value": "journal" }, - { "name": "Lumen", "value": "lumen" }, - { "name": "Paper", "value": "paper" }, - { "name": "Readable", "value": "readable" }, - { "name": "Sandstone", "value": "sandstone" }, - { "name": "Simplex", "value": "simplex" }, - { "name": "Slate", "value": "slate" }, - { "name": "Spacelab", "value": "spacelab" }, - { "name": "Superhero", "value": "superhero" }, - { "name": "United", "value": "united" }, - { "name": "Yeti", "value": "yeti" } + { name: 'No skin', value: 'noskin' }, + { name: 'Default', value: 'default' }, + { name: 'Cerulean', value: 'cerulean' }, + { name: 'Cosmo', value: 'cosmo' }, + { name: 'Cyborg', value: 'cyborg' }, + { name: 'Darkly', value: 'darkly' }, + { name: 'Flatly', value: 'flatly' }, + { name: 'Journal', value: 'journal' }, + { name: 'Lumen', value: 'lumen' }, + { name: 'Paper', value: 'paper' }, + { name: 'Readable', value: 'readable' }, + { name: 'Sandstone', value: 'sandstone' }, + { name: 'Simplex', value: 'simplex' }, + { name: 'Slate', value: 'slate' }, + { name: 'Spacelab', value: 'spacelab' }, + { name: 'Superhero', value: 'superhero' }, + { name: 'United', value: 'united' }, + { name: 'Yeti', value: 'yeti' }, ]; var isCustom = true; @@ -140,9 +141,9 @@ settingsController.get = function (req, res, callback) { } userData.homePageRoutes.push({ - route: 'custom', - name: 'Custom', - selected: isCustom + route: 'custom', + name: 'Custom', + selected: isCustom, }); userData.bootswatchSkinOptions.forEach(function (skin) { @@ -160,7 +161,7 @@ settingsController.get = function (req, res, callback) { userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search'); userData.title = '[[pages:account/settings]]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:settings]]'}]); + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:settings]]' }]); res.render('account/settings', userData); }); @@ -182,36 +183,36 @@ function getHomePageRoutes(callback) { categoryData = categoryData.map(function (category) { return { route: 'category/' + category.slug, - name: 'Category: ' + category.name + name: 'Category: ' + category.name, }; }); categoryData = categoryData || []; - plugins.fireHook('filter:homepage.get', {routes: [ + plugins.fireHook('filter:homepage.get', { routes: [ { route: 'categories', - name: 'Categories' + name: 'Categories', }, { route: 'unread', - name: 'Unread' + name: 'Unread', }, { route: 'recent', - name: 'Recent' + name: 'Recent', }, { route: 'popular', - name: 'Popular' - } - ].concat(categoryData)}, next); + name: 'Popular', + }, + ].concat(categoryData) }, next); }, function (data, next) { next(null, data.routes); - } + }, ], callback); } -module.exports = settingsController; \ No newline at end of file +module.exports = settingsController; diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 7f622466cd..056a7025aa 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var adminController = { dashboard: require('./admin/dashboard'), @@ -10,7 +10,7 @@ var adminController = { appearance: require('./admin/appearance'), extend: { widgets: require('./admin/widgets'), - rewards: require('./admin/rewards') + rewards: require('./admin/rewards'), }, events: require('./admin/events'), logs: require('./admin/logs'), @@ -28,7 +28,7 @@ var adminController = { themes: require('./admin/themes'), users: require('./admin/users'), uploads: require('./admin/uploads'), - info: require('./admin/info') + info: require('./admin/info'), }; diff --git a/src/controllers/admin/appearance.js b/src/controllers/admin/appearance.js index 8956bd175d..021733d417 100644 --- a/src/controllers/admin/appearance.js +++ b/src/controllers/admin/appearance.js @@ -1,8 +1,8 @@ -"use strict"; +'use strict'; var appearanceController = {}; -appearanceController.get = function (req, res, next) { +appearanceController.get = function (req, res) { var term = req.params.term ? req.params.term : 'themes'; res.render('admin/appearance/' + term, {}); diff --git a/src/controllers/admin/blacklist.js b/src/controllers/admin/blacklist.js index 73e4d6c333..7ce4edda49 100644 --- a/src/controllers/admin/blacklist.js +++ b/src/controllers/admin/blacklist.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var meta = require('../../meta'); @@ -11,7 +11,7 @@ blacklistController.get = function (req, res, next) { } res.render('admin/manage/ip-blacklist', { rules: rules, - title: '[[pages:ip-blacklist]]' + title: '[[pages:ip-blacklist]]', }); }); }; diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js index 21ef6ff086..dce16818f8 100644 --- a/src/controllers/admin/cache.js +++ b/src/controllers/admin/cache.js @@ -2,7 +2,7 @@ var cacheController = {}; -cacheController.get = function (req, res, next) { +cacheController.get = function (req, res) { var postCache = require('../../posts/cache'); var groupCache = require('../../groups').cache; @@ -19,17 +19,17 @@ cacheController.get = function (req, res, next) { max: postCache.max, itemCount: postCache.itemCount, percentFull: percentFull, - avgPostSize: avgPostSize + avgPostSize: avgPostSize, }, groupCache: { length: groupCache.length, max: groupCache.max, itemCount: groupCache.itemCount, percentFull: ((groupCache.length / groupCache.max) * 100).toFixed(2), - dump: req.query.debug ? JSON.stringify(groupCache.dump(), null, 4) : false - } + dump: req.query.debug ? JSON.stringify(groupCache.dump(), null, 4) : false, + }, }); }; -module.exports = cacheController; \ No newline at end of file +module.exports = cacheController; diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js index 8a59bb0b4e..4a60fc14e2 100644 --- a/src/controllers/admin/categories.js +++ b/src/controllers/admin/categories.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -14,7 +14,7 @@ var categoriesController = {}; categoriesController.get = function (req, res, next) { async.parallel({ category: async.apply(categories.getCategories, [req.params.category_id], req.user.uid), - privileges: async.apply(privileges.categories.list, req.params.category_id) + privileges: async.apply(privileges.categories.list, req.params.category_id), }, function (err, data) { if (err) { return next(err); @@ -32,13 +32,13 @@ categoriesController.get = function (req, res, next) { data.category.name = translator.escape(String(data.category.name)); res.render('admin/manage/category', { category: data.category, - privileges: data.privileges + privileges: data.privileges, }); }); }); }; -categoriesController.getAll = function (req, res, next) { +categoriesController.getAll = function (req, res) { // Categories list will be rendered on client side with recursion, etc. res.render('admin/manage/categories', {}); }; @@ -46,7 +46,7 @@ categoriesController.getAll = function (req, res, next) { categoriesController.getAnalytics = function (req, res, next) { async.parallel({ name: async.apply(categories.getCategoryField, req.params.category_id, 'name'), - analytics: async.apply(analytics.getCategoryAnalytics, req.params.category_id) + analytics: async.apply(analytics.getCategoryAnalytics, req.params.category_id), }, function (err, data) { if (err) { return next(err); diff --git a/src/controllers/admin/dashboard.js b/src/controllers/admin/dashboard.js index 2ffbea0e98..70149e580e 100644 --- a/src/controllers/admin/dashboard.js +++ b/src/controllers/admin/dashboard.js @@ -20,26 +20,26 @@ dashboardController.get = function (req, res, next) { { done: !meta.reloadRequired, doneText: '[[admin/general/dashboard:restart-not-required]]', - notDoneText:'[[admin/general/dashboard:restart-required]]' + notDoneText: '[[admin/general/dashboard:restart-required]]', }, { done: plugins.hasListeners('filter:search.query'), doneText: '[[admin/general/dashboard:search-plugin-installed]]', - notDoneText:'[[admin/general/dashboard:search-plugin-not-installed]]', + notDoneText: '[[admin/general/dashboard:search-plugin-not-installed]]', tooltip: '[[admin/general/dashboard:search-plugin-tooltip]]', - link:'/admin/extend/plugins' - } + link: '/admin/extend/plugins', + }, ]; if (global.env !== 'production') { notices.push({ done: false, - notDoneText: '[[admin/general/dashboard:running-in-development]]' + notDoneText: '[[admin/general/dashboard:running-in-development]]', }); } plugins.fireHook('filter:admin.notices', notices, next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -47,7 +47,7 @@ dashboardController.get = function (req, res, next) { res.render('admin/general/dashboard', { version: nconf.get('version'), notices: results.notices, - stats: results.stats + stats: results.stats, }); }); }; @@ -65,7 +65,7 @@ function getStats(callback) { }, function (next) { getStatsForSet('topics:tid', 'topicCount', next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -83,7 +83,7 @@ function getStatsForSet(set, field, callback) { var terms = { day: 86400000, week: 604800000, - month: 2592000000 + month: 2592000000, }; var now = Date.now(); @@ -99,7 +99,7 @@ function getStatsForSet(set, field, callback) { }, alltime: function (next) { getGlobalField(field, next); - } + }, }, callback); } diff --git a/src/controllers/admin/database.js b/src/controllers/admin/database.js index 5a28b95ec4..9ce8a3c00f 100644 --- a/src/controllers/admin/database.js +++ b/src/controllers/admin/database.js @@ -6,7 +6,6 @@ var nconf = require('nconf'); var databaseController = {}; - databaseController.get = function (req, res, next) { async.parallel({ redis: function (next) { @@ -24,7 +23,7 @@ databaseController.get = function (req, res, next) { } else { next(); } - } + }, }, function (err, results) { if (err) { return next(err); @@ -33,4 +32,4 @@ databaseController.get = function (req, res, next) { }); }; -module.exports = databaseController; \ No newline at end of file +module.exports = databaseController; diff --git a/src/controllers/admin/errors.js b/src/controllers/admin/errors.js index 4cacd425c9..5a00e95537 100644 --- a/src/controllers/admin/errors.js +++ b/src/controllers/admin/errors.js @@ -11,7 +11,7 @@ var errorsController = {}; errorsController.get = function (req, res, next) { async.parallel({ 'not-found': async.apply(meta.errors.get, true), - analytics: async.apply(analytics.getErrorAnalytics) + analytics: async.apply(analytics.getErrorAnalytics), }, function (err, data) { if (err) { return next(err); @@ -24,7 +24,7 @@ errorsController.get = function (req, res, next) { errorsController.export = function (req, res, next) { async.waterfall([ async.apply(meta.errors.get, false), - async.apply(json2csv) + async.apply(json2csv), ], function (err, csv) { if (err) { return next(err); @@ -35,4 +35,4 @@ errorsController.export = function (req, res, next) { }; -module.exports = errorsController; \ No newline at end of file +module.exports = errorsController; diff --git a/src/controllers/admin/events.js b/src/controllers/admin/events.js index 8a4d63bad1..97838d2266 100644 --- a/src/controllers/admin/events.js +++ b/src/controllers/admin/events.js @@ -10,7 +10,6 @@ var eventsController = {}; eventsController.get = function (req, res, next) { - var page = parseInt(req.query.page, 10) || 1; var itemsPerPage = 20; var start = (page - 1) * itemsPerPage; @@ -22,7 +21,7 @@ eventsController.get = function (req, res, next) { }, events: function (next) { events.getEvents(start, stop, next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -33,10 +32,10 @@ eventsController.get = function (req, res, next) { res.render('admin/advanced/events', { events: results.events, pagination: pagination.create(page, pageCount), - next: 20 + next: 20, }); }); }; -module.exports = eventsController; \ No newline at end of file +module.exports = eventsController; diff --git a/src/controllers/admin/flags.js b/src/controllers/admin/flags.js index 03c9329fca..2191394b57 100644 --- a/src/controllers/admin/flags.js +++ b/src/controllers/admin/flags.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var validator = require('validator'); @@ -29,7 +29,7 @@ flagsController.get = function (req, res, next) { analytics: function (next) { analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30, next); }, - assignees: async.apply(user.getAdminsandGlobalModsandModerators) + assignees: async.apply(user.getAdminsandGlobalModsandModerators), }, function (err, results) { if (err) { return next(err); @@ -39,7 +39,7 @@ flagsController.get = function (req, res, next) { results.assignees = results.assignees.map(function (userObj) { return { uid: userObj.uid, - username: userObj.username + username: userObj.username, }; }); @@ -94,7 +94,7 @@ function getFlagData(req, res, callback) { } posts.getFlags(sets, cid, req.uid, start, stop, next); - } + }, ], callback); } diff --git a/src/controllers/admin/groups.js b/src/controllers/admin/groups.js index db940c8324..5e7dd1e78f 100644 --- a/src/controllers/admin/groups.js +++ b/src/controllers/admin/groups.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -6,12 +6,9 @@ var db = require('../../database'); var groups = require('../../groups'); var meta = require('../../meta'); var pagination = require('../../pagination'); -var helpers = require('../helpers'); - var groupsController = {}; - groupsController.list = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; var groupsPerPage = 20; @@ -28,14 +25,14 @@ groupsController.list = function (req, res, next) { pageCount = Math.ceil(groupNames.length / groupsPerPage); var start = (page - 1) * groupsPerPage; - var stop = start + groupsPerPage - 1; + var stop = start + groupsPerPage - 1; groupNames = groupNames.slice(start, stop + 1); groups.getGroupsData(groupNames, next); }, function (groupData, next) { - next(null, {groups: groupData, pagination: pagination.create(page, pageCount)}); - } + next(null, { groups: groupData, pagination: pagination.create(page, pageCount) }); + }, ], function (err, data) { if (err) { return next(err); @@ -44,7 +41,7 @@ groupsController.list = function (req, res, next) { res.render('admin/manage/groups', { groups: data.groups, pagination: data.pagination, - yourid: req.uid + yourid: req.uid, }); }); }; @@ -59,14 +56,14 @@ groupsController.get = function (req, res, callback) { if (!exists) { return callback(); } - groups.get(groupName, {uid: req.uid, truncateUserList: true, userListCount: 20}, next); - } + groups.get(groupName, { uid: req.uid, truncateUserList: true, userListCount: 20 }, next); + }, ], function (err, group) { if (err) { return callback(err); } group.isOwner = true; - res.render('admin/manage/group', {group: group, allowPrivateGroups: parseInt(meta.config.allowPrivateGroups, 10) === 1}); + res.render('admin/manage/group', { group: group, allowPrivateGroups: parseInt(meta.config.allowPrivateGroups, 10) === 1 }); }); }; diff --git a/src/controllers/admin/homepage.js b/src/controllers/admin/homepage.js index 9fdf3a2371..1450283847 100644 --- a/src/controllers/admin/homepage.js +++ b/src/controllers/admin/homepage.js @@ -25,37 +25,37 @@ homePageController.get = function (req, res, next) { categoryData = categoryData.map(function (category) { return { route: 'category/' + category.slug, - name: 'Category: ' + category.name + name: 'Category: ' + category.name, }; }); next(null, categoryData); - } + }, ], function (err, categoryData) { if (err || !categoryData) { categoryData = []; } - plugins.fireHook('filter:homepage.get', {routes: [ + plugins.fireHook('filter:homepage.get', { routes: [ { route: 'categories', - name: 'Categories' + name: 'Categories', }, { route: 'recent', - name: 'Recent' + name: 'Recent', }, { route: 'popular', - name: 'Popular' - } - ].concat(categoryData)}, function (err, data) { + name: 'Popular', + }, + ].concat(categoryData) }, function (err, data) { if (err) { return next(err); } data.routes.push({ route: '', - name: 'Custom' + name: 'Custom', }); res.render('admin/general/homepage', data); @@ -63,4 +63,4 @@ homePageController.get = function (req, res, next) { }); }; -module.exports = homePageController; \ No newline at end of file +module.exports = homePageController; diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index 8fa54ae4f0..88fef98b4b 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -13,7 +13,7 @@ var infoController = {}; var info = {}; -infoController.get = function (req, res, next) { +infoController.get = function (req, res) { info = {}; pubsub.publish('sync:node:info:start'); setTimeout(function () { @@ -22,9 +22,15 @@ infoController.get = function (req, res, next) { data.push(info[key]); }); data.sort(function (a, b) { - return (a.os.hostname < b.os.hostname) ? -1 : (a.os.hostname > b.os.hostname) ? 1 : 0; + if (a.os.hostname < b.os.hostname) { + return -1; + } + if (a.os.hostname > b.os.hostname) { + return 1; + } + return 0; }); - res.render('admin/development/info', {info: data, infoJSON: JSON.stringify(data, null, 4), host: os.hostname(), port: nconf.get('port')}); + res.render('admin/development/info', { info: data, infoJSON: JSON.stringify(data, null, 4), host: os.hostname(), port: nconf.get('port') }); }, 500); }; @@ -33,7 +39,7 @@ pubsub.on('sync:node:info:start', function () { if (err) { return winston.error(err); } - pubsub.publish('sync:node:info:end', {data: data, id: os.hostname() + ':' + nconf.get('port')}); + pubsub.publish('sync:node:info:end', { data: data, id: os.hostname() + ':' + nconf.get('port') }); }); }); @@ -49,7 +55,7 @@ function getNodeInfo(callback) { title: process.title, version: process.version, memoryUsage: process.memoryUsage(), - uptime: process.uptime() + uptime: process.uptime(), }, os: { hostname: os.hostname(), @@ -57,8 +63,8 @@ function getNodeInfo(callback) { platform: os.platform(), arch: os.arch(), release: os.release(), - load: os.loadavg().map(function (load) { return load.toFixed(2); }).join(', ') - } + load: os.loadavg().map(function (load) { return load.toFixed(2); }).join(', '), + }, }; async.parallel({ @@ -67,7 +73,7 @@ function getNodeInfo(callback) { }, gitInfo: function (next) { getGitInfo(next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -79,7 +85,7 @@ function getNodeInfo(callback) { } function getGitInfo(callback) { - function get(cmd, callback) { + function get(cmd, callback) { exec(cmd, function (err, stdout) { if (err) { winston.error(err); @@ -93,8 +99,8 @@ function getGitInfo(callback) { }, branch: function (next) { get('git rev-parse --abbrev-ref HEAD', next); - } + }, }, callback); } -module.exports = infoController; \ No newline at end of file +module.exports = infoController; diff --git a/src/controllers/admin/languages.js b/src/controllers/admin/languages.js index 2b458d1508..0ac4e98e99 100644 --- a/src/controllers/admin/languages.js +++ b/src/controllers/admin/languages.js @@ -17,9 +17,9 @@ languagesController.get = function (req, res, next) { }); res.render('admin/general/languages', { - languages: languages + languages: languages, }); }); }; -module.exports = languagesController; \ No newline at end of file +module.exports = languagesController; diff --git a/src/controllers/admin/logger.js b/src/controllers/admin/logger.js index 7ae327a858..0e8006bbeb 100644 --- a/src/controllers/admin/logger.js +++ b/src/controllers/admin/logger.js @@ -6,4 +6,4 @@ loggerController.get = function (req, res) { res.render('admin/development/logger', {}); }; -module.exports = loggerController; \ No newline at end of file +module.exports = loggerController; diff --git a/src/controllers/admin/logs.js b/src/controllers/admin/logs.js index 6723d3795f..c2c5166dd7 100644 --- a/src/controllers/admin/logs.js +++ b/src/controllers/admin/logs.js @@ -13,10 +13,10 @@ logsController.get = function (req, res, next) { } res.render('admin/advanced/logs', { - data: validator.escape(logs) + data: validator.escape(logs), }); }); }; -module.exports = logsController; \ No newline at end of file +module.exports = logsController; diff --git a/src/controllers/admin/navigation.js b/src/controllers/admin/navigation.js index 423f21721c..9c96444be3 100644 --- a/src/controllers/admin/navigation.js +++ b/src/controllers/admin/navigation.js @@ -20,4 +20,4 @@ navigationController.get = function (req, res, next) { }); }; -module.exports = navigationController; \ No newline at end of file +module.exports = navigationController; diff --git a/src/controllers/admin/plugins.js b/src/controllers/admin/plugins.js index f1a72720ac..4e8e1a415e 100644 --- a/src/controllers/admin/plugins.js +++ b/src/controllers/admin/plugins.js @@ -24,22 +24,22 @@ pluginsController.get = function (req, res, next) { next(null, plugins); }); - } + }, }, function (err, payload) { if (err) { return next(err); } var compatiblePkgNames = payload.compatible.map(function (pkgData) { - return pkgData.name; - }); + return pkgData.name; + }); - res.render('admin/extend/plugins' , { + res.render('admin/extend/plugins', { installed: payload.compatible.filter(function (plugin) { return plugin.installed; }), upgradeCount: payload.compatible.reduce(function (count, current) { if (current.installed && current.outdated) { - ++count; + count += 1; } return count; }, 0), @@ -48,9 +48,9 @@ pluginsController.get = function (req, res, next) { }), incompatible: payload.all.filter(function (plugin) { return compatiblePkgNames.indexOf(plugin.name) === -1; - }) + }), }); }); }; -module.exports = pluginsController; \ No newline at end of file +module.exports = pluginsController; diff --git a/src/controllers/admin/rewards.js b/src/controllers/admin/rewards.js index 8ff05c75b3..56c5ed3cd0 100644 --- a/src/controllers/admin/rewards.js +++ b/src/controllers/admin/rewards.js @@ -13,5 +13,4 @@ rewardsController.get = function (req, res, next) { }; - -module.exports = rewardsController; \ No newline at end of file +module.exports = rewardsController; diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js index 0d1f509631..55e5a1dfbf 100644 --- a/src/controllers/admin/settings.js +++ b/src/controllers/admin/settings.js @@ -11,12 +11,12 @@ settingsController.get = function (req, res, next) { var term = req.params.term ? req.params.term : 'general'; switch (req.params.term) { - case 'email': - renderEmail(req, res, next); - break; + case 'email': + renderEmail(req, res, next); + break; - default: - res.render('admin/settings/' + term); + default: + res.render('admin/settings/' + term); } }; @@ -47,11 +47,11 @@ function renderEmail(req, res, next) { path: path, fullpath: email, text: text, - original: original.toString() + original: original.toString(), }); }); }, next); - } + }, ], function (err, emails) { if (err) { return next(err); @@ -61,7 +61,7 @@ function renderEmail(req, res, next) { emails: emails, sendable: emails.filter(function (email) { return email.path.indexOf('_plaintext') === -1 && email.path.indexOf('partials') === -1; - }) + }), }); }); } diff --git a/src/controllers/admin/social.js b/src/controllers/admin/social.js index 11c7982701..da12f3341e 100644 --- a/src/controllers/admin/social.js +++ b/src/controllers/admin/social.js @@ -12,9 +12,9 @@ socialController.get = function (req, res, next) { } res.render('admin/general/social', { - posts: posts + posts: posts, }); }); }; -module.exports = socialController; \ No newline at end of file +module.exports = socialController; diff --git a/src/controllers/admin/sounds.js b/src/controllers/admin/sounds.js index b042048313..164bf4a427 100644 --- a/src/controllers/admin/sounds.js +++ b/src/controllers/admin/sounds.js @@ -1,23 +1,23 @@ 'use strict'; var plugins = require('../../plugins'); -var db = require('../../database'); +var meta = require('../../meta'); var soundsController = {}; soundsController.get = function (req, res, next) { - db.getObject('settings:sounds', function (err, settings) { + var types = [ + 'notification', + 'chat-incoming', + 'chat-outgoing', + ]; + meta.configs.getFields(types, function (err, settings) { if (err) { return next(err); } - + settings = settings || {}; - var types = [ - 'notification', - 'chat-incoming', - 'chat-outgoing', - ]; var output = {}; types.forEach(function (type) { @@ -44,4 +44,4 @@ soundsController.get = function (req, res, next) { }); }; -module.exports = soundsController; \ No newline at end of file +module.exports = soundsController; diff --git a/src/controllers/admin/tags.js b/src/controllers/admin/tags.js index a645e2ef11..f586e5f70c 100644 --- a/src/controllers/admin/tags.js +++ b/src/controllers/admin/tags.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var topics = require('../../topics'); @@ -10,7 +10,7 @@ tagsController.get = function (req, res, next) { return next(err); } - res.render('admin/manage/tags', {tags: tags}); + res.render('admin/manage/tags', { tags: tags }); }); }; diff --git a/src/controllers/admin/themes.js b/src/controllers/admin/themes.js index 4f6f3e1f3b..598cd7cf94 100644 --- a/src/controllers/admin/themes.js +++ b/src/controllers/admin/themes.js @@ -12,8 +12,8 @@ themesController.get = function (req, res, next) { return next(); } - var themeConfig = require(path.join(themeDir, 'theme.json')), - screenshotPath = path.join(themeDir, themeConfig.screenshot); + var themeConfig = require(path.join(themeDir, 'theme.json')); + var screenshotPath = path.join(themeDir, themeConfig.screenshot); if (themeConfig.screenshot && file.existsSync(screenshotPath)) { res.sendFile(screenshotPath); } else { @@ -22,4 +22,4 @@ themesController.get = function (req, res, next) { }); }; -module.exports = themesController; \ No newline at end of file +module.exports = themesController; diff --git a/src/controllers/admin/uploads.js b/src/controllers/admin/uploads.js index 0b7104f1de..02bd065c0b 100644 --- a/src/controllers/admin/uploads.js +++ b/src/controllers/admin/uploads.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var fs = require('fs'); var path = require('path'); @@ -31,7 +31,7 @@ uploadsController.uploadCategoryPicture = function (req, res, next) { } if (validateUpload(req, res, next, uploadedFile, allowedImageTypes)) { - var filename = 'category-' + params.cid + path.extname(uploadedFile.name); + var filename = 'category-' + params.cid + path.extname(uploadedFile.name); uploadImage(filename, 'category', uploadedFile, req, res, next); } }; @@ -51,15 +51,15 @@ uploadsController.uploadFavicon = function (req, res, next) { return next(err); } - res.json([{name: uploadedFile.name, url: image.url}]); + res.json([{ name: uploadedFile.name, url: image.url }]); }); } }; uploadsController.uploadTouchIcon = function (req, res, next) { - var uploadedFile = req.files.files[0], - allowedTypes = ['image/png'], - sizes = [36, 48, 72, 96, 144, 192]; + var uploadedFile = req.files.files[0]; + var allowedTypes = ['image/png']; + var sizes = [36, 48, 72, 96, 144, 192]; if (validateUpload(req, res, next, uploadedFile, allowedTypes)) { file.saveFileToLocal('touchicon-orig.png', 'system', uploadedFile.path, function (err, imageObj) { @@ -75,8 +75,8 @@ uploadsController.uploadTouchIcon = function (req, res, next) { path: path.join(nconf.get('upload_path'), 'system', 'touchicon-' + size + '.png'), extension: 'png', width: size, - height: size - }) + height: size, + }), ], next); }, function (err) { fs.unlink(uploadedFile.path, function (err) { @@ -89,7 +89,7 @@ uploadsController.uploadTouchIcon = function (req, res, next) { return next(err); } - res.json([{name: uploadedFile.name, url: imageObj.url}]); + res.json([{ name: uploadedFile.name, url: imageObj.url }]); }); }); } @@ -142,7 +142,7 @@ function validateUpload(req, res, next, uploadedFile, allowedTypes) { } }); - res.json({error: '[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]'}); + res.json({ error: '[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]' }); return false; } @@ -160,11 +160,11 @@ function uploadImage(filename, folder, uploadedFile, req, res, next) { return next(err); } - res.json([{name: uploadedFile.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); + res.json([{ name: uploadedFile.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url }]); } if (plugins.hasListeners('filter:uploadImage')) { - plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.user.uid}, done); + plugins.fireHook('filter:uploadImage', { image: uploadedFile, uid: req.user.uid }, done); } else { file.saveFileToLocal(filename, folder, uploadedFile.path, done); } diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index 0e67c7d64c..54d9ab93de 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var validator = require('validator'); @@ -15,10 +15,10 @@ var usersController = {}; var userFields = ['uid', 'username', 'userslug', 'email', 'postcount', 'joindate', 'banned', 'reputation', 'picture', 'flags', 'lastonline', 'email:confirmed']; -usersController.search = function (req, res, next) { +usersController.search = function (req, res) { res.render('admin/manage/users', { search_display: '', - users: [] + users: [], }); }; @@ -71,7 +71,7 @@ usersController.registrationQueue = function (req, res, next) { user.getRegistrationQueue(start, stop, next); }, customHeaders: function (next) { - plugins.fireHook('filter:admin.registrationQueue.customHeaders', {headers: []}, next); + plugins.fireHook('filter:admin.registrationQueue.customHeaders', { headers: [] }, next); }, invites: function (next) { async.waterfall([ @@ -97,14 +97,14 @@ usersController.registrationQueue = function (req, res, next) { invites.invitations = invites.invitations.map(function (email, i) { return { email: email, - username: usernames[index][i] === '[[global:guest]]' ? '' : usernames[index][i] + username: usernames[index][i] === '[[global:guest]]' ? '' : usernames[index][i], }; }); }); next(null, invitations); - } + }, ], next); - } + }, }, function (err, data) { if (err) { return next(err); @@ -142,9 +142,9 @@ function getUsers(set, section, min, max, req, res, next) { }, function (uids, next) { user.getUsersWithFields(uids, userFields, req.uid, next); - } + }, ], next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -157,7 +157,7 @@ function getUsers(set, section, min, max, req, res, next) { var data = { users: results.users, page: page, - pageCount: Math.max(1, Math.ceil(results.count / resultsPerPage)) + pageCount: Math.max(1, Math.ceil(results.count / resultsPerPage)), }; data[section] = true; render(req, res, data); @@ -181,7 +181,7 @@ usersController.getCSV = function (req, res, next) { events.log({ type: 'getUsersCSV', uid: req.user.uid, - ip: req.ip + ip: req.ip, }); user.getUsersCSV(function (err, data) { diff --git a/src/controllers/admin/widgets.js b/src/controllers/admin/widgets.js index c2d0d1e667..889fa1dcc6 100644 --- a/src/controllers/admin/widgets.js +++ b/src/controllers/admin/widgets.js @@ -13,4 +13,4 @@ widgetsController.get = function (req, res, next) { }; -module.exports = widgetsController; \ No newline at end of file +module.exports = widgetsController; diff --git a/src/controllers/api.js b/src/controllers/api.js index 1bbf3962c8..f7158481e7 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var validator = require('validator'); @@ -13,9 +13,8 @@ var privileges = require('../privileges'); var plugins = require('../plugins'); var widgets = require('../widgets'); var translator = require('../../public/src/modules/translator'); -var accountHelpers = require('../controllers/accounts/helpers'); -var apiController = {}; +var apiController = module.exports; apiController.getConfig = function (req, res, next) { var config = {}; @@ -62,7 +61,12 @@ apiController.getConfig = function (req, res, next) { config.categoryTopicSort = meta.config.categoryTopicSort || 'newest_to_oldest'; config.csrf_token = req.csrfToken(); config.searchEnabled = plugins.hasListeners('filter:search.query'); - config.bootswatchSkin = 'default'; + config.bootswatchSkin = meta.config.bootswatchSkin || 'noskin'; + config.defaultBootswatchSkin = meta.config.bootswatchSkin || 'noskin'; + + if (config.useOutgoingLinksPage) { + config.outgoingLinksWhitelist = meta.config['outgoingLinks:whitelist']; + } var timeagoCutoff = meta.config.timeagoCutoff === undefined ? 30 : meta.config.timeagoCutoff; config.timeagoCutoff = timeagoCutoff !== '' ? Math.max(0, parseInt(timeagoCutoff, 10)) : timeagoCutoff; @@ -71,7 +75,7 @@ apiController.getConfig = function (req, res, next) { enabled: parseInt(meta.config.cookieConsentEnabled, 10) === 1, message: translator.escape(meta.config.cookieConsentMessage || '[[global:cookies.message]]').replace(/\\/g, '\\\\'), dismiss: translator.escape(meta.config.cookieConsentDismiss || '[[global:cookies.accept]]').replace(/\\/g, '\\\\'), - link: translator.escape(meta.config.cookieConsentLink || '[[global:cookies.learn_more]]').replace(/\\/g, '\\\\') + link: translator.escape(meta.config.cookieConsentLink || '[[global:cookies.learn_more]]').replace(/\\/g, '\\\\'), }; async.waterfall([ @@ -91,9 +95,9 @@ apiController.getConfig = function (req, res, next) { config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort; config.topicSearchEnabled = settings.topicSearchEnabled || false; config.delayImageLoading = settings.delayImageLoading !== undefined ? settings.delayImageLoading : true; - config.bootswatchSkin = settings.bootswatchSkin || config.bootswatchSkin; + config.bootswatchSkin = (settings.bootswatchSkin && settings.bootswatchSkin !== 'default') ? settings.bootswatchSkin : config.bootswatchSkin; plugins.fireHook('filter:config.get', config, next); - } + }, ], function (err, config) { if (err) { return next(err); @@ -119,16 +123,16 @@ apiController.renderWidgets = function (req, res, next) { url: req.query.url, locations: req.query.locations, isMobile: req.query.isMobile === 'true', - cid: req.query.cid + cid: req.query.cid, }, req, res, function (err, widgets) { - if (err) { - return next(err); - } - res.status(200).json(widgets); - }); + if (err) { + return next(err); + } + res.status(200).json(widgets); + }); }; apiController.getPostData = function (pid, uid, callback) { @@ -138,7 +142,7 @@ apiController.getPostData = function (pid, uid, callback) { }, post: function (next) { posts.getPostData(pid, next); - } + }, }, function (err, results) { if (err || !results.post) { return callback(err); @@ -167,7 +171,7 @@ apiController.getTopicData = function (tid, uid, callback) { }, topic: function (next) { topics.getTopicData(tid, next); - } + }, }, function (err, results) { if (err || !results.topic) { return callback(err); @@ -187,7 +191,7 @@ apiController.getCategoryData = function (cid, uid, callback) { }, category: function (next) { categories.getCategoryData(cid, next); - } + }, }, function (err, results) { if (err || !results.category) { return callback(err); @@ -205,7 +209,7 @@ apiController.getObject = function (req, res, next) { var methods = { post: apiController.getPostData, topic: apiController.getTopicData, - category: apiController.getCategoryData + category: apiController.getCategoryData, }; var method = methods[req.params.type]; if (!method) { @@ -220,110 +224,11 @@ apiController.getObject = function (req, res, next) { }); }; -apiController.getCurrentUser = function (req, res, next) { - if (!req.uid) { - return res.status(401).json('not-authorized'); - } - async.waterfall([ - function (next) { - user.getUserField(req.uid, 'userslug', next); - }, - function (userslug, next) { - accountHelpers.getUserDataByUserSlug(userslug, req.uid, next); - } - ], function (err, userData) { - if (err) { - return next(err); - } - res.json(userData); - }); -}; - -apiController.getUserByUID = function (req, res, next) { - byType('uid', req, res, next); -}; - -apiController.getUserByUsername = function (req, res, next) { - byType('username', req, res, next); -}; - -apiController.getUserByEmail = function (req, res, next) { - byType('email', req, res, next); -}; - -function byType(type, req, res, next) { - apiController.getUserDataByField(req.uid, type, req.params[type], function (err, data) { - if (err || !data) { - return next(err); - } - res.json(data); - }); -} - -apiController.getUserDataByField = function (callerUid, field, fieldValue, callback) { - async.waterfall([ - function (next) { - if (field === 'uid') { - next(null, fieldValue); - } else if (field === 'username') { - user.getUidByUsername(fieldValue, next); - } else if (field === 'email') { - user.getUidByEmail(fieldValue, next); - } else { - next(); - } - }, - function (uid, next) { - if (!uid) { - return next(); - } - apiController.getUserDataByUID(callerUid, uid, next); - } - ], callback); -}; - -apiController.getUserDataByUID = function (callerUid, uid, callback) { - if (!parseInt(callerUid, 10) && parseInt(meta.config.privateUserInfo, 10) === 1) { - return callback(new Error('[[error:no-privileges]]')); - } - - if (!parseInt(uid, 10)) { - return callback(new Error('[[error:no-user]]')); - } - - async.parallel({ - userData: async.apply(user.getUserData, uid), - settings: async.apply(user.getSettings, uid) - }, function (err, results) { - if (err || !results.userData) { - return callback(err || new Error('[[error:no-user]]')); - } - - results.userData.email = results.settings.showemail ? results.userData.email : undefined; - results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; - - callback(null, results.userData); - }); -}; - apiController.getModerators = function (req, res, next) { categories.getModerators(req.params.cid, function (err, moderators) { if (err) { return next(err); } - res.json({moderators: moderators}); + res.json({ moderators: moderators }); }); }; - - -apiController.getRecentPosts = function (req, res, next) { - posts.getRecentPosts(req.uid, 0, 19, req.params.term, function (err, data) { - if (err) { - return next(err); - } - - res.json(data); - }); -}; - -module.exports = apiController; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 90a1715cbb..6a2051d2c9 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -6,7 +6,6 @@ var passport = require('passport'); var nconf = require('nconf'); var validator = require('validator'); var _ = require('underscore'); -var url = require('url'); var db = require('../database'); var meta = require('../meta'); @@ -19,7 +18,7 @@ var sockets = require('../socket.io'); var authenticationController = {}; -authenticationController.register = function (req, res, next) { +authenticationController.register = function (req, res) { var registrationType = meta.config.registrationType || 'normal'; if (registrationType === 'disabled') { @@ -74,7 +73,7 @@ authenticationController.register = function (req, res, next) { }, function (queue, next) { res.locals.processLogin = true; // set it to false in plugin if you wish to just register only - plugins.fireHook('filter:register.check', {req: req, res: res, userData: userData, queue: queue}, next); + plugins.fireHook('filter:register.check', { req: req, res: res, userData: userData, queue: queue }, next); }, function (data, next) { if (data.queue) { @@ -82,7 +81,7 @@ authenticationController.register = function (req, res, next) { } else { registerAndLoginUser(req, res, userData, next); } - } + }, ], function (err, data) { if (err) { return res.status(400).send(err.message); @@ -102,7 +101,7 @@ function registerAndLoginUser(req, res, userData, callback) { function (next) { plugins.fireHook('filter:register.interstitial', { userData: userData, - interstitials: [] + interstitials: [], }, function (err, data) { if (err) { return next(err); @@ -113,11 +112,10 @@ function registerAndLoginUser(req, res, userData, callback) { if (!deferRegistration) { return next(); - } else { - userData.register = true; - req.session.registration = userData; - return res.json({ referrer: nconf.get('relative_path') + '/register/complete' }); } + userData.register = true; + req.session.registration = userData; + return res.json({ referrer: nconf.get('relative_path') + '/register/complete' }); }); }, function (next) { @@ -133,8 +131,8 @@ function registerAndLoginUser(req, res, userData, callback) { }, function (next) { user.deleteInvitationKey(userData.email); - plugins.fireHook('filter:register.complete', {uid: uid, referrer: req.body.referrer || nconf.get('relative_path') + '/'}, next); - } + plugins.fireHook('filter:register.complete', { uid: uid, referrer: req.body.referrer || nconf.get('relative_path') + '/' }, next); + }, ], callback); } @@ -145,8 +143,8 @@ function addToApprovalQueue(req, userData, callback) { user.addToApprovalQueue(userData, next); }, function (next) { - next(null, {message: '[[register:registration-added-to-queue]]'}); - } + next(null, { message: '[[register:registration-added-to-queue]]' }); + }, ], callback); } @@ -154,7 +152,7 @@ authenticationController.registerComplete = function (req, res, next) { // For the interstitials that respond, execute the callback with the form body plugins.fireHook('filter:register.interstitial', { userData: req.session.registration, - interstitials: [] + interstitials: [], }, function (err, data) { if (err) { return next(err); @@ -214,7 +212,7 @@ authenticationController.login = function (req, res, next) { if (err) { return next(err); } - req.body.username = username ? username : req.body.username; + req.body.username = username || req.body.username; continueLogin(req, res, next); }); } else if (loginWith.indexOf('username') !== -1 && !validator.isEmail(req.body.username)) { @@ -284,7 +282,7 @@ authenticationController.doLogin = function (req, uid, callback) { return callback(); } - req.login({uid: uid}, function (err) { + req.login({ uid: uid }, function (err) { if (err) { return callback(err); } @@ -310,7 +308,7 @@ authenticationController.onSuccessfulLogin = function (req, uid, callback) { datetime: Date.now(), platform: req.useragent.platform, browser: req.useragent.browser, - version: req.useragent.version + version: req.useragent.version, }); // Associate login session with user @@ -323,7 +321,7 @@ authenticationController.onSuccessfulLogin = function (req, uid, callback) { }, function (next) { user.updateLastOnlineTime(uid, next); - } + }, ], function (err) { if (err) { return callback(err); @@ -343,7 +341,8 @@ authenticationController.localLogin = function (req, username, password, next) { } var userslug = utils.slugify(username); - var uid, userData = {}; + var uid; + var userData = {}; async.waterfall([ function (next) { @@ -369,7 +368,7 @@ authenticationController.localLogin = function (req, username, password, next) { }, banned: function (next) { user.isBanned(uid, next); - } + }, }, next); }, function (result, next) { @@ -408,7 +407,7 @@ authenticationController.localLogin = function (req, username, password, next) { } user.auth.clearLoginAttempts(uid); next(null, userData, '[[success:authentication-successful]]'); - } + }, ], next); }; @@ -426,7 +425,7 @@ authenticationController.logout = function (req, res, next) { user.setUserField(uid, 'lastonline', Date.now() - 300000); - plugins.fireHook('static:user.loggedOut', {req: req, res: res, uid: uid}, function () { + plugins.fireHook('static:user.loggedOut', { req: req, res: res, uid: uid }, function () { res.status(200).send(''); // Force session check for all connected socket.io clients with the same session id diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 9a18e7f1dd..e02f107b4a 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; var async = require('async'); var nconf = require('nconf'); -var validator = require('validator'); var categories = require('../categories'); var meta = require('../meta'); @@ -12,17 +11,14 @@ var categoriesController = {}; categoriesController.list = function (req, res, next) { res.locals.metaTags = [{ - name: "title", - content: validator.escape(String(meta.config.title || 'NodeBB')) - }, { - name: "description", - content: validator.escape(String(meta.config.description || '')) + name: 'title', + content: String(meta.config.title || 'NodeBB'), }, { property: 'og:title', - content: '[[pages:categories]]' + content: '[[pages:categories]]', }, { property: 'og:type', - content: 'website' + content: 'website', }]; var ogImage = meta.config['og:image'] || meta.config['brand:logo'] || ''; @@ -32,7 +28,7 @@ categoriesController.list = function (req, res, next) { } res.locals.metaTags.push({ property: 'og:image', - content: ogImage + content: ogImage, }); } @@ -48,7 +44,7 @@ categoriesController.list = function (req, res, next) { categories.flattenCategories(allCategories, categoryData); categories.getRecentTopicReplies(allCategories, req.uid, next); - } + }, ], function (err) { if (err) { return next(err); @@ -56,11 +52,11 @@ categoriesController.list = function (req, res, next) { var data = { title: '[[pages:categories]]', - categories: categoryData + categories: categoryData, }; if (req.path.startsWith('/api/categories') || req.path.startsWith('/categories')) { - data.breadcrumbs = helpers.buildBreadcrumbs([{text: data.title}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: data.title }]); } data.categories.forEach(function (category) { @@ -68,7 +64,7 @@ categoriesController.list = function (req, res, next) { category.teaser = { url: nconf.get('relative_path') + '/topic/' + category.posts[0].topic.slug + '/' + category.posts[0].index, timestampISO: category.posts[0].timestampISO, - pid: category.posts[0].pid + pid: category.posts[0].pid, }; } }); diff --git a/src/controllers/category.js b/src/controllers/category.js index 3570f279ee..ce5f7b5e07 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -37,7 +37,7 @@ categoryController.get = function (req, res, callback) { }, userSettings: function (next) { user.getSettings(req.uid, next); - } + }, }, next); }, function (results, next) { @@ -87,7 +87,7 @@ categoryController.get = function (req, res, callback) { set = 'cid:' + cid + ':tids:posts'; } - var start = (currentPage - 1) * settings.topicsPerPage + topicIndex; + var start = ((currentPage - 1) * settings.topicsPerPage) + topicIndex; var stop = start + settings.topicsPerPage - 1; var payload = { @@ -97,7 +97,7 @@ categoryController.get = function (req, res, callback) { start: start, stop: stop, uid: req.uid, - settings: settings + settings: settings, }; async.waterfall([ @@ -120,11 +120,10 @@ categoryController.get = function (req, res, callback) { } } categories.getCategoryById(payload, next); - } + }, ], next); }, function (categoryData, next) { - categories.modifyTopicsByPrivilege(categoryData.topics, userPrivileges); if (categoryData.link) { @@ -135,8 +134,8 @@ categoryController.get = function (req, res, callback) { var breadcrumbs = [ { text: categoryData.name, - url: nconf.get('relative_path') + '/category/' + categoryData.slug - } + url: nconf.get('relative_path') + '/category/' + categoryData.slug, + }, ]; helpers.buildCategoryBreadcrumbs(categoryData.parentCid, function (err, crumbs) { if (err) { @@ -155,7 +154,7 @@ categoryController.get = function (req, res, callback) { categories.getRecentTopicReplies(allCategories, req.uid, function (err) { next(err, categoryData); }); - } + }, ], function (err, categoryData) { if (err) { return callback(err); @@ -167,26 +166,26 @@ categoryController.get = function (req, res, callback) { res.locals.metaTags = [ { name: 'title', - content: categoryData.name + content: categoryData.name, }, { property: 'og:title', - content: categoryData.name + content: categoryData.name, }, { name: 'description', - content: categoryData.description + content: categoryData.description, }, { - property: "og:type", - content: 'website' - } + property: 'og:type', + content: 'website', + }, ]; if (categoryData.backgroundImage) { res.locals.metaTags.push({ name: 'og:image', - content: categoryData.backgroundImage + content: categoryData.backgroundImage, }); } @@ -194,12 +193,12 @@ categoryController.get = function (req, res, callback) { { rel: 'alternate', type: 'application/rss+xml', - href: nconf.get('url') + '/category/' + cid + '.rss' + href: nconf.get('url') + '/category/' + cid + '.rss', }, { rel: 'up', - href: nconf.get('url') - } + href: nconf.get('url'), + }, ]; if (parseInt(req.uid, 10)) { diff --git a/src/controllers/errors.js b/src/controllers/errors.js new file mode 100644 index 0000000000..6ab0dc6471 --- /dev/null +++ b/src/controllers/errors.js @@ -0,0 +1,63 @@ +'use strict'; + +var nconf = require('nconf'); +var winston = require('winston'); +var validator = require('validator'); + +exports.handleURIErrors = function (err, req, res, next) { + // Handle cases where malformed URIs are passed in + if (err instanceof URIError) { + var tidMatch = req.path.match(/^\/topic\/(\d+)\//); + var cidMatch = req.path.match(/^\/category\/(\d+)\//); + + if (tidMatch) { + res.redirect(nconf.get('relative_path') + tidMatch[0]); + } else if (cidMatch) { + res.redirect(nconf.get('relative_path') + cidMatch[0]); + } else { + winston.warn('[controller] Bad request: ' + req.path); + if (res.locals.isAPI) { + res.status(400).json({ + error: '[[global:400.title]]', + }); + } else { + var middleware = require('../middleware'); + middleware.buildHeader(req, res, function () { + res.render('400', { error: validator.escape(String(err.message)) }); + }); + } + } + } else { + next(err); + } +}; + +// this needs to have four arguments or express treats it as `(req, res, next)` +// don't remove `next`! +exports.handleErrors = function (err, req, res, next) { // eslint-disable-line no-unused-vars + switch (err.code) { + case 'EBADCSRFTOKEN': + winston.error(req.path + '\n', err.message); + return res.sendStatus(403); + case 'blacklisted-ip': + return res.status(403).type('text/plain').send(err.message); + } + + if (parseInt(err.status, 10) === 302 && err.path) { + return res.locals.isAPI ? res.status(302).json(err.path) : res.redirect(err.path); + } + + winston.error(req.path + '\n', err.stack); + + res.status(err.status || 500); + + var path = String(req.path || ''); + if (res.locals.isAPI) { + res.json({ path: validator.escape(path), error: err.message }); + } else { + var middleware = require('../middleware'); + middleware.buildHeader(req, res, function () { + res.render('500', { path: validator.escape(path), error: validator.escape(String(err.message)) }); + }); + } +}; diff --git a/src/controllers/globalmods.js b/src/controllers/globalmods.js index 7e4fd1ffec..793c33653e 100644 --- a/src/controllers/globalmods.js +++ b/src/controllers/globalmods.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var user = require('../user'); var adminBlacklistController = require('./admin/blacklist'); diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 25a6d928db..94f5469ef4 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -1,7 +1,6 @@ -"use strict"; +'use strict'; var async = require('async'); -var nconf = require('nconf'); var validator = require('validator'); var meta = require('../meta'); @@ -19,7 +18,7 @@ groupsController.list = function (req, res, next) { return next(err); } data.title = '[[pages:groups]]'; - data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[pages:groups]]'}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[pages:groups]]' }]); res.render('groups/list', data); }); }; @@ -40,9 +39,9 @@ groupsController.getGroupsFromSet = function (uid, sort, start, stop, callback) next(null, { groups: groupsData, allowGroupCreation: parseInt(meta.config.allowGroupCreation, 10) === 1, - nextStart: stop + 1 + nextStart: stop + 1, }); - } + }, ], callback); }; @@ -59,7 +58,7 @@ groupsController.details = function (req, res, callback) { } async.parallel({ exists: async.apply(groups.exists, groupName), - hidden: async.apply(groups.isHidden, groupName) + hidden: async.apply(groups.isHidden, groupName), }, next); }, function (results, next) { @@ -71,7 +70,7 @@ groupsController.details = function (req, res, callback) { } async.parallel({ isMember: async.apply(groups.isMember, req.uid, groupName), - isInvited: async.apply(groups.isInvited, req.uid, groupName) + isInvited: async.apply(groups.isInvited, req.uid, groupName), }, function (err, checks) { if (err || checks.isMember || checks.isInvited) { return next(err); @@ -85,20 +84,20 @@ groupsController.details = function (req, res, callback) { groups.get(groupName, { uid: req.uid, truncateUserList: true, - userListCount: 20 + userListCount: 20, }, next); }, posts: function (next) { groups.getLatestMemberPosts(groupName, 10, req.uid, next); }, - isAdmin:function (next) { + isAdmin: function (next) { user.isAdministrator(req.uid, next); }, isGlobalMod: function (next) { user.isGlobalModerator(req.uid, next); - } + }, }, next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -109,7 +108,7 @@ groupsController.details = function (req, res, callback) { } results.group.isOwner = results.group.isOwner || results.isAdmin || (results.isGlobalMod && !results.group.system); results.title = '[[pages:group, ' + results.group.displayName + ']]'; - results.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[pages:groups]]', url: '/groups' }, {text: results.group.displayName}]); + results.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[pages:groups]]', url: '/groups' }, { text: results.group.displayName }]); results.allowPrivateGroups = parseInt(meta.config.allowPrivateGroups, 10) === 1; res.render('groups/details', results); @@ -130,7 +129,7 @@ groupsController.members = function (req, res, callback) { async.parallel({ isAdminOrGlobalMod: async.apply(user.isAdminOrGlobalMod, req.uid), isMember: async.apply(groups.isMember, req.uid, groupName), - isHidden: async.apply(groups.isHidden, groupName) + isHidden: async.apply(groups.isHidden, groupName), }, next); }, function (results, next) { @@ -146,16 +145,16 @@ groupsController.members = function (req, res, callback) { } var breadcrumbs = helpers.buildBreadcrumbs([ - {text: '[[pages:groups]]', url: '/groups' }, - {text: validator.escape(String(groupName)), url: '/groups/' + req.params.slug}, - {text: '[[groups:details.members]]'} + { text: '[[pages:groups]]', url: '/groups' }, + { text: validator.escape(String(groupName)), url: '/groups/' + req.params.slug }, + { text: '[[groups:details.members]]' }, ]); res.render('groups/members', { users: users, nextStart: 50, loadmore_display: users.length > 50 ? 'block' : 'hide', - breadcrumbs: breadcrumbs + breadcrumbs: breadcrumbs, }); }); }; @@ -174,14 +173,14 @@ groupsController.uploadCover = function (req, res, next) { groups.updateCover(req.uid, { file: req.files.files[0].path, - groupName: params.groupName + groupName: params.groupName, }, next); - } + }, ], function (err, image) { if (err) { return next(err); } - res.json([{url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); + res.json([{ url: image.url }]); }); }; diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 488ac6507c..5571bfbf62 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -17,8 +17,8 @@ helpers.notAllowed = function (req, res, error) { plugins.fireHook('filter:helpers.notAllowed', { req: req, res: res, - error: error - }, function (err, data) { + error: error, + }, function (err) { if (err) { return winston.error(err); } @@ -28,24 +28,22 @@ helpers.notAllowed = function (req, res, error) { path: req.path.replace(/^\/api/, ''), loggedIn: !!req.uid, error: error, - title: '[[global:403.title]]' + title: '[[global:403.title]]', }); } else { res.status(403).render('403', { path: req.path, loggedIn: !!req.uid, error: error, - title: '[[global:403.title]]' + title: '[[global:403.title]]', }); } + } else if (res.locals.isAPI) { + req.session.returnTo = nconf.get('relative_path') + req.url.replace(/^\/api/, ''); + res.status(401).json('not-authorized'); } else { - if (res.locals.isAPI) { - req.session.returnTo = nconf.get('relative_path') + req.url.replace(/^\/api/, ''); - res.status(401).json('not-authorized'); - } else { - req.session.returnTo = nconf.get('relative_path') + req.url; - res.redirect(nconf.get('relative_path') + '/login'); - } + req.session.returnTo = nconf.get('relative_path') + req.url; + res.redirect(nconf.get('relative_path') + '/login'); } }); }; @@ -72,7 +70,7 @@ helpers.buildCategoryBreadcrumbs = function (cid, callback) { if (!parseInt(data.disabled, 10)) { breadcrumbs.unshift({ text: validator.escape(String(data.name)), - url: nconf.get('relative_path') + '/category/' + data.slug + url: nconf.get('relative_path') + '/category/' + data.slug, }); } @@ -87,13 +85,13 @@ helpers.buildCategoryBreadcrumbs = function (cid, callback) { if (!meta.config.homePageRoute && meta.config.homePageCustom) { breadcrumbs.unshift({ text: '[[global:header.categories]]', - url: nconf.get('relative_path') + '/categories' + url: nconf.get('relative_path') + '/categories', }); } breadcrumbs.unshift({ text: '[[global:home]]', - url: nconf.get('relative_path') + '/' + url: nconf.get('relative_path') + '/', }); callback(null, breadcrumbs); @@ -104,8 +102,8 @@ helpers.buildBreadcrumbs = function (crumbs) { var breadcrumbs = [ { text: '[[global:home]]', - url: nconf.get('relative_path') + '/' - } + url: nconf.get('relative_path') + '/', + }, ]; crumbs.forEach(function (crumb) { @@ -164,8 +162,8 @@ helpers.getWatchedCategories = function (uid, selectedCid, callback) { recursive(category, categoriesData, ''); }); - next(null, {categories: categoriesData, selectedCategory: selectedCategory}); - } + next(null, { categories: categoriesData, selectedCategory: selectedCategory }); + }, ], callback); }; diff --git a/src/controllers/index.js b/src/controllers/index.js index 800559db4b..93b8e9a383 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -1,36 +1,38 @@ -"use strict"; +'use strict'; var async = require('async'); var nconf = require('nconf'); var validator = require('validator'); -var winston = require('winston'); var meta = require('../meta'); var user = require('../user'); var plugins = require('../plugins'); var helpers = require('./helpers'); -var Controllers = { - topics: require('./topics'), - posts: require('./posts'), - categories: require('./categories'), - category: require('./category'), - unread: require('./unread'), - recent: require('./recent'), - popular: require('./popular'), - tags: require('./tags'), - search: require('./search'), - users: require('./users'), - groups: require('./groups'), - accounts: require('./accounts'), - authentication: require('./authentication'), - api: require('./api'), - admin: require('./admin'), - globalMods: require('./globalmods'), - mods: require('./mods'), - sitemap: require('./sitemap') -}; +var Controllers = module.exports; +Controllers.topics = require('./topics'); +Controllers.posts = require('./posts'); +Controllers.categories = require('./categories'); +Controllers.category = require('./category'); +Controllers.unread = require('./unread'); +Controllers.recent = require('./recent'); +Controllers.popular = require('./popular'); +Controllers.tags = require('./tags'); +Controllers.search = require('./search'); +Controllers.user = require('./user'); +Controllers.users = require('./users'); +Controllers.groups = require('./groups'); +Controllers.accounts = require('./accounts'); +Controllers.authentication = require('./authentication'); +Controllers.api = require('./api'); +Controllers.admin = require('./admin'); +Controllers.globalMods = require('./globalmods'); +Controllers.mods = require('./mods'); +Controllers.sitemap = require('./sitemap'); +Controllers.osd = require('./osd'); +Controllers['404'] = require('./404'); +Controllers.errors = require('./errors'); Controllers.home = function (req, res, next) { var route = meta.config.homePageRoute || (meta.config.homePageCustom || '').replace(/^\/+/, '') || 'categories'; @@ -46,7 +48,7 @@ Controllers.home = function (req, res, next) { var hook = 'action:homepage.get:' + route; if (plugins.hasListeners(hook)) { - return plugins.fireHook(hook, {req: req, res: res, next: next}); + return plugins.fireHook(hook, { req: req, res: res, next: next }); } if (route === 'categories' || route === '/') { @@ -61,7 +63,7 @@ Controllers.home = function (req, res, next) { var match = /^category\/(\d+)\/(.*)$/.exec(route); if (match) { - req.params.topic_index = "1"; + req.params.topic_index = '1'; req.params.category_id = match[1]; req.params.slug = match[2]; Controllers.category.get(req, res, next); @@ -83,8 +85,8 @@ Controllers.reset = function (req, res, next) { displayExpiryNotice: req.session.passwordExpired, code: req.params.code, minimumPasswordLength: parseInt(meta.config.minimumPasswordLength, 10), - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]', url: '/reset'}, {text: '[[reset_password:update_password]]'}]), - title: '[[pages:reset]]' + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[reset_password:reset_password]]', url: '/reset' }, { text: '[[reset_password:update_password]]' }]), + title: '[[pages:reset]]', }); delete req.session.passwordExpired; @@ -92,8 +94,8 @@ Controllers.reset = function (req, res, next) { } else { res.render('reset', { code: null, - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[reset_password:reset_password]]'}]), - title: '[[pages:reset]]' + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[reset_password:reset_password]]' }]), + title: '[[pages:reset]]', }); } }; @@ -122,18 +124,17 @@ Controllers.login = function (req, res, next) { data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1 || parseInt(req.query.local, 10) === 1; data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval' || registrationType === 'admin-approval-ip'; data.allowLoginWith = '[[login:' + allowLoginWith + ']]'; - data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:login]]'}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[global:login]]' }]); data.error = req.flash('error')[0] || errorText; data.title = '[[pages:login]]'; if (!data.allowLocalLogin && !data.allowRegistration && data.alternate_logins && data.authentication.length === 1) { if (res.locals.isAPI) { return helpers.redirect(res, { - external: data.authentication[0].url + external: nconf.get('relative_path') + data.authentication[0].url, }); - } else { - return res.redirect(nconf.get('relative_path') + data.authentication[0].url); } + return res.redirect(nconf.get('relative_path') + data.authentication[0].url); } if (req.uid) { user.getUserFields(req.uid, ['username', 'email'], function (err, user) { @@ -147,7 +148,6 @@ Controllers.login = function (req, res, next) { } else { res.render('login', data); } - }; Controllers.register = function (req, res, next) { @@ -171,8 +171,8 @@ Controllers.register = function (req, res, next) { } }, function (next) { - plugins.fireHook('filter:parse.post', {postData: {content: meta.config.termsOfUse || ''}}, next); - } + plugins.fireHook('filter:parse.post', { postData: { content: meta.config.termsOfUse || '' } }, next); + }, ], function (err, termsOfUse) { if (err) { return next(err); @@ -180,7 +180,7 @@ Controllers.register = function (req, res, next) { var loginStrategies = require('../routes/authentication').getLoginStrategies(); var data = { 'register_window:spansize': loginStrategies.length ? 'col-md-6' : 'col-md-12', - 'alternate_logins': !!loginStrategies.length + alternate_logins: !!loginStrategies.length, }; data.authentication = loginStrategies; @@ -189,7 +189,7 @@ Controllers.register = function (req, res, next) { data.maximumUsernameLength = parseInt(meta.config.maximumUsernameLength, 10); data.minimumPasswordLength = parseInt(meta.config.minimumPasswordLength, 10); data.termsOfUse = termsOfUse.postData.content; - data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[register:register]]'}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[register:register]]' }]); data.regFormEntry = []; data.error = req.flash('error')[0] || errorText; data.title = '[[pages:register]]'; @@ -203,37 +203,35 @@ Controllers.registerInterstitial = function (req, res, next) { return res.redirect(nconf.get('relative_path') + '/register'); } - plugins.fireHook('filter:register.interstitial', { - userData: req.session.registration, - interstitials: [] - }, function (err, data) { - if (err) { - return next(err); - } - - if (!data.interstitials.length) { - // No interstitials, redirect to home - delete req.session.registration; - return res.redirect('/'); - } - - var renders = data.interstitials.map(function (interstitial) { - return async.apply(req.app.render.bind(req.app), interstitial.template, interstitial.data || {}); - }); - var errors = req.flash('error'); - - async.parallel(renders, function (err, sections) { - if (err) { - return next(err); + async.waterfall([ + function (next) { + plugins.fireHook('filter:register.interstitial', { + userData: req.session.registration, + interstitials: [], + }, next); + }, + function (data, next) { + if (!data.interstitials.length) { + // No interstitials, redirect to home + delete req.session.registration; + return res.redirect('/'); } + var renders = data.interstitials.map(function (interstitial) { + return async.apply(req.app.render.bind(req.app), interstitial.template, interstitial.data || {}); + }); + + async.parallel(renders, next); + }, + function (sections) { + var errors = req.flash('error'); res.render('registerComplete', { title: '[[pages:registration-complete]]', errors: errors, - sections: sections + sections: sections, }); - }); - }); + }, + ], next); }; Controllers.compose = function (req, res, next) { @@ -241,7 +239,7 @@ Controllers.compose = function (req, res, next) { req: req, res: res, next: next, - templateData: {} + templateData: {}, }, function (err, data) { if (err) { return next(err); @@ -249,7 +247,7 @@ Controllers.compose = function (req, res, next) { if (data.templateData.disabled) { res.render('', { - title: '[[modules:composer.compose]]' + title: '[[modules:composer.compose]]', }); } else { data.templateData.title = '[[modules:composer.compose]]'; @@ -270,12 +268,12 @@ Controllers.confirmEmail = function (req, res) { Controllers.robots = function (req, res) { res.set('Content-Type', 'text/plain'); - if (meta.config["robots.txt"]) { - res.send(meta.config["robots.txt"]); + if (meta.config['robots.txt']) { + res.send(meta.config['robots.txt']); } else { - res.send("User-agent: *\n" + - "Disallow: " + nconf.get('relative_path') + "/admin/\n" + - "Sitemap: " + nconf.get('url') + "/sitemap.xml"); + res.send('User-agent: *\n' + + 'Disallow: ' + nconf.get('relative_path') + '/admin/\n' + + 'Sitemap: ' + nconf.get('url') + '/sitemap.xml'); } }; @@ -285,7 +283,7 @@ Controllers.manifest = function (req, res) { start_url: nconf.get('relative_path') + '/', display: 'standalone', orientation: 'portrait', - icons: [] + icons: [], }; if (meta.config['brand:touchIcon']) { @@ -293,159 +291,59 @@ Controllers.manifest = function (req, res) { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-36.png', sizes: '36x36', type: 'image/png', - density: 0.75 + density: 0.75, }, { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-48.png', sizes: '48x48', type: 'image/png', - density: 1.0 + density: 1.0, }, { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-72.png', sizes: '72x72', type: 'image/png', - density: 1.5 + density: 1.5, }, { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-96.png', sizes: '96x96', type: 'image/png', - density: 2.0 + density: 2.0, }, { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-144.png', sizes: '144x144', type: 'image/png', - density: 3.0 + density: 3.0, }, { src: nconf.get('relative_path') + '/assets/uploads/system/touchicon-192.png', sizes: '192x192', type: 'image/png', - density: 4.0 + density: 4.0, }); } res.status(200).json(manifest); }; -Controllers.outgoing = function (req, res) { +Controllers.outgoing = function (req, res, next) { var url = req.query.url || ''; - var data = { + + if (!url) { + return next(); + } + + res.render('outgoing', { outgoing: validator.escape(String(url)), title: meta.config.title, - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[notifications:outgoing_link]]'}]) - }; - - if (url) { - res.render('outgoing', data); - } else { - res.status(404).redirect(nconf.get('relative_path') + '/404'); - } + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[notifications:outgoing_link]]' }]), + }); }; Controllers.termsOfUse = function (req, res, next) { if (!meta.config.termsOfUse) { return next(); } - res.render('tos', {termsOfUse: meta.config.termsOfUse}); + res.render('tos', { termsOfUse: meta.config.termsOfUse }); }; Controllers.ping = function (req, res) { res.status(200).send(req.path === '/sping' ? 'healthy' : '200'); }; - -Controllers.handle404 = function (req, res) { - var relativePath = nconf.get('relative_path'); - var isClientScript = new RegExp('^' + relativePath + '\\/assets\\/src\\/.+\\.js'); - - if (plugins.hasListeners('action:meta.override404')) { - return plugins.fireHook('action:meta.override404', { - req: req, - res: res, - error: {} - }); - } - - if (isClientScript.test(req.url)) { - res.type('text/javascript').status(200).send(''); - } else if (req.path.startsWith(relativePath + '/assets/uploads') || (req.get('accept') && req.get('accept').indexOf('text/html') === -1) || req.path === '/favicon.ico') { - meta.errors.log404(req.path || ''); - res.sendStatus(404); - } else if (req.accepts('html')) { - if (process.env.NODE_ENV === 'development') { - winston.warn('Route requested but not found: ' + req.url); - } - - meta.errors.log404(req.path.replace(/^\/api/, '') || ''); - res.status(404); - - var path = String(req.path || ''); - - if (res.locals.isAPI) { - return res.json({path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]'}); - } - var middleware = require('../middleware'); - middleware.buildHeader(req, res, function () { - res.render('404', {path: validator.escape(path), title: '[[global:404.title]]'}); - }); - } else { - res.status(404).type('txt').send('Not found'); - } -}; - -Controllers.handleURIErrors = function (err, req, res, next) { - // Handle cases where malformed URIs are passed in - if (err instanceof URIError) { - var tidMatch = req.path.match(/^\/topic\/(\d+)\//); - var cidMatch = req.path.match(/^\/category\/(\d+)\//); - - if (tidMatch) { - res.redirect(nconf.get('relative_path') + tidMatch[0]); - } else if (cidMatch) { - res.redirect(nconf.get('relative_path') + cidMatch[0]); - } else { - winston.warn('[controller] Bad request: ' + req.path); - if (res.locals.isAPI) { - res.status(400).json({ - error: '[[global:400.title]]' - }); - } else { - var middleware = require('../middleware'); - middleware.buildHeader(req, res, function () { - res.render('400', { error: validator.escape(String(err.message)) }); - }); - } - } - - return; - } else { - next(err); - } -}; - -Controllers.handleErrors = function (err, req, res, next) { - switch (err.code) { - case 'EBADCSRFTOKEN': - winston.error(req.path + '\n', err.message); - return res.sendStatus(403); - case 'blacklisted-ip': - return res.status(403).type('text/plain').send(err.message); - } - - if (parseInt(err.status, 10) === 302 && err.path) { - return res.locals.isAPI ? res.status(302).json(err.path) : res.redirect(err.path); - } - - winston.error(req.path + '\n', err.stack); - - res.status(err.status || 500); - - var path = String(req.path || ''); - if (res.locals.isAPI) { - res.json({path: validator.escape(path), error: err.message}); - } else { - var middleware = require('../middleware'); - middleware.buildHeader(req, res, function () { - res.render('500', { path: validator.escape(path), error: validator.escape(String(err.message)) }); - }); - } -}; - -module.exports = Controllers; diff --git a/src/controllers/mods.js b/src/controllers/mods.js index 0079412f87..6a1835f980 100644 --- a/src/controllers/mods.js +++ b/src/controllers/mods.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -10,7 +10,7 @@ var modsController = {}; modsController.flagged = function (req, res, next) { async.parallel({ isAdminOrGlobalMod: async.apply(user.isAdminOrGlobalMod, req.uid), - moderatedCids: async.apply(user.getModeratedCids, req.uid) + moderatedCids: async.apply(user.getModeratedCids, req.uid), }, function (err, results) { if (err || !(results.isAdminOrGlobalMod || !!results.moderatedCids.length)) { return next(err); diff --git a/src/controllers/osd.js b/src/controllers/osd.js new file mode 100644 index 0000000000..c83f7f142c --- /dev/null +++ b/src/controllers/osd.js @@ -0,0 +1,32 @@ +'use strict'; + +var xml = require('xml'); +var nconf = require('nconf'); + +var plugins = require('../plugins'); +var meta = require('../meta'); + +module.exports.handle = function (req, res, next) { + if (plugins.hasListeners('filter:search.query')) { + res.type('application/xml').send(generateXML()); + } else { + next(); + } +}; + +function generateXML() { + return xml([{ + OpenSearchDescription: [ + { _attr: { xmlns: 'http://a9.com/-/spec/opensearch/1.1/' } }, + { ShortName: String(meta.config.title || meta.config.browserTitle || 'NodeBB') }, + { Description: String(meta.config.description || '') }, + { Url: { + _attr: { + type: 'text/html', + method: 'get', + template: nconf.get('url') + '/search?term={searchTerms}&in=titlesposts', + }, + } }, + ], + }], { declaration: true, indent: '\t' }); +} diff --git a/src/controllers/popular.js b/src/controllers/popular.js index f38edd594c..21c07224c1 100644 --- a/src/controllers/popular.js +++ b/src/controllers/popular.js @@ -14,11 +14,10 @@ var lastUpdateTime = 0; var terms = { daily: 'day', weekly: 'week', - monthly: 'month' + monthly: 'month', }; popularController.get = function (req, res, next) { - var term = terms[req.params.term]; if (!term && req.params.term) { @@ -30,7 +29,7 @@ popularController.get = function (req, res, next) { day: '[[recent:day]]', week: '[[recent:week]]', month: '[[recent:month]]', - alltime: '[[global:header.popular]]' + alltime: '[[global:header.popular]]', }; if (!req.uid) { @@ -49,14 +48,14 @@ popularController.get = function (req, res, next) { 'feeds:disableRSS': parseInt(meta.config['feeds:disableRSS'], 10) === 1, rssFeedUrl: nconf.get('relative_path') + '/popular/' + (req.params.term || 'daily') + '.rss', title: '[[pages:popular-' + term + ']]', - term: term + term: term, }; if (req.path.startsWith('/api/popular') || req.path.startsWith('/popular')) { - var breadcrumbs = [{text: termToBreadcrumb[term]}]; + var breadcrumbs = [{ text: termToBreadcrumb[term] }]; if (req.params.term) { - breadcrumbs.unshift({text: '[[global:header.popular]]', url: '/popular'}); + breadcrumbs.unshift({ text: '[[global:header.popular]]', url: '/popular' }); } data.breadcrumbs = helpers.buildBreadcrumbs(breadcrumbs); @@ -71,4 +70,4 @@ popularController.get = function (req, res, next) { }); }; -module.exports = popularController; \ No newline at end of file +module.exports = popularController; diff --git a/src/controllers/posts.js b/src/controllers/posts.js index dae990e171..8afb3f5729 100644 --- a/src/controllers/posts.js +++ b/src/controllers/posts.js @@ -1,24 +1,38 @@ -"use strict"; +'use strict'; + +var async = require('async'); var posts = require('../posts'); var helpers = require('./helpers'); -var postsController = {}; +var postsController = module.exports; -postsController.redirectToPost = function (req, res, callback) { +postsController.redirectToPost = function (req, res, next) { var pid = parseInt(req.params.pid, 10); if (!pid) { - return callback(); + return next(); } - posts.generatePostPath(pid, req.uid, function (err, path) { - if (err || !path) { - return callback(err); - } - - helpers.redirect(res, path); - }); + async.waterfall([ + function (next) { + posts.generatePostPath(pid, req.uid, next); + }, + function (path, next) { + if (!path) { + return next(); + } + helpers.redirect(res, path); + }, + ], next); }; - -module.exports = postsController; +postsController.getRecentPosts = function (req, res, next) { + async.waterfall([ + function (next) { + posts.getRecentPosts(req.uid, 0, 19, req.params.term, next); + }, + function (data) { + res.json(data); + }, + ], next); +}; diff --git a/src/controllers/recent.js b/src/controllers/recent.js index 2da6e7d09c..c5d1d2128a 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -13,7 +13,7 @@ var pagination = require('../pagination'); var recentController = {}; -var validFilter = {'': true, 'new': true, 'watched': true}; +var validFilter = { '': true, new: true, watched: true }; recentController.get = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; @@ -35,7 +35,7 @@ recentController.get = function (req, res, next) { }, watchedCategories: function (next) { helpers.getWatchedCategories(req.uid, cid, next); - } + }, }, next); }, function (results, next) { @@ -46,7 +46,7 @@ recentController.get = function (req, res, next) { stop = start + settings.topicsPerPage - 1; topics.getRecentTopics(cid, req.uid, start, stop, filter, next); - } + }, ], function (err, data) { if (err) { return next(err); @@ -63,17 +63,17 @@ recentController.get = function (req, res, next) { name: '[[unread:all-topics]]', url: 'recent', selected: filter === '', - filter: '' + filter: '', }, { name: '[[unread:new-topics]]', url: 'recent/new', selected: filter === 'new', - filter: 'new' + filter: 'new', }, { name: '[[unread:watched-topics]]', url: 'recent/watched', selected: filter === 'watched', - filter: 'watched' + filter: 'watched', }]; data.selectedFilter = data.filters.find(function (filter) { @@ -84,7 +84,7 @@ recentController.get = function (req, res, next) { data.pagination = pagination.create(page, pageCount, req.query); if (req.path.startsWith('/api/recent') || req.path.startsWith('/recent')) { - data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[recent:title]]'}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[recent:title]]' }]); } data.querystring = cid ? ('?cid=' + validator.escape(String(cid))) : ''; @@ -92,4 +92,4 @@ recentController.get = function (req, res, next) { }); }; -module.exports = recentController; \ No newline at end of file +module.exports = recentController; diff --git a/src/controllers/search.js b/src/controllers/search.js index 2261e4f3b7..29a883489f 100644 --- a/src/controllers/search.js +++ b/src/controllers/search.js @@ -42,20 +42,20 @@ searchController.search = function (req, res, next) { sortDirection: req.query.sortDirection, page: page, uid: req.uid, - qs: req.query + qs: req.query, }; async.parallel({ categories: async.apply(categories.buildForSelect, req.uid), - search: async.apply(search.search, data) + search: async.apply(search.search, data), }, function (err, results) { if (err) { return next(err); } var categoriesData = [ - {value: 'all', text: '[[unread:all_categories]]'}, - {value: 'watched', text: '[[category:watched-categories]]'} + { value: 'all', text: '[[unread:all_categories]]' }, + { value: 'watched', text: '[[category:watched-categories]]' }, ].concat(results.categories); var searchData = results.search; @@ -65,7 +65,7 @@ searchController.search = function (req, res, next) { searchData.showAsPosts = !req.query.showAs || req.query.showAs === 'posts'; searchData.showAsTopics = req.query.showAs === 'topics'; searchData.title = '[[global:header.search]]'; - searchData.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]); + searchData.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[global:search]]' }]); searchData.expandSearch = !req.query.term; res.render('search', searchData); diff --git a/src/controllers/sitemap.js b/src/controllers/sitemap.js index 42b0ae1076..846c6facb2 100644 --- a/src/controllers/sitemap.js +++ b/src/controllers/sitemap.js @@ -1,68 +1,57 @@ 'use strict'; +var async = require('async'); + var sitemap = require('../sitemap'); var meta = require('../meta'); -var sitemapController = {}; -sitemapController.render = function (req, res, next) { - sitemap.render(function (err, tplData) { - if (err) { - return next(err); - } +var sitemapController = module.exports; - req.app.render('sitemap', tplData, function (err, xml) { - if (err) { - return next(err); - } +sitemapController.render = function (req, res, next) { + async.waterfall([ + function (next) { + sitemap.render(next); + }, + function (tplData, next) { + req.app.render('sitemap', tplData, next); + }, + function (xml) { res.header('Content-Type', 'application/xml'); res.send(xml); - }); - }); + }, + ], next); }; sitemapController.getPages = function (req, res, next) { - if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { - return next(); - } - - sitemap.getPages(function (err, xml) { - if (err) { - return next(err); - } - res.header('Content-Type', 'application/xml'); - res.send(xml); - }); + sendSitemap(sitemap.getPages, res, next); }; sitemapController.getCategories = function (req, res, next) { - if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { - return next(); - } - - sitemap.getCategories(function (err, xml) { - if (err) { - return next(err); - } - res.header('Content-Type', 'application/xml'); - res.send(xml); - }); + sendSitemap(sitemap.getCategories, res, next); }; sitemapController.getTopicPage = function (req, res, next) { - if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { - return next(); - } - - sitemap.getTopicPage(parseInt(req.params[0], 10), function (err, xml) { - if (err) { - return next(err); - } else if (!xml) { - return next(); - } - - res.header('Content-Type', 'application/xml'); - res.send(xml); - }); + sendSitemap(function (callback) { + sitemap.getTopicPage(parseInt(req.params[0], 10), callback); + }, res, next); }; -module.exports = sitemapController; \ No newline at end of file +function sendSitemap(method, res, callback) { + if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { + return callback(); + } + async.waterfall([ + function (next) { + method(next); + }, + function (xml) { + if (!xml) { + return callback(); + } + + res.header('Content-Type', 'application/xml'); + res.send(xml); + }, + ], callback); +} + diff --git a/src/controllers/tags.js b/src/controllers/tags.js index a433694220..cffff0e44c 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -8,7 +8,7 @@ var validator = require('validator'); var user = require('../user'); var topics = require('../topics'); var pagination = require('../pagination'); -var helpers = require('./helpers'); +var helpers = require('./helpers'); var tagsController = {}; @@ -19,8 +19,8 @@ tagsController.getTag = function (req, res, next) { var templateData = { topics: [], tag: tag, - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[tags:tags]]', url: '/tags'}, {text: tag}]), - title: '[[pages:tag, ' + tag + ']]' + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[tags:tags]]', url: '/tags' }, { text: tag }]), + title: '[[pages:tag, ' + tag + ']]', }; var settings; var topicCount = 0; @@ -39,7 +39,7 @@ tagsController.getTag = function (req, res, next) { }, tids: function (next) { topics.getTagTids(req.params.tag, start, stop, next); - } + }, }, next); }, function (results, next) { @@ -48,7 +48,7 @@ tagsController.getTag = function (req, res, next) { } topicCount = results.topicCount; topics.getTopics(results.tids, req.uid, next); - } + }, ], function (err, topics) { if (err) { return next(err); @@ -57,16 +57,16 @@ tagsController.getTag = function (req, res, next) { res.locals.metaTags = [ { name: 'title', - content: tag + content: tag, }, { property: 'og:title', - content: tag + content: tag, }, { property: 'og:url', - content: nconf.get('url') + '/tags/' + tag - } + content: nconf.get('url') + '/tags/' + tag, + }, ]; templateData.topics = topics; @@ -86,8 +86,8 @@ tagsController.getTags = function (req, res, next) { var data = { tags: tags, nextStart: 100, - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[tags:tags]]'}]), - title: '[[pages:tags]]' + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[tags:tags]]' }]), + title: '[[pages:tags]]', }; res.render('tags', data); }); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 0677c0a8c3..1d813868ae 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -39,7 +39,7 @@ topicsController.get = function (req, res, callback) { }, topic: function (next) { topics.getTopicData(tid, next); - } + }, }, next); }, function (results, next) { @@ -113,7 +113,7 @@ topicsController.get = function (req, res, callback) { currentPage = Math.max(1, Math.ceil(index / settings.postsPerPage)); } - var start = (currentPage - 1) * settings.postsPerPage + postIndex; + var start = ((currentPage - 1) * settings.postsPerPage) + postIndex; var stop = start + settings.postsPerPage - 1; topics.getTopicWithPosts(results.topic, set, req.uid, start, stop, reverse, next); @@ -125,18 +125,17 @@ topicsController.get = function (req, res, callback) { topics.modifyPostsByPrivilege(topicData, userPrivileges); - plugins.fireHook('filter:controllers.topic.get', {topicData: topicData, uid: req.uid}, next); + plugins.fireHook('filter:controllers.topic.get', { topicData: topicData, uid: req.uid }, next); }, function (data, next) { - var breadcrumbs = [ { text: data.topicData.category.name, - url: nconf.get('relative_path') + '/category/' + data.topicData.category.slug + url: nconf.get('relative_path') + '/category/' + data.topicData.category.slug, }, { - text: data.topicData.title - } + text: data.topicData.title, + }, ]; helpers.buildCategoryBreadcrumbs(data.topicData.category.parentCid, function (err, crumbs) { @@ -149,7 +148,7 @@ topicsController.get = function (req, res, callback) { }, function (topicData, next) { function findPost(index) { - for(var i = 0; i < topicData.posts.length; ++i) { + for (var i = 0; i < topicData.posts.length; i += 1) { if (parseInt(topicData.posts[i].index, 10) === parseInt(index, 10)) { return topicData.posts[i]; } @@ -187,71 +186,71 @@ topicsController.get = function (req, res, callback) { res.locals.metaTags = [ { - name: "title", - content: topicData.titleRaw + name: 'title', + content: topicData.titleRaw, }, { - name: "description", - content: description + name: 'description', + content: description, }, { property: 'og:title', - content: topicData.titleRaw + content: topicData.titleRaw, }, { property: 'og:description', - content: description + content: description, }, { - property: "og:type", - content: 'article' + property: 'og:type', + content: 'article', }, { - property: "og:url", + property: 'og:url', content: nconf.get('url') + '/topic/' + topicData.slug + (req.params.post_index ? ('/' + req.params.post_index) : ''), - noEscape: true + noEscape: true, }, { property: 'og:image', content: ogImageUrl, - noEscape: true + noEscape: true, }, { - property: "og:image:url", + property: 'og:image:url', content: ogImageUrl, - noEscape: true + noEscape: true, }, { - property: "article:published_time", - content: utils.toISOString(topicData.timestamp) + property: 'article:published_time', + content: utils.toISOString(topicData.timestamp), }, { property: 'article:modified_time', - content: utils.toISOString(topicData.lastposttime) + content: utils.toISOString(topicData.lastposttime), }, { property: 'article:section', - content: topicData.category ? topicData.category.name : '' - } + content: topicData.category ? topicData.category.name : '', + }, ]; res.locals.linkTags = [ { rel: 'alternate', type: 'application/rss+xml', - href: nconf.get('url') + '/topic/' + tid + '.rss' - } + href: nconf.get('url') + '/topic/' + tid + '.rss', + }, ]; if (topicData.category) { res.locals.linkTags.push({ rel: 'up', - href: nconf.get('url') + '/category/' + topicData.category.slug + href: nconf.get('url') + '/category/' + topicData.category.slug, }); } next(null, topicData); - } + }, ], function (err, data) { if (err) { return callback(err); @@ -316,8 +315,8 @@ topicsController.teaser = function (req, res, next) { if (!pid) { return res.status(404).json('not-found'); } - posts.getPostSummaryByPids([pid], req.uid, {stripTags: false}, next); - } + posts.getPostSummaryByPids([pid], req.uid, { stripTags: false }, next); + }, ], function (err, posts) { if (err) { return next(err); @@ -341,7 +340,7 @@ topicsController.pagination = function (req, res, callback) { async.parallel({ privileges: async.apply(privileges.topics.get, tid, req.uid), settings: async.apply(user.getSettings, req.uid), - topic: async.apply(topics.getTopicData, tid) + topic: async.apply(topics.getTopicData, tid), }, function (err, results) { if (err || !results.topic) { return callback(err); diff --git a/src/controllers/unread.js b/src/controllers/unread.js index 83de85a67e..c5d0d4d950 100644 --- a/src/controllers/unread.js +++ b/src/controllers/unread.js @@ -12,7 +12,7 @@ var helpers = require('./helpers'); var unreadController = {}; -var validFilter = {'': true, 'new': true, 'watched': true}; +var validFilter = { '': true, new: true, watched: true }; unreadController.get = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; @@ -32,7 +32,7 @@ unreadController.get = function (req, res, next) { }, settings: function (next) { user.getSettings(req.uid, next); - } + }, }, next); }, function (_results, next) { @@ -41,7 +41,7 @@ unreadController.get = function (req, res, next) { var start = Math.max(0, (page - 1) * settings.topicsPerPage); var stop = start + settings.topicsPerPage - 1; topics.getUnreadTopics(cid, req.uid, start, stop, filter, next); - } + }, ], function (err, data) { if (err) { return next(err); @@ -59,7 +59,7 @@ unreadController.get = function (req, res, next) { data.selectedCategory = results.watchedCategories.selectedCategory; if (req.path.startsWith('/api/unread') || req.path.startsWith('/unread')) { - data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[unread:title]]'}]); + data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[unread:title]]' }]); } data.title = '[[pages:unread]]'; @@ -67,17 +67,17 @@ unreadController.get = function (req, res, next) { name: '[[unread:all-topics]]', url: 'unread', selected: filter === '', - filter: '' + filter: '', }, { name: '[[unread:new-topics]]', url: 'unread/new', selected: filter === 'new', - filter: 'new' + filter: 'new', }, { name: '[[unread:watched-topics]]', url: 'unread/watched', selected: filter === 'watched', - filter: 'watched' + filter: 'watched', }]; data.selectedFilter = data.filters.find(function (filter) { diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 22e533a33d..82556ee12c 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var fs = require('fs'); var path = require('path'); @@ -30,7 +30,7 @@ uploadsController.upload = function (req, res, filesIterator) { deleteTempFiles(files); if (err) { - return res.status(500).json({path: req.path, error: err.message}); + return res.status(500).json({ path: req.path, error: err.message }); } res.status(200).send(images); @@ -60,13 +60,13 @@ function uploadAsImage(req, uploadedFile, callback) { if (plugins.hasListeners('filter:uploadImage')) { return plugins.fireHook('filter:uploadImage', { image: uploadedFile, - uid: req.uid + uid: req.uid, }, callback); } file.isFileTypeAllowed(uploadedFile.path, next); }, function (next) { - uploadFile(req.uid, uploadedFile, next); + uploadsController.uploadFile(req.uid, uploadedFile, next); }, function (fileObj, next) { if (parseInt(meta.config.maximumImageWidth, 10) === 0) { @@ -74,7 +74,7 @@ function uploadAsImage(req, uploadedFile, callback) { } resizeImage(fileObj, next); - } + }, ], callback); } @@ -90,8 +90,8 @@ function uploadAsFile(req, uploadedFile, callback) { if (parseInt(meta.config.allowFileUploads, 10) !== 1) { return next(new Error('[[error:uploads-are-disabled]]')); } - uploadFile(req.uid, uploadedFile, next); - } + uploadsController.uploadFile(req.uid, uploadedFile, next); + }, ], callback); } @@ -113,20 +113,19 @@ function resizeImage(fileObj, callback) { path: fileObj.path, target: path.join(dirname, basename + '-resized' + extname), extension: extname, - width: parseInt(meta.config.maximumImageWidth, 10) || 760 + width: parseInt(meta.config.maximumImageWidth, 10) || 760, }, next); }, function (next) { - // Return the resized version to the composer/postData var dirname = path.dirname(fileObj.url); var extname = path.extname(fileObj.url); var basename = path.basename(fileObj.url, extname); - fileObj.url = path.join(dirname, basename + '-resized' + extname); + fileObj.url = dirname + '/' + basename + '-resized' + extname; next(null, fileObj); - } + }, ], callback); } @@ -151,19 +150,19 @@ uploadsController.uploadThumb = function (req, res, next) { path: uploadedFile.path, extension: path.extname(uploadedFile.name), width: size, - height: size + height: size, }, next); }, function (next) { if (plugins.hasListeners('filter:uploadImage')) { return plugins.fireHook('filter:uploadImage', { image: uploadedFile, - uid: req.uid + uid: req.uid, }, next); } - uploadFile(req.uid, uploadedFile, next); - } + uploadsController.uploadFile(req.uid, uploadedFile, next); + }, ], next); }, next); }; @@ -172,14 +171,14 @@ uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) { if (plugins.hasListeners('filter:uploadImage')) { return plugins.fireHook('filter:uploadImage', { image: uploadedFile, - uid: uid + uid: uid, }, callback); } if (plugins.hasListeners('filter:uploadFile')) { return plugins.fireHook('filter:uploadFile', { file: uploadedFile, - uid: uid + uid: uid, }, callback); } @@ -189,15 +188,15 @@ uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) { }, function (next) { saveFileToLocal(uploadedFile, next); - } + }, ], callback); }; -function uploadFile(uid, uploadedFile, callback) { +uploadsController.uploadFile = function (uid, uploadedFile, callback) { if (plugins.hasListeners('filter:uploadFile')) { return plugins.fireHook('filter:uploadFile', { file: uploadedFile, - uid: uid + uid: uid, }, callback); } @@ -218,7 +217,7 @@ function uploadFile(uid, uploadedFile, callback) { } saveFileToLocal(uploadedFile, callback); -} +}; function saveFileToLocal(uploadedFile, callback) { var extension = file.typeToExtension(uploadedFile.type); @@ -237,9 +236,9 @@ function saveFileToLocal(uploadedFile, callback) { next(null, { url: nconf.get('relative_path') + upload.url, path: upload.path, - name: uploadedFile.name + name: uploadedFile.name, }); - } + }, ], callback); } diff --git a/src/controllers/user.js b/src/controllers/user.js new file mode 100644 index 0000000000..0f93f549b3 --- /dev/null +++ b/src/controllers/user.js @@ -0,0 +1,99 @@ +'use strict'; + +var async = require('async'); + +var user = require('../user'); +var meta = require('../meta'); +var accountHelpers = require('./accounts/helpers'); + +var userController = module.exports; + +userController.getCurrentUser = function (req, res, next) { + if (!req.uid) { + return res.status(401).json('not-authorized'); + } + async.waterfall([ + function (next) { + user.getUserField(req.uid, 'userslug', next); + }, + function (userslug, next) { + accountHelpers.getUserDataByUserSlug(userslug, req.uid, next); + }, + function (userData) { + res.json(userData); + }, + ], next); +}; + + +userController.getUserByUID = function (req, res, next) { + byType('uid', req, res, next); +}; + +userController.getUserByUsername = function (req, res, next) { + byType('username', req, res, next); +}; + +userController.getUserByEmail = function (req, res, next) { + byType('email', req, res, next); +}; + +function byType(type, req, res, next) { + async.waterfall([ + function (next) { + userController.getUserDataByField(req.uid, type, req.params[type], next); + }, + function (data, next) { + if (!data) { + return next(); + } + res.json(data); + }, + ], next); +} + +userController.getUserDataByField = function (callerUid, field, fieldValue, callback) { + async.waterfall([ + function (next) { + if (field === 'uid') { + next(null, fieldValue); + } else if (field === 'username') { + user.getUidByUsername(fieldValue, next); + } else if (field === 'email') { + user.getUidByEmail(fieldValue, next); + } else { + next(null, null); + } + }, + function (uid, next) { + if (!uid) { + return next(null, null); + } + userController.getUserDataByUID(callerUid, uid, next); + }, + ], callback); +}; + +userController.getUserDataByUID = function (callerUid, uid, callback) { + if (!parseInt(callerUid, 10) && parseInt(meta.config.privateUserInfo, 10) === 1) { + return callback(new Error('[[error:no-privileges]]')); + } + + if (!parseInt(uid, 10)) { + return callback(new Error('[[error:no-user]]')); + } + + async.parallel({ + userData: async.apply(user.getUserData, uid), + settings: async.apply(user.getSettings, uid), + }, function (err, results) { + if (err || !results.userData) { + return callback(err || new Error('[[error:no-user]]')); + } + + results.userData.email = results.settings.showemail ? results.userData.email : undefined; + results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; + + callback(null, results.userData); + }); +}; diff --git a/src/controllers/users.js b/src/controllers/users.js index baf18a5b64..45cb5f1e21 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var user = require('../user'); @@ -8,9 +8,7 @@ var pagination = require('../pagination'); var db = require('../database'); var helpers = require('./helpers'); - -var usersController = {}; - +var usersController = module.exports; usersController.index = function (req, res, next) { var section = req.query.section || 'joindate'; @@ -20,7 +18,7 @@ usersController.index = function (req, res, next) { 'sort-posts': usersController.getUsersSortedByPosts, 'sort-reputation': usersController.getUsersSortedByReputation, banned: usersController.getBannedUsers, - flagged: usersController.getFlaggedUsers + flagged: usersController.getFlaggedUsers, }; if (req.query.term) { @@ -33,62 +31,65 @@ usersController.index = function (req, res, next) { }; usersController.search = function (req, res, next) { - async.parallel({ - search: function (next) { - user.search({ - query: req.query.term, - searchBy: req.query.searchBy || 'username', - page: req.query.page || 1, - sortBy: req.query.sortBy, - onlineOnly: req.query.onlineOnly === 'true', - bannedOnly: req.query.bannedOnly === 'true', - flaggedOnly: req.query.flaggedOnly === 'true' + async.waterfall([ + function (next) { + async.parallel({ + search: function (next) { + user.search({ + query: req.query.term, + searchBy: req.query.searchBy || 'username', + page: req.query.page || 1, + sortBy: req.query.sortBy, + onlineOnly: req.query.onlineOnly === 'true', + bannedOnly: req.query.bannedOnly === 'true', + flaggedOnly: req.query.flaggedOnly === 'true', + }, next); + }, + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(req.uid, next); + }, }, next); }, - isAdminOrGlobalMod: function (next) { - user.isAdminOrGlobalMod(req.uid, next); - } - }, function (err, results) { - if (err) { - return next(err); - } + function (results, next) { + var section = req.query.section || 'joindate'; - var section = req.query.section || 'joindate'; - - results.search.isAdminOrGlobalMod = results.isAdminOrGlobalMod; - results.search.pagination = pagination.create(req.query.page, results.search.pageCount, req.query); - results.search['section_' + section] = true; - render(req, res, results.search, next); - }); + results.search.isAdminOrGlobalMod = results.isAdminOrGlobalMod; + results.search.pagination = pagination.create(req.query.page, results.search.pageCount, req.query); + results.search['section_' + section] = true; + render(req, res, results.search, next); + }, + ], next); }; usersController.getOnlineUsers = function (req, res, next) { - async.parallel({ - users: function (next) { - usersController.getUsers('users:online', req.uid, req.query, next); + async.waterfall([ + function (next) { + async.parallel({ + users: function (next) { + usersController.getUsers('users:online', req.uid, req.query, next); + }, + guests: function (next) { + require('../socket.io/admin/rooms').getTotalGuestCount(next); + }, + }, next); }, - guests: function (next) { - require('../socket.io/admin/rooms').getTotalGuestCount(next); - } - }, function (err, results) { - if (err) { - return next(err); - } - var userData = results.users; - var hiddenCount = 0; - if (!userData.isAdminOrGlobalMod) { - userData.users = userData.users.filter(function (user) { - if (user && user.status === 'offline') { - hiddenCount ++; - } - return user && user.status !== 'offline'; - }); - } + function (results, next) { + var userData = results.users; + var hiddenCount = 0; + if (!userData.isAdminOrGlobalMod) { + userData.users = userData.users.filter(function (user) { + if (user && user.status === 'offline') { + hiddenCount += 1; + } + return user && user.status !== 'offline'; + }); + } - userData.anonymousUserCount = results.guests + hiddenCount; + userData.anonymousUserCount = results.guests + hiddenCount; - render(req, res, userData, next); - }); + render(req, res, userData, next); + }, + ], next); }; usersController.getUsersSortedByPosts = function (req, res, next) { @@ -107,61 +108,56 @@ usersController.getUsersSortedByJoinDate = function (req, res, next) { }; usersController.getBannedUsers = function (req, res, next) { - usersController.getUsers('users:banned', req.uid, req.query, function (err, userData) { - if (err) { - return next(err); - } - - if (!userData.isAdminOrGlobalMod) { - return next(); - } - - render(req, res, userData, next); - }); + renderIfAdminOrGlobalMod('users:banned', req, res, next); }; usersController.getFlaggedUsers = function (req, res, next) { - usersController.getUsers('users:flags', req.uid, req.query, function (err, userData) { - if (err) { - return next(err); - } - - if (!userData.isAdminOrGlobalMod) { - return next(); - } - - render(req, res, userData, next); - }); + renderIfAdminOrGlobalMod('users:flags', req, res, next); }; -usersController.renderUsersPage = function (set, req, res, next) { - usersController.getUsers(set, req.uid, req.query, function (err, userData) { - if (err) { - return next(err); - } +function renderIfAdminOrGlobalMod(set, req, res, next) { + async.waterfall([ + function (next) { + user.isAdminOrGlobalMod(req.uid, next); + }, + function (isAdminOrGlobalMod, next) { + if (!isAdminOrGlobalMod) { + return helpers.notAllowed(req, res); + } + usersController.renderUsersPage(set, req, res, next); + }, + ], next); +} - render(req, res, userData, next); - }); +usersController.renderUsersPage = function (set, req, res, next) { + async.waterfall([ + function (next) { + usersController.getUsers(set, req.uid, req.query, next); + }, + function (userData, next) { + render(req, res, userData, next); + }, + ], next); }; usersController.getUsers = function (set, uid, query, callback) { var setToData = { - 'users:postcount': {title: '[[pages:users/sort-posts]]', crumb: '[[users:top_posters]]'}, - 'users:reputation': {title: '[[pages:users/sort-reputation]]', crumb: '[[users:most_reputation]]'}, - 'users:joindate': {title: '[[pages:users/latest]]', crumb: '[[global:users]]'}, - 'users:online': {title: '[[pages:users/online]]', crumb: '[[global:online]]'}, - 'users:banned': {title: '[[pages:users/banned]]', crumb: '[[user:banned]]'}, - 'users:flags': {title: '[[pages:users/most-flags]]', crumb: '[[users:most_flags]]'}, + 'users:postcount': { title: '[[pages:users/sort-posts]]', crumb: '[[users:top_posters]]' }, + 'users:reputation': { title: '[[pages:users/sort-reputation]]', crumb: '[[users:most_reputation]]' }, + 'users:joindate': { title: '[[pages:users/latest]]', crumb: '[[global:users]]' }, + 'users:online': { title: '[[pages:users/online]]', crumb: '[[global:online]]' }, + 'users:banned': { title: '[[pages:users/banned]]', crumb: '[[user:banned]]' }, + 'users:flags': { title: '[[pages:users/most-flags]]', crumb: '[[users:most_flags]]' }, }; if (!setToData[set]) { - setToData[set] = {title: '', crumb: ''}; + setToData[set] = { title: '', crumb: '' }; } - var breadcrumbs = [{text: setToData[set].crumb}]; + var breadcrumbs = [{ text: setToData[set].crumb }]; if (set !== 'users:joindate') { - breadcrumbs.unshift({text: '[[global:users]]', url: '/users'}); + breadcrumbs.unshift({ text: '[[global:users]]', url: '/users' }); } var page = parseInt(query.page, 10) || 1; @@ -169,59 +165,62 @@ usersController.getUsers = function (set, uid, query, callback) { var start = Math.max(0, page - 1) * resultsPerPage; var stop = start + resultsPerPage - 1; - async.parallel({ - isAdminOrGlobalMod: function (next) { - user.isAdminOrGlobalMod(uid, next); + async.waterfall([ + function (next) { + async.parallel({ + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(uid, next); + }, + usersData: function (next) { + usersController.getUsersAndCount(set, uid, start, stop, next); + }, + }, next); }, - usersData: function (next) { - usersController.getUsersAndCount(set, uid, start, stop, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } - - var pageCount = Math.ceil(results.usersData.count / resultsPerPage); - var userData = { - users: results.usersData.users, - pagination: pagination.create(page, pageCount, query), - userCount: results.usersData.count, - title: setToData[set].title || '[[pages:users/latest]]', - breadcrumbs: helpers.buildBreadcrumbs(breadcrumbs), - isAdminOrGlobalMod: results.isAdminOrGlobalMod - }; - userData['section_' + (query.section || 'joindate')] = true; - callback(null, userData); - }); + function (results, next) { + var pageCount = Math.ceil(results.usersData.count / resultsPerPage); + var userData = { + users: results.usersData.users, + pagination: pagination.create(page, pageCount, query), + userCount: results.usersData.count, + title: setToData[set].title || '[[pages:users/latest]]', + breadcrumbs: helpers.buildBreadcrumbs(breadcrumbs), + isAdminOrGlobalMod: results.isAdminOrGlobalMod, + }; + userData['section_' + (query.section || 'joindate')] = true; + next(null, userData); + }, + ], callback); }; usersController.getUsersAndCount = function (set, uid, start, stop, callback) { - async.parallel({ - users: function (next) { - user.getUsersFromSet(set, uid, start, stop, next); + async.waterfall([ + function (next) { + async.parallel({ + users: function (next) { + user.getUsersFromSet(set, uid, start, stop, next); + }, + count: function (next) { + if (set === 'users:online') { + var now = Date.now(); + db.sortedSetCount('users:online', now - 300000, '+inf', next); + } else if (set === 'users:banned') { + db.sortedSetCard('users:banned', next); + } else if (set === 'users:flags') { + db.sortedSetCard('users:flags', next); + } else { + db.getObjectField('global', 'userCount', next); + } + }, + }, next); }, - count: function (next) { - if (set === 'users:online') { - var now = Date.now(); - db.sortedSetCount('users:online', now - 300000, '+inf', next); - } else if (set === 'users:banned') { - db.sortedSetCard('users:banned', next); - } else if (set === 'users:flags') { - db.sortedSetCard('users:flags', next); - } else { - db.getObjectField('global', 'userCount', next); - } - } - }, function (err, results) { - if (err) { - return callback(err); - } - results.users = results.users.filter(function (user) { - return user && parseInt(user.uid, 10); - }); + function (results, next) { + results.users = results.users.filter(function (user) { + return user && parseInt(user.uid, 10); + }); - callback(null, results); - }); + next(null, results); + }, + ], callback); }; function render(req, res, data, next) { @@ -232,16 +231,15 @@ function render(req, res, data, next) { data.adminInviteOnly = registrationType === 'admin-invite-only'; data['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; - user.getInvitesNumber(req.uid, function (err, numInvites) { - if (err) { - return next(err); - } + async.waterfall([ + function (next) { + user.getInvitesNumber(req.uid, next); + }, + function (numInvites) { + res.append('X-Total-Count', data.userCount); + data.invites = numInvites; - res.append('X-Total-Count', data.userCount); - data.invites = numInvites; - - res.render('users', data); - }); + res.render('users', data); + }, + ], next); } - -module.exports = usersController; diff --git a/src/coverPhoto.js b/src/coverPhoto.js index 6307110253..024ae48f20 100644 --- a/src/coverPhoto.js +++ b/src/coverPhoto.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var coverPhoto = {}; var meta = require('./meta'); @@ -14,13 +14,13 @@ coverPhoto.getDefaultProfileCover = function (uid) { }; function getCover(type, id) { - if (meta.config[type + ':defaultCovers']) { + if (meta.config[type + ':defaultCovers']) { var covers = meta.config[type + ':defaultCovers'].trim().split(/[\s,]+/g); - + if (typeof id === 'string') { id = (id.charCodeAt(0) + id.charCodeAt(1)) % covers.length; } else { - id = id % covers.length; + id %= covers.length; } return covers[id]; diff --git a/src/database.js b/src/database.js index 65a5453d09..c62255306b 100644 --- a/src/database.js +++ b/src/database.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var nconf = require('nconf'); var databaseName = nconf.get('database'); @@ -11,4 +11,4 @@ if (!databaseName) { var primaryDB = require('./database/' + databaseName); -module.exports = primaryDB; \ No newline at end of file +module.exports = primaryDB; diff --git a/src/database/mongo.js b/src/database/mongo.js index 3a3331e900..8e6494ffd7 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -2,7 +2,6 @@ 'use strict'; (function (module) { - var winston = require('winston'); var async = require('async'); var nconf = require('nconf'); @@ -17,30 +16,30 @@ { name: 'mongo:host', description: 'Host IP or address of your MongoDB instance', - 'default': nconf.get('mongo:host') || '127.0.0.1' + default: nconf.get('mongo:host') || '127.0.0.1', }, { name: 'mongo:port', description: 'Host port of your MongoDB instance', - 'default': nconf.get('mongo:port') || 27017 + default: nconf.get('mongo:port') || 27017, }, { name: 'mongo:username', description: 'MongoDB username', - 'default': nconf.get('mongo:username') || '' + default: nconf.get('mongo:username') || '', }, { name: 'mongo:password', description: 'Password of your MongoDB database', hidden: true, default: nconf.get('mongo:password') || '', - before: function (value) { value = value || nconf.get('mongo:password') || ''; return value; } + before: function (value) { value = value || nconf.get('mongo:password') || ''; return value; }, }, { - name: "mongo:database", - description: "MongoDB database name", - 'default': nconf.get('mongo:database') || 'nodebb' - } + name: 'mongo:database', + description: 'MongoDB database name', + default: nconf.get('mongo:database') || 'nodebb', + }, ]; module.helpers = module.helpers || {}; @@ -48,13 +47,8 @@ module.init = function (callback) { callback = callback || function () { }; - var mongoClient; - try { - mongoClient = require('mongodb').MongoClient; - } catch (err) { - winston.error('Unable to initialize MongoDB! Is MongoDB installed? Error :' + err.message); - return callback(err); - } + + var mongoClient = require('mongodb').MongoClient; var usernamePassword = ''; if (nconf.get('mongo:username') && nconf.get('mongo:password')) { @@ -76,7 +70,7 @@ var ports = nconf.get('mongo:port').toString().split(','); var servers = []; - for (var i = 0; i < hosts.length; i++) { + for (var i = 0; i < hosts.length; i += 1) { servers.push(hosts[i] + ':' + ports[i]); } @@ -84,15 +78,18 @@ var connOptions = { server: { - poolSize: parseInt(nconf.get('mongo:poolSize'), 10) || 10 - } + poolSize: parseInt(nconf.get('mongo:poolSize'), 10) || 10, + socketOptions: { autoReconnect: true, keepAlive: nconf.get('mongo:keepAlive') || 0 }, + reconnectTries: 3600, + reconnectInterval: 1000, + }, }; - connOptions = _.deepExtend((nconf.get('mongo:options') || {}), connOptions); + connOptions = _.deepExtend(connOptions, nconf.get('mongo:options') || {}); mongoClient.connect(connString, connOptions, function (err, _db) { if (err) { - winston.error("NodeBB could not connect to your Mongo database. Mongo returned the following error: " + err.message); + winston.error('NodeBB could not connect to your Mongo database. Mongo returned the following error: ' + err.message); return callback(err); } @@ -108,10 +105,7 @@ if (nconf.get('mongo:password') && nconf.get('mongo:username')) { db.authenticate(nconf.get('mongo:username'), nconf.get('mongo:password'), function (err) { - if (err) { - return callback(err); - } - callback(); + callback(err); }); } else { winston.warn('You have no mongo password setup!'); @@ -135,13 +129,13 @@ module.sessionStore = new sessionStore({ client: rdb.client, - ttl: ttl + ttl: ttl, }); } else if (nconf.get('mongo')) { sessionStore = require('connect-mongo')(session); module.sessionStore = new sessionStore({ db: db, - ttl: ttl + ttl: ttl, }); } @@ -162,7 +156,7 @@ async.series([ async.apply(createIndex, 'objects', { _key: 1, score: -1 }, { background: true }), async.apply(createIndex, 'objects', { _key: 1, value: -1 }, { background: true, unique: true, sparse: true }), - async.apply(createIndex, 'objects', { expireAt: 1 }, { expireAfterSeconds: 0, background: true }) + async.apply(createIndex, 'objects', { expireAt: 1 }, { expireAfterSeconds: 0, background: true }), ], function (err) { if (err) { winston.error('Error creating index ' + err.message); @@ -189,10 +183,10 @@ } async.parallel({ serverStatus: function (next) { - db.command({ 'serverStatus': 1 }, next); + db.command({ serverStatus: 1 }, next); }, stats: function (next) { - db.command({ 'dbStats': 1 }, next); + db.command({ dbStats: 1 }, next); }, listCollections: function (next) { db.listCollections().toArray(function (err, items) { @@ -203,7 +197,7 @@ db.collection(collection.name).stats(next); }, next); }); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -219,7 +213,7 @@ avgObjSize: collectionInfo.avgObjSize, storageSize: collectionInfo.storageSize, totalIndexSize: collectionInfo.totalIndexSize, - indexSizes: collectionInfo.indexSizes + indexSizes: collectionInfo.indexSizes, }; }); @@ -246,5 +240,4 @@ module.close = function () { db.close(); }; - -} (exports)); +}(exports)); diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index 4951b44529..57c72cdc91 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; module.exports = function (db, module) { var helpers = module.helpers.mongo; @@ -9,7 +9,7 @@ module.exports = function (db, module) { return callback(); } - db.collection('objects').update({_key: key}, {$set: data}, {upsert: true, w: 1}, function (err) { + db.collection('objects').update({ _key: key }, { $set: data }, { upsert: true, w: 1 }, function (err) { callback(err); }); }; @@ -29,14 +29,14 @@ module.exports = function (db, module) { if (!key) { return callback(); } - db.collection('objects').findOne({_key: key}, {_id: 0, _key: 0}, callback); + db.collection('objects').findOne({ _key: key }, { _id: 0, _key: 0 }, callback); }; module.getObjects = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, []); } - db.collection('objects').find({_key: {$in: keys}}, {_id: 0}).toArray(function (err, data) { + db.collection('objects').find({ _key: { $in: keys } }, { _id: 0 }).toArray(function (err, data) { if (err) { return callback(err); } @@ -44,7 +44,7 @@ module.exports = function (db, module) { var map = helpers.toMap(data); var returnData = []; - for (var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { returnData.push(map[keys[i]]); } @@ -58,10 +58,10 @@ module.exports = function (db, module) { } field = helpers.fieldToString(field); var _fields = { - _id: 0 + _id: 0, }; _fields[field] = 1; - db.collection('objects').findOne({_key: key}, {fields: _fields}, function (err, item) { + db.collection('objects').findOne({ _key: key }, { fields: _fields }, function (err, item) { if (err || !item) { return callback(err, null); } @@ -75,20 +75,21 @@ module.exports = function (db, module) { return callback(); } var _fields = { - _id: 0 + _id: 0, }; + var i; - for(var i = 0; i < fields.length; ++i) { + for (i = 0; i < fields.length; i += 1) { fields[i] = helpers.fieldToString(fields[i]); _fields[fields[i]] = 1; } - db.collection('objects').findOne({_key: key}, {fields: _fields}, function (err, item) { + db.collection('objects').findOne({ _key: key }, { fields: _fields }, function (err, item) { if (err) { return callback(err); } item = item || {}; var result = {}; - for(i = 0; i < fields.length; ++i) { + for (i = 0; i < fields.length; i += 1) { result[fields[i]] = item[fields[i]] !== undefined ? item[fields[i]] : null; } callback(null, result); @@ -101,15 +102,15 @@ module.exports = function (db, module) { } var _fields = { _id: 0, - _key: 1 + _key: 1, }; - for(var i = 0; i < fields.length; ++i) { + for (var i = 0; i < fields.length; i += 1) { fields[i] = helpers.fieldToString(fields[i]); _fields[fields[i]] = 1; } - db.collection('objects').find({_key: {$in: keys}}, {fields: _fields}).toArray(function (err, items) { + db.collection('objects').find({ _key: { $in: keys } }, { fields: _fields }).toArray(function (err, items) { if (err) { return callback(err); } @@ -122,10 +123,10 @@ module.exports = function (db, module) { var returnData = []; var item; - for (var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { item = map[keys[i]] || {}; - for (var k = 0; k < fields.length; ++k) { + for (var k = 0; k < fields.length; k += 1) { if (item[fields[k]] === undefined) { item[fields[k]] = null; } @@ -145,12 +146,12 @@ module.exports = function (db, module) { module.getObjectValues = function (key, callback) { module.getObject(key, function (err, data) { - if(err) { + if (err) { return callback(err); } var values = []; - for(var key in data) { + for (var key in data) { if (data && data.hasOwnProperty(key)) { values.push(data[key]); } @@ -166,7 +167,7 @@ module.exports = function (db, module) { var data = {}; field = helpers.fieldToString(field); data[field] = ''; - db.collection('objects').findOne({_key: key}, {fields: data}, function (err, item) { + db.collection('objects').findOne({ _key: key }, { fields: data }, function (err, item) { callback(err, !!item && item[field] !== undefined && item[field] !== null); }); }; @@ -182,7 +183,7 @@ module.exports = function (db, module) { data[field] = ''; }); - db.collection('objects').findOne({_key: key}, {fields: data}, function (err, item) { + db.collection('objects').findOne({ _key: key }, { fields: data }, function (err, item) { if (err) { return callback(err); } @@ -216,7 +217,7 @@ module.exports = function (db, module) { data[field] = ''; }); - db.collection('objects').update({_key: key}, {$unset : data}, function (err) { + db.collection('objects').update({ _key: key }, { $unset: data }, function (err) { callback(err); }); }; @@ -240,8 +241,8 @@ module.exports = function (db, module) { field = helpers.fieldToString(field); data[field] = value; - db.collection('objects').findAndModify({_key: key}, {}, {$inc: data}, {new: true, upsert: true}, function (err, result) { + db.collection('objects').findAndModify({ _key: key }, {}, { $inc: data }, { new: true, upsert: true }, function (err, result) { callback(err, result && result.value ? result.value[field] : null); }); }; -}; \ No newline at end of file +}; diff --git a/src/database/mongo/helpers.js b/src/database/mongo/helpers.js index 0985e62617..47f8434c77 100644 --- a/src/database/mongo/helpers.js +++ b/src/database/mongo/helpers.js @@ -1,10 +1,10 @@ -"use strict"; +'use strict'; var helpers = {}; helpers.toMap = function (data) { var map = {}; - for (var i = 0; i < data.length; ++i) { + for (var i = 0; i < data.length; i += 1) { map[data[i]._key] = data[i]; data[i]._key = undefined; } @@ -12,11 +12,11 @@ helpers.toMap = function (data) { }; helpers.fieldToString = function (field) { - if(field === null || field === undefined) { + if (field === null || field === undefined) { return field; } - if(typeof field !== 'string') { + if (typeof field !== 'string') { field = field.toString(); } // if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E @@ -25,7 +25,7 @@ helpers.fieldToString = function (field) { }; helpers.valueToString = function (value) { - if(value === null || value === undefined) { + if (value === null || value === undefined) { return value; } @@ -34,4 +34,4 @@ helpers.valueToString = function (value) { helpers.noop = function () {}; -module.exports = helpers; \ No newline at end of file +module.exports = helpers; diff --git a/src/database/mongo/list.js b/src/database/mongo/list.js index c4b4ffbb6c..0c5e2955e5 100644 --- a/src/database/mongo/list.js +++ b/src/database/mongo/list.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; module.exports = function (db, module) { var helpers = module.helpers.mongo; @@ -18,7 +18,7 @@ module.exports = function (db, module) { } if (exists) { - db.collection('objects').update({_key:key}, {$push: {array: {$each: [value], $position: 0}}}, {upsert:true, w:1 }, function (err, res) { + db.collection('objects').update({ _key: key }, { $push: { array: { $each: [value], $position: 0 } } }, { upsert: true, w: 1 }, function (err) { callback(err); }); } else { @@ -33,7 +33,7 @@ module.exports = function (db, module) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').update({ _key: key }, { $push: { array: value } }, {upsert:true, w:1}, function (err, res) { + db.collection('objects').update({ _key: key }, { $push: { array: value } }, { upsert: true, w: 1 }, function (err) { callback(err); }); }; @@ -48,20 +48,20 @@ module.exports = function (db, module) { return callback(err); } - db.collection('objects').update({_key: key }, { $pop: { array: 1 } }, function (err, result) { + db.collection('objects').update({ _key: key }, { $pop: { array: 1 } }, function (err) { callback(err, (value && value.length) ? value[0] : null); }); }); }; module.listRemoveAll = function (key, value, callback) { - callback = callback || helpers.noop; + callback = callback || helpers.noop; if (!key) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').update({_key: key }, { $pull: { array: value } }, function (err, res) { + db.collection('objects').update({ _key: key }, { $pull: { array: value } }, function (err) { callback(err); }); }; @@ -76,7 +76,7 @@ module.exports = function (db, module) { return callback(err); } - db.collection('objects').update({_key: key}, {$set: {array: value}}, function (err, res) { + db.collection('objects').update({ _key: key }, { $set: { array: value } }, function (err) { callback(err); }); }); @@ -87,8 +87,8 @@ module.exports = function (db, module) { return callback(); } - db.collection('objects').findOne({_key:key}, { array: 1}, function (err, data) { - if(err || !(data && data.array)) { + db.collection('objects').findOne({ _key: key }, { array: 1 }, function (err, data) { + if (err || !(data && data.array)) { return callback(err, []); } @@ -100,4 +100,4 @@ module.exports = function (db, module) { callback(null, data.array); }); }; -}; \ No newline at end of file +}; diff --git a/src/database/mongo/main.js b/src/database/mongo/main.js index 0aebaf75b2..4ca3bb2cd3 100644 --- a/src/database/mongo/main.js +++ b/src/database/mongo/main.js @@ -1,6 +1,4 @@ -"use strict"; - -var winston = require('winston'); +'use strict'; module.exports = function (db, module) { var helpers = module.helpers.mongo; @@ -23,7 +21,7 @@ module.exports = function (db, module) { if (!key) { return callback(); } - db.collection('objects').findOne({_key: key}, function (err, item) { + db.collection('objects').findOne({ _key: key }, function (err, item) { callback(err, item !== undefined && item !== null); }); }; @@ -33,7 +31,7 @@ module.exports = function (db, module) { if (!key) { return callback(); } - db.collection('objects').remove({_key: key}, function (err, res) { + db.collection('objects').remove({ _key: key }, function (err) { callback(err); }); }; @@ -43,7 +41,7 @@ module.exports = function (db, module) { if (!Array.isArray(keys) || !keys.length) { return callback(); } - db.collection('objects').remove({_key: {$in: keys}}, function (err, res) { + db.collection('objects').remove({ _key: { $in: keys } }, function (err) { callback(err); }); }; @@ -60,7 +58,7 @@ module.exports = function (db, module) { if (!key) { return callback(); } - var data = {value: value}; + var data = { value: value }; module.setObject(key, data, callback); }; @@ -69,14 +67,14 @@ module.exports = function (db, module) { if (!key) { return callback(); } - db.collection('objects').findAndModify({_key: key}, {}, {$inc: {value: 1}}, {new: true, upsert: true}, function (err, result) { + db.collection('objects').findAndModify({ _key: key }, {}, { $inc: { value: 1 } }, { new: true, upsert: true }, function (err, result) { callback(err, result && result.value ? result.value.value : null); }); }; module.rename = function (oldKey, newKey, callback) { callback = callback || helpers.noop; - db.collection('objects').update({_key: oldKey}, {$set:{_key: newKey}}, {multi: true}, function (err, res) { + db.collection('objects').update({ _key: oldKey }, { $set: { _key: newKey } }, { multi: true }, function (err) { callback(err); }); }; @@ -96,4 +94,4 @@ module.exports = function (db, module) { module.pexpireAt = function (key, timestamp, callback) { module.setObjectField(key, 'expireAt', new Date(timestamp), callback); }; -}; \ No newline at end of file +}; diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index 0a035a3398..18ce2a932a 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -1,11 +1,11 @@ -"use strict"; +'use strict'; module.exports = function (db, module) { var helpers = module.helpers.mongo; module.setAdd = function (key, value, callback) { callback = callback || helpers.noop; - if(!Array.isArray(value)) { + if (!Array.isArray(value)) { value = [value]; } @@ -14,17 +14,17 @@ module.exports = function (db, module) { }); db.collection('objects').update({ - _key: key + _key: key, }, { $addToSet: { members: { - $each: value - } - } + $each: value, + }, + }, }, { upsert: true, - w: 1 - }, function (err, res) { + w: 1, + }, function (err) { callback(err); }); }; @@ -36,7 +36,7 @@ module.exports = function (db, module) { return callback(); } - if(!Array.isArray(value)) { + if (!Array.isArray(value)) { value = [value]; } @@ -46,22 +46,22 @@ module.exports = function (db, module) { var bulk = db.collection('objects').initializeUnorderedBulkOp(); - for(var i = 0; i < keys.length; ++i) { - bulk.find({_key: keys[i]}).upsert().updateOne({ $addToSet: { + for (var i = 0; i < keys.length; i += 1) { + bulk.find({ _key: keys[i] }).upsert().updateOne({ $addToSet: { members: { - $each: value - } - }}); + $each: value, + }, + } }); } - bulk.execute(function (err, res) { + bulk.execute(function (err) { callback(err); }); }; module.setRemove = function (key, value, callback) { callback = callback || helpers.noop; - if(!Array.isArray(value)) { + if (!Array.isArray(value)) { value = [value]; } @@ -69,7 +69,7 @@ module.exports = function (db, module) { array[index] = helpers.valueToString(element); }); - db.collection('objects').update({_key: key}, {$pullAll: {members: value}}, function (err, res) { + db.collection('objects').update({ _key: key }, { $pullAll: { members: value } }, function (err) { callback(err); }); }; @@ -83,13 +83,13 @@ module.exports = function (db, module) { var bulk = db.collection('objects').initializeUnorderedBulkOp(); - for(var i = 0; i < keys.length; ++i) { - bulk.find({_key: keys[i]}).updateOne({$pull: { - members: value - }}); + for (var i = 0; i < keys.length; i += 1) { + bulk.find({ _key: keys[i] }).updateOne({ $pull: { + members: value, + } }); } - bulk.execute(function (err, res) { + bulk.execute(function (err) { callback(err); }); }; @@ -100,7 +100,7 @@ module.exports = function (db, module) { } value = helpers.valueToString(value); - db.collection('objects').findOne({_key: key, members: value}, {_id: 0, members: 0},function (err, item) { + db.collection('objects').findOne({ _key: key, members: value }, { _id: 0, members: 0 }, function (err, item) { callback(err, item !== null && item !== undefined); }); }; @@ -110,11 +110,11 @@ module.exports = function (db, module) { return callback(null, []); } - for (var i = 0; i < values.length; ++i) { + for (var i = 0; i < values.length; i += 1) { values[i] = helpers.valueToString(values[i]); } - db.collection('objects').findOne({_key: key}, {_id: 0, _key: 0}, function (err, items) { + db.collection('objects').findOne({ _key: key }, { _id: 0, _key: 0 }, function (err, items) { if (err) { return callback(err); } @@ -133,7 +133,7 @@ module.exports = function (db, module) { } value = helpers.valueToString(value); - db.collection('objects').find({_key: {$in : sets}, members: value}, {_id:0, members: 0}).toArray(function (err, result) { + db.collection('objects').find({ _key: { $in: sets }, members: value }, { _id: 0, members: 0 }).toArray(function (err, result) { if (err) { return callback(err); } @@ -154,7 +154,7 @@ module.exports = function (db, module) { if (!key) { return callback(null, []); } - db.collection('objects').findOne({_key: key}, {members: 1}, {_id: 0, _key: 0}, function (err, data) { + db.collection('objects').findOne({ _key: key }, { members: 1 }, { _id: 0, _key: 0 }, function (err, data) { callback(err, data ? data.members : []); }); }; @@ -163,7 +163,7 @@ module.exports = function (db, module) { if (!Array.isArray(keys) || !keys.length) { return callback(null, []); } - db.collection('objects').find({_key: {$in: keys}}, {_id: 0, _key: 1, members: 1}).toArray(function (err, data) { + db.collection('objects').find({ _key: { $in: keys } }, { _id: 0, _key: 1, members: 1 }).toArray(function (err, data) { if (err) { return callback(err); } @@ -174,7 +174,7 @@ module.exports = function (db, module) { }); var returnData = new Array(keys.length); - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { returnData[i] = sets[keys[i]] || []; } callback(null, returnData); @@ -185,7 +185,7 @@ module.exports = function (db, module) { if (!key) { return callback(null, 0); } - db.collection('objects').findOne({_key: key}, {_id: 0}, function (err, data) { + db.collection('objects').findOne({ _key: key }, { _id: 0 }, function (err, data) { callback(err, data ? data.members.length : 0); }); }; @@ -205,8 +205,8 @@ module.exports = function (db, module) { module.setRemoveRandom = function (key, callback) { callback = callback || function () {}; - db.collection('objects').findOne({_key:key}, function (err, data) { - if(err || !data) { + db.collection('objects').findOne({ _key: key }, function (err, data) { + if (err || !data) { return callback(err); } @@ -217,4 +217,4 @@ module.exports = function (db, module) { }); }); }; -}; \ No newline at end of file +}; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index b9d511d94d..defaed80fc 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var utils = require('../../../public/src/utils'); @@ -32,13 +32,13 @@ module.exports = function (db, module) { return callback(); } - var fields = {_id: 0, value: 1}; + var fields = { _id: 0, value: 1 }; if (withScores) { fields.score = 1; } if (Array.isArray(key)) { - key = {$in: key}; + key = { $in: key }; } var limit = stop - start + 1; @@ -46,10 +46,10 @@ module.exports = function (db, module) { limit = 0; } - db.collection('objects').find({_key: key}, {fields: fields}) + db.collection('objects').find({ _key: key }, { fields: fields }) .limit(limit) .skip(start) - .sort({score: sort}) + .sort({ score: sort }) .toArray(function (err, data) { if (err || !data) { return callback(err); @@ -89,25 +89,25 @@ module.exports = function (db, module) { count = 0; } - var query = {_key: key}; + var query = { _key: key }; if (min !== '-inf') { - query.score = {$gte: min}; + query.score = { $gte: min }; } if (max !== '+inf') { query.score = query.score || {}; query.score.$lte = max; } - var fields = {_id: 0, value: 1}; + var fields = { _id: 0, value: 1 }; if (withScores) { fields.score = 1; } - db.collection('objects').find(query, {fields: fields}) + db.collection('objects').find(query, { fields: fields }) .limit(count) .skip(start) - .sort({score: sort}) + .sort({ score: sort }) .toArray(function (err, data) { if (err) { return callback(err); @@ -128,9 +128,9 @@ module.exports = function (db, module) { return callback(); } - var query = {_key: key}; + var query = { _key: key }; if (min !== '-inf') { - query.score = {$gte: min}; + query.score = { $gte: min }; } if (max !== '+inf') { query.score = query.score || {}; @@ -138,7 +138,7 @@ module.exports = function (db, module) { } db.collection('objects').count(query, function (err, count) { - callback(err, count ? count : 0); + callback(err, count || 0); }); }; @@ -146,9 +146,9 @@ module.exports = function (db, module) { if (!key) { return callback(null, 0); } - db.collection('objects').count({_key: key}, function (err, count) { + db.collection('objects').count({ _key: key }, function (err, count) { count = parseInt(count, 10); - callback(err, count ? count : 0); + callback(err, count || 0); }); }; @@ -157,9 +157,9 @@ module.exports = function (db, module) { return callback(); } var pipeline = [ - { $match : { _key : { $in: keys } } } , - { $group: { _id: {_key: '$_key'}, count: { $sum: 1 } } }, - { $project: { _id: 1, count: '$count' } } + { $match: { _key: { $in: keys } } }, + { $group: { _id: { _key: '$_key' }, count: { $sum: 1 } } }, + { $project: { _id: 1, count: '$count' } }, ]; db.collection('objects').aggregate(pipeline, function (err, results) { if (err) { @@ -198,7 +198,7 @@ module.exports = function (db, module) { } value = helpers.valueToString(value); method(key, 0, -1, function (err, result) { - if(err) { + if (err) { return callback(err); } @@ -212,8 +212,8 @@ module.exports = function (db, module) { return callback(null, []); } var data = new Array(values.length); - for (var i = 0; i < values.length; ++i) { - data[i] = {key: keys[i], value: values[i]}; + for (var i = 0; i < values.length; i += 1) { + data[i] = { key: keys[i], value: values[i] }; } async.map(data, function (item, next) { @@ -244,7 +244,7 @@ module.exports = function (db, module) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').findOne({_key: key, value: value}, {fields:{_id: 0, score: 1}}, function (err, result) { + db.collection('objects').findOne({ _key: key, value: value }, { fields: { _id: 0, score: 1 } }, function (err, result) { callback(err, result ? result.score : null); }); }; @@ -254,16 +254,16 @@ module.exports = function (db, module) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').find({_key:{$in:keys}, value: value}, {_id:0, _key:1, score: 1}).toArray(function (err, result) { + db.collection('objects').find({ _key: { $in: keys }, value: value }, { _id: 0, _key: 1, score: 1 }).toArray(function (err, result) { if (err) { return callback(err); } - var map = helpers.toMap(result), - returnData = [], - item; + var map = helpers.toMap(result); + var returnData = []; + var item; - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { item = map[keys[i]]; returnData.push(item ? item.score : null); } @@ -277,7 +277,7 @@ module.exports = function (db, module) { return callback(); } values = values.map(helpers.valueToString); - db.collection('objects').find({_key: key, value: {$in: values}}, {_id: 0, value: 1, score: 1}).toArray(function (err, result) { + db.collection('objects').find({ _key: key, value: { $in: values } }, { _id: 0, value: 1, score: 1 }).toArray(function (err, result) { if (err) { return callback(err); } @@ -290,7 +290,7 @@ module.exports = function (db, module) { var returnData = new Array(values.length); var score; - for(var i = 0; i < values.length; ++i) { + for (var i = 0; i < values.length; i += 1) { score = map[values[i]]; returnData[i] = utils.isNumber(score) ? score : null; } @@ -304,7 +304,7 @@ module.exports = function (db, module) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').findOne({_key: key, value: value}, {_id: 0, value: 1}, function (err, result) { + db.collection('objects').findOne({ _key: key, value: value }, { _id: 0, value: 1 }, function (err, result) { callback(err, !!result); }); }; @@ -314,7 +314,7 @@ module.exports = function (db, module) { return callback(); } values = values.map(helpers.valueToString); - db.collection('objects').find({_key: key, value: {$in: values}}, {fields: {_id: 0, value: 1}}).toArray(function (err, results) { + db.collection('objects').find({ _key: key, value: { $in: values } }, { fields: { _id: 0, value: 1 } }).toArray(function (err, results) { if (err) { return callback(err); } @@ -335,7 +335,7 @@ module.exports = function (db, module) { return callback(); } value = helpers.valueToString(value); - db.collection('objects').find({_key: {$in: keys}, value: value}, {fields: {_id: 0, _key: 1, value: 1}}).toArray(function (err, results) { + db.collection('objects').find({ _key: { $in: keys }, value: value }, { fields: { _id: 0, _key: 1, value: 1 } }).toArray(function (err, results) { if (err) { return callback(err); } @@ -355,20 +355,20 @@ module.exports = function (db, module) { if (!Array.isArray(keys) || !keys.length) { return callback(null, []); } - db.collection('objects').find({_key: {$in: keys}}, {_id: 0, _key: 1, value: 1}).toArray(function (err, data) { + db.collection('objects').find({ _key: { $in: keys } }, { _id: 0, _key: 1, value: 1 }).toArray(function (err, data) { if (err) { return callback(err); } var sets = {}; data.forEach(function (set) { - sets[set._key] = sets[set._key] || []; - sets[set._key].push(set.value); + sets[set._key] = sets[set._key] || []; + sets[set._key].push(set.value); }); var returnData = new Array(keys.length); - for(var i = 0; i < keys.length; ++i) { - returnData[i] = sets[keys[i]] || []; + for (var i = 0; i < keys.length; i += 1) { + returnData[i] = sets[keys[i]] || []; } callback(null, returnData); }); @@ -383,7 +383,7 @@ module.exports = function (db, module) { value = helpers.valueToString(value); data.score = parseFloat(increment); - db.collection('objects').findAndModify({_key: key, value: value}, {}, {$inc: data}, {new: true, upsert: true}, function (err, result) { + db.collection('objects').findAndModify({ _key: key, value: value }, {}, { $inc: data }, { new: true, upsert: true }, function (err, result) { // if there is duplicate key error retry the upsert // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 @@ -416,11 +416,11 @@ module.exports = function (db, module) { count = 0; } - var query = {_key: key}; + var query = { _key: key }; buildLexQuery(query, min, max); - db.collection('objects').find(query, {_id: 0, value: 1}) - .sort({value: sort}) + db.collection('objects').find(query, { _id: 0, value: 1 }) + .sort({ value: sort }) .skip(start) .limit(count === -1 ? 0 : count) .toArray(function (err, data) { @@ -431,13 +431,13 @@ module.exports = function (db, module) { return item && item.value; }); callback(err, data); - }); + }); } module.sortedSetRemoveRangeByLex = function (key, min, max, callback) { callback = callback || helpers.noop; - var query = {_key: key}; + var query = { _key: key }; buildLexQuery(query, min, max); db.collection('objects').remove(query, function (err) { @@ -448,11 +448,11 @@ module.exports = function (db, module) { function buildLexQuery(query, min, max) { if (min !== '-') { if (min.match(/^\(/)) { - query.value = {$gt: min.slice(1)}; + query.value = { $gt: min.slice(1) }; } else if (min.match(/^\[/)) { - query.value = {$gte: min.slice(1)}; + query.value = { $gte: min.slice(1) }; } else { - query.value = {$gte: min}; + query.value = { $gte: min }; } } if (max !== '+') { @@ -470,9 +470,9 @@ module.exports = function (db, module) { module.processSortedSet = function (setKey, process, batch, callback) { var done = false; var ids = []; - var cursor = db.collection('objects').find({_key: setKey}) - .sort({score: 1}) - .project({_id: 0, value: 1}) + var cursor = db.collection('objects').find({ _key: setKey }) + .sort({ score: 1 }) + .project({ _id: 0, value: 1 }) .batchSize(batch); async.whilst( @@ -503,5 +503,4 @@ module.exports = function (db, module) { callback ); }; - }; diff --git a/src/database/mongo/sorted/add.js b/src/database/mongo/sorted/add.js index e03452b3df..b90501feee 100644 --- a/src/database/mongo/sorted/add.js +++ b/src/database/mongo/sorted/add.js @@ -1,7 +1,6 @@ 'use strict'; module.exports = function (db, module) { - var helpers = module.helpers.mongo; module.sortedSetAdd = function (key, score, value, callback) { @@ -15,7 +14,7 @@ module.exports = function (db, module) { value = helpers.valueToString(value); - db.collection('objects').update({_key: key, value: value}, {$set: {score: parseFloat(score)}}, {upsert:true, w: 1}, function (err) { + db.collection('objects').update({ _key: key, value: value }, { $set: { score: parseFloat(score) } }, { upsert: true, w: 1 }, function (err) { if (err && err.message.startsWith('E11000 duplicate key error')) { return process.nextTick(module.sortedSetAdd, key, score, value, callback); } @@ -35,8 +34,8 @@ module.exports = function (db, module) { var bulk = db.collection('objects').initializeUnorderedBulkOp(); - for(var i = 0; i < scores.length; ++i) { - bulk.find({_key: key, value: values[i]}).upsert().updateOne({$set: {score: parseFloat(scores[i])}}); + for (var i = 0; i < scores.length; i += 1) { + bulk.find({ _key: key, value: values[i] }).upsert().updateOne({ $set: { score: parseFloat(scores[i]) } }); } bulk.execute(function (err) { @@ -53,13 +52,12 @@ module.exports = function (db, module) { var bulk = db.collection('objects').initializeUnorderedBulkOp(); - for(var i = 0; i < keys.length; ++i) { - bulk.find({_key: keys[i], value: value}).upsert().updateOne({$set: {score: parseFloat(score)}}); + for (var i = 0; i < keys.length; i += 1) { + bulk.find({ _key: keys[i], value: value }).upsert().updateOne({ $set: { score: parseFloat(score) } }); } bulk.execute(function (err) { callback(err); }); }; - -}; \ No newline at end of file +}; diff --git a/src/database/mongo/sorted/intersect.js b/src/database/mongo/sorted/intersect.js index ed8ade3fb3..82f24214ea 100644 --- a/src/database/mongo/sorted/intersect.js +++ b/src/database/mongo/sorted/intersect.js @@ -1,17 +1,16 @@ 'use strict'; module.exports = function (db, module) { - module.sortedSetIntersectCard = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, 0); } var pipeline = [ - { $match: { _key: {$in: keys}} }, - { $group: { _id: {value: '$value'}, count: {$sum: 1}} }, - { $match: { count: keys.length} }, - { $group: { _id: null, count: { $sum: 1 } } } + { $match: { _key: { $in: keys } } }, + { $group: { _id: { value: '$value' }, count: { $sum: 1 } } }, + { $match: { count: keys.length } }, + { $group: { _id: null, count: { $sum: 1 } } }, ]; db.collection('objects').aggregate(pipeline, function (err, data) { @@ -48,7 +47,7 @@ module.exports = function (db, module) { limit = 0; } - var pipeline = [{ $match: { _key: {$in: sets}} }]; + var pipeline = [{ $match: { _key: { $in: sets } } }]; weights.forEach(function (weight, index) { if (weight !== 1) { @@ -56,16 +55,24 @@ module.exports = function (db, module) { $project: { value: 1, score: { - $cond: { if: { $eq: [ "$_key", sets[index] ] }, then: { $multiply: [ '$score', weight ] }, else: '$score' } - } - } + $cond: { + if: { + $eq: ['$_key', sets[index]], + }, + then: { + $multiply: ['$score', weight], + }, + else: '$score', + }, + }, + }, }); } }); - pipeline.push({ $group: { _id: {value: '$value'}, totalScore: aggregate, count: {$sum: 1}} }); - pipeline.push({ $match: { count: sets.length} }); - pipeline.push({ $sort: { totalScore: params.sort} }); + pipeline.push({ $group: { _id: { value: '$value' }, totalScore: aggregate, count: { $sum: 1 } } }); + pipeline.push({ $match: { count: sets.length } }); + pipeline.push({ $sort: { totalScore: params.sort } }); if (start) { pipeline.push({ $skip: start }); @@ -75,7 +82,7 @@ module.exports = function (db, module) { pipeline.push({ $limit: limit }); } - var project = { _id: 0, value: '$_id.value'}; + var project = { _id: 0, value: '$_id.value' }; if (params.withScores) { project.score = '$totalScore'; } @@ -95,5 +102,4 @@ module.exports = function (db, module) { callback(null, data); }); } - -}; \ No newline at end of file +}; diff --git a/src/database/mongo/sorted/remove.js b/src/database/mongo/sorted/remove.js index 71320619c4..e8dea857eb 100644 --- a/src/database/mongo/sorted/remove.js +++ b/src/database/mongo/sorted/remove.js @@ -1,7 +1,6 @@ 'use strict'; module.exports = function (db, module) { - var helpers = module.helpers.mongo; module.sortedSetRemove = function (key, value, callback) { @@ -15,10 +14,10 @@ module.exports = function (db, module) { if (Array.isArray(value)) { value = value.map(helpers.valueToString); - db.collection('objects').remove({_key: key, value: {$in: value}}, done); + db.collection('objects').remove({ _key: key, value: { $in: value } }, done); } else { value = helpers.valueToString(value); - db.collection('objects').remove({_key: key, value: value}, done); + db.collection('objects').remove({ _key: key, value: value }, done); } }; @@ -29,7 +28,7 @@ module.exports = function (db, module) { } value = helpers.valueToString(value); - db.collection('objects').remove({_key: {$in: keys}, value: value}, function (err) { + db.collection('objects').remove({ _key: { $in: keys }, value: value }, function (err) { callback(err); }); }; @@ -39,10 +38,10 @@ module.exports = function (db, module) { if (!Array.isArray(keys) || !keys.length) { return callback(); } - var query = {_key: {$in: keys}}; + var query = { _key: { $in: keys } }; if (min !== '-inf') { - query.score = {$gte: min}; + query.score = { $gte: min }; } if (max !== '+inf') { query.score = query.score || {}; @@ -53,5 +52,4 @@ module.exports = function (db, module) { callback(err); }); }; - -}; \ No newline at end of file +}; diff --git a/src/database/mongo/sorted/union.js b/src/database/mongo/sorted/union.js index 49669bd830..a06df788aa 100644 --- a/src/database/mongo/sorted/union.js +++ b/src/database/mongo/sorted/union.js @@ -1,16 +1,15 @@ 'use strict'; module.exports = function (db, module) { - module.sortedSetUnionCard = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, 0); } var pipeline = [ - { $match: { _key: {$in: keys} } }, - { $group: { _id: {value: '$value' } } }, - { $group: { _id: null, count: { $sum: 1 } } } + { $match: { _key: { $in: keys } } }, + { $group: { _id: { value: '$value' } } }, + { $group: { _id: null, count: { $sum: 1 } } }, ]; var project = { _id: 0, count: '$count' }; @@ -48,9 +47,9 @@ module.exports = function (db, module) { } var pipeline = [ - { $match: { _key: {$in: params.sets}} }, - { $group: { _id: {value: '$value'}, totalScore: aggregate} }, - { $sort: { totalScore: params.sort} } + { $match: { _key: { $in: params.sets } } }, + { $group: { _id: { value: '$value' }, totalScore: aggregate } }, + { $sort: { totalScore: params.sort } }, ]; if (params.start) { @@ -81,5 +80,4 @@ module.exports = function (db, module) { callback(null, data); }); } - -}; \ No newline at end of file +}; diff --git a/src/database/redis.js b/src/database/redis.js index 8519b57bae..27394f7463 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -1,38 +1,36 @@ 'use strict'; (function (module) { - var winston = require('winston'); var nconf = require('nconf'); var semver = require('semver'); var session = require('express-session'); var redis; - var connectRedis; var redisClient; module.questions = [ { name: 'redis:host', description: 'Host IP or address of your Redis instance', - 'default': nconf.get('redis:host') || '127.0.0.1' + default: nconf.get('redis:host') || '127.0.0.1', }, { name: 'redis:port', description: 'Host port of your Redis instance', - 'default': nconf.get('redis:port') || 6379 + default: nconf.get('redis:port') || 6379, }, { name: 'redis:password', description: 'Password of your Redis database', hidden: true, default: nconf.get('redis:password') || '', - before: function (value) { value = value || nconf.get('redis:password') || ''; return value; } + before: function (value) { value = value || nconf.get('redis:password') || ''; return value; }, }, { - name: "redis:database", - description: "Which database to use (0..n)", - 'default': nconf.get('redis:database') || 0 - } + name: 'redis:database', + description: 'Which database to use (0..n)', + default: nconf.get('redis:database') || 0, + }, ]; module.init = function (callback) { @@ -68,7 +66,7 @@ module.sessionStore = new sessionStore({ client: module.client, - ttl: ttl + ttl: ttl, }); if (typeof callback === 'function') { @@ -110,7 +108,7 @@ if (dbIdx) { cxn.select(dbIdx, function (error) { if (error) { - winston.error("NodeBB could not connect to your Redis database. Redis returned the following error: " + error.message); + winston.error('NodeBB could not connect to your Redis database. Redis returned the following error: ' + error.message); process.exit(); } }); @@ -150,7 +148,7 @@ return callback(err); } - var lines = data.toString().split("\r\n").sort(); + var lines = data.toString().split('\r\n').sort(); var redisData = {}; lines.forEach(function (line) { var parts = line.split(':'); @@ -168,5 +166,5 @@ module.helpers = module.helpers || {}; module.helpers.redis = require('./redis/helpers'); -} (exports)); +}(exports)); diff --git a/src/database/redis/hash.js b/src/database/redis/hash.js index f679f7637d..61d83a93f6 100644 --- a/src/database/redis/hash.js +++ b/src/database/redis/hash.js @@ -1,7 +1,6 @@ -"use strict"; +'use strict'; module.exports = function (redisClient, module) { - var helpers = module.helpers.redis; module.setObject = function (key, data, callback) { @@ -52,14 +51,14 @@ module.exports = function (redisClient, module) { } var multi = redisClient.multi(); - for(var x = 0; x < keys.length; ++x) { + for (var x = 0; x < keys.length; x += 1) { multi.hmget.apply(multi, [keys[x]].concat(fields)); } function makeObject(array) { var obj = {}; - for (var i = 0, ii = fields.length; i < ii; ++i) { + for (var i = 0, ii = fields.length; i < ii; i += 1) { obj[fields[i]] = array[i]; } return obj; @@ -97,13 +96,16 @@ module.exports = function (redisClient, module) { module.deleteObjectField = function (key, field, callback) { callback = callback || function () {}; - redisClient.hdel(key, field, function (err, res) { + if (field === null) { + return setImmediate(callback); + } + redisClient.hdel(key, field, function (err) { callback(err); }); }; module.deleteObjectFields = function (key, fields, callback) { - helpers.multiKeyValues(redisClient, 'hdel', key, fields, function (err, results) { + helpers.multiKeyValues(redisClient, 'hdel', key, fields, function (err) { callback(err); }); }; @@ -119,4 +121,4 @@ module.exports = function (redisClient, module) { module.incrObjectFieldBy = function (key, field, value, callback) { redisClient.hincrby(key, field, value, callback); }; -}; \ No newline at end of file +}; diff --git a/src/database/redis/helpers.js b/src/database/redis/helpers.js index a4ca7e116f..7100437177 100644 --- a/src/database/redis/helpers.js +++ b/src/database/redis/helpers.js @@ -1,11 +1,11 @@ -"use strict"; +'use strict'; var helpers = {}; helpers.multiKeys = function (redisClient, command, keys, callback) { callback = callback || function () {}; var multi = redisClient.multi(); - for (var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi[command](keys[i]); } multi.exec(callback); @@ -14,7 +14,7 @@ helpers.multiKeys = function (redisClient, command, keys, callback) { helpers.multiKeysValue = function (redisClient, command, keys, value, callback) { callback = callback || function () {}; var multi = redisClient.multi(); - for (var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi[command](keys[i], value); } multi.exec(callback); @@ -23,17 +23,17 @@ helpers.multiKeysValue = function (redisClient, command, keys, value, callback) helpers.multiKeyValues = function (redisClient, command, key, values, callback) { callback = callback || function () {}; var multi = redisClient.multi(); - for (var i = 0; i < values.length; ++i) { + for (var i = 0; i < values.length; i += 1) { multi[command](key, values[i]); } multi.exec(callback); }; helpers.resultsToBool = function (results) { - for (var i = 0; i < results.length; ++i) { + for (var i = 0; i < results.length; i += 1) { results[i] = results[i] === 1; } return results; }; -module.exports = helpers; \ No newline at end of file +module.exports = helpers; diff --git a/src/database/redis/list.js b/src/database/redis/list.js index c44c23b475..fb445573ff 100644 --- a/src/database/redis/list.js +++ b/src/database/redis/list.js @@ -1,16 +1,16 @@ -"use strict"; +'use strict'; module.exports = function (redisClient, module) { module.listPrepend = function (key, value, callback) { callback = callback || function () {}; - redisClient.lpush(key, value, function (err, res) { + redisClient.lpush(key, value, function (err) { callback(err); }); }; module.listAppend = function (key, value, callback) { callback = callback || function () {}; - redisClient.rpush(key, value, function (err, res) { + redisClient.rpush(key, value, function (err) { callback(err); }); }; @@ -22,14 +22,14 @@ module.exports = function (redisClient, module) { module.listRemoveAll = function (key, value, callback) { callback = callback || function () {}; - redisClient.lrem(key, 0, value, function (err, res) { + redisClient.lrem(key, 0, value, function (err) { callback(err); }); }; module.listTrim = function (key, start, stop, callback) { callback = callback || function () {}; - redisClient.ltrim(key, start, stop, function (err, res) { + redisClient.ltrim(key, start, stop, function (err) { callback(err); }); }; @@ -38,4 +38,4 @@ module.exports = function (redisClient, module) { callback = callback || function () {}; redisClient.lrange(key, start, stop, callback); }; -}; \ No newline at end of file +}; diff --git a/src/database/redis/main.js b/src/database/redis/main.js index 10f26cfd3e..baca6b0ffe 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -1,7 +1,6 @@ -"use strict"; +'use strict'; module.exports = function (redisClient, module) { - module.flushdb = function (callback) { redisClient.send_command('flushdb', [], function (err) { if (typeof callback === 'function') { @@ -22,7 +21,7 @@ module.exports = function (redisClient, module) { module.delete = function (key, callback) { callback = callback || function () {}; - redisClient.del(key, function (err, res) { + redisClient.del(key, function (err) { callback(err); }); }; @@ -30,10 +29,10 @@ module.exports = function (redisClient, module) { module.deleteAll = function (keys, callback) { callback = callback || function () {}; var multi = redisClient.multi(); - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi.del(keys[i]); } - multi.exec(function (err, res) { + multi.exec(function (err) { callback(err); }); }; @@ -56,7 +55,7 @@ module.exports = function (redisClient, module) { module.rename = function (oldKey, newKey, callback) { callback = callback || function () {}; - redisClient.rename(oldKey, newKey, function (err, res) { + redisClient.rename(oldKey, newKey, function (err) { callback(err && err.message !== 'ERR no such key' ? err : null); }); }; diff --git a/src/database/redis/sets.js b/src/database/redis/sets.js index 5b2b803868..a5716438e4 100644 --- a/src/database/redis/sets.js +++ b/src/database/redis/sets.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; module.exports = function (redisClient, module) { var helpers = module.helpers.redis; @@ -11,28 +11,28 @@ module.exports = function (redisClient, module) { if (!value.length) { return callback(); } - redisClient.sadd(key, value, function (err, res) { + redisClient.sadd(key, value, function (err) { callback(err); }); }; module.setsAdd = function (keys, value, callback) { callback = callback || function () {}; - helpers.multiKeysValue(redisClient, 'sadd', keys, value, function (err, res) { + helpers.multiKeysValue(redisClient, 'sadd', keys, value, function (err) { callback(err); }); }; module.setRemove = function (key, value, callback) { callback = callback || function () {}; - redisClient.srem(key, value, function (err, res) { + redisClient.srem(key, value, function (err) { callback(err); }); }; module.setsRemove = function (keys, value, callback) { callback = callback || function () {}; - helpers.multiKeysValue(redisClient, 'srem', keys, value, function (err, res) { + helpers.multiKeysValue(redisClient, 'srem', keys, value, function (err) { callback(err); }); }; @@ -77,4 +77,4 @@ module.exports = function (redisClient, module) { }; return module; -}; \ No newline at end of file +}; diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 1e8c629fa9..a2c18296db 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -1,7 +1,6 @@ -"use strict"; +'use strict'; module.exports = function (redisClient, module) { - var utils = require('../../../public/src/utils'); var helpers = module.helpers.redis; @@ -29,7 +28,7 @@ module.exports = function (redisClient, module) { function sortedSetRange(method, key, start, stop, withScores, callback) { if (Array.isArray(key)) { - return module.sortedSetUnion({method: method, sets: key, start: start, stop: stop, withScores: withScores}, callback); + return module.sortedSetUnion({ method: method, sets: key, start: start, stop: stop, withScores: withScores }, callback); } var params = [key, start, stop]; @@ -45,8 +44,8 @@ module.exports = function (redisClient, module) { return callback(null, data); } var objects = []; - for(var i = 0; i < data.length; i += 2) { - objects.push({value: data[i], score: parseFloat(data[i + 1])}); + for (var i = 0; i < data.length; i += 2) { + objects.push({ value: data[i], score: parseFloat(data[i + 1]) }); } callback(null, objects); }); @@ -74,8 +73,8 @@ module.exports = function (redisClient, module) { return callback(err); } var objects = []; - for(var i = 0; i < data.length; i += 2) { - objects.push({value: data[i], score: parseFloat(data[i + 1])}); + for (var i = 0; i < data.length; i += 2) { + objects.push({ value: data[i], score: parseFloat(data[i + 1]) }); } callback(null, objects); }); @@ -94,7 +93,7 @@ module.exports = function (redisClient, module) { return callback(null, []); } var multi = redisClient.multi(); - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi.zcard(keys[i]); } multi.exec(callback); @@ -106,7 +105,7 @@ module.exports = function (redisClient, module) { module.sortedSetsRanks = function (keys, values, callback) { var multi = redisClient.multi(); - for(var i = 0; i < values.length; ++i) { + for (var i = 0; i < values.length; i += 1) { multi.zrank(keys[i], values[i]); } multi.exec(callback); @@ -114,7 +113,7 @@ module.exports = function (redisClient, module) { module.sortedSetRanks = function (key, values, callback) { var multi = redisClient.multi(); - for(var i = 0; i < values.length; ++i) { + for (var i = 0; i < values.length; i += 1) { multi.zrank(key, values[i]); } multi.exec(callback); @@ -164,7 +163,7 @@ module.exports = function (redisClient, module) { module.getSortedSetsMembers = function (keys, callback) { var multi = redisClient.multi(); - for (var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi.zrange(keys[i], 0, -1); } multi.exec(callback); @@ -198,7 +197,8 @@ module.exports = function (redisClient, module) { function sortedSetLex(method, reverse, key, min, max, start, count, callback) { callback = callback || start; - var minmin, maxmax; + var minmin; + var maxmax; if (reverse) { minmin = '+'; maxmax = '-'; @@ -207,10 +207,10 @@ module.exports = function (redisClient, module) { maxmax = '+'; } - if (min !== minmin && !min.match(/^[\[\(]/)) { + if (min !== minmin && !min.match(/^[[(]/)) { min = '[' + min; } - if (max !== maxmax && !max.match(/^[\[\(]/)) { + if (max !== maxmax && !max.match(/^[[(]/)) { max = '[' + max; } diff --git a/src/database/redis/sorted/add.js b/src/database/redis/sorted/add.js index b2eb710221..e60d079eac 100644 --- a/src/database/redis/sorted/add.js +++ b/src/database/redis/sorted/add.js @@ -1,7 +1,6 @@ 'use strict'; module.exports = function (redisClient, module) { - module.sortedSetAdd = function (key, score, value, callback) { callback = callback || function () {}; if (Array.isArray(score) && Array.isArray(value)) { @@ -23,7 +22,7 @@ module.exports = function (redisClient, module) { var args = [key]; - for(var i = 0; i < scores.length; ++i) { + for (var i = 0; i < scores.length; i += 1) { args.push(scores[i], values[i]); } @@ -36,7 +35,7 @@ module.exports = function (redisClient, module) { callback = callback || function () {}; var multi = redisClient.multi(); - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi.zadd(keys[i], score, value); } @@ -44,6 +43,4 @@ module.exports = function (redisClient, module) { callback(err); }); }; - - -}; \ No newline at end of file +}; diff --git a/src/database/redis/sorted/intersect.js b/src/database/redis/sorted/intersect.js index a4e3c131b4..86240a7a34 100644 --- a/src/database/redis/sorted/intersect.js +++ b/src/database/redis/sorted/intersect.js @@ -2,7 +2,6 @@ 'use strict'; module.exports = function (redisClient, module) { - module.sortedSetIntersectCard = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, 0); @@ -70,10 +69,10 @@ module.exports = function (redisClient, module) { } results = results[1] || []; var objects = []; - for(var i = 0; i < results.length; i += 2) { - objects.push({value: results[i], score: parseFloat(results[i + 1])}); + for (var i = 0; i < results.length; i += 2) { + objects.push({ value: results[i], score: parseFloat(results[i + 1]) }); } callback(null, objects); }); } -}; \ No newline at end of file +}; diff --git a/src/database/redis/sorted/remove.js b/src/database/redis/sorted/remove.js index aa1d42a3ce..eacb6ca861 100644 --- a/src/database/redis/sorted/remove.js +++ b/src/database/redis/sorted/remove.js @@ -2,7 +2,6 @@ 'use strict'; module.exports = function (redisClient, module) { - var helpers = module.helpers.redis; module.sortedSetRemove = function (key, value, callback) { @@ -28,11 +27,11 @@ module.exports = function (redisClient, module) { module.sortedSetsRemoveRangeByScore = function (keys, min, max, callback) { callback = callback || function () {}; var multi = redisClient.multi(); - for(var i = 0; i < keys.length; ++i) { + for (var i = 0; i < keys.length; i += 1) { multi.zremrangebyscore(keys[i], min, max); } multi.exec(function (err) { callback(err); }); }; -}; \ No newline at end of file +}; diff --git a/src/database/redis/sorted/union.js b/src/database/redis/sorted/union.js index 677b086259..ea17ee2d4e 100644 --- a/src/database/redis/sorted/union.js +++ b/src/database/redis/sorted/union.js @@ -2,7 +2,6 @@ 'use strict'; module.exports = function (redisClient, module) { - module.sortedSetUnionCard = function (keys, callback) { var tempSetName = 'temp_' + Date.now(); @@ -30,7 +29,6 @@ module.exports = function (redisClient, module) { }; module.sortedSetUnion = function (params, callback) { - var tempSetName = 'temp_' + Date.now(); var rangeParams = [tempSetName, params.start, params.stop]; @@ -51,10 +49,10 @@ module.exports = function (redisClient, module) { } results = results[1] || []; var objects = []; - for(var i = 0; i < results.length; i += 2) { - objects.push({value: results[i], score: parseFloat(results[i + 1])}); + for (var i = 0; i < results.length; i += 2) { + objects.push({ value: results[i], score: parseFloat(results[i + 1]) }); } callback(null, objects); }); }; -}; \ No newline at end of file +}; diff --git a/src/emailer.js b/src/emailer.js index 4ccd35ed99..95ffbdceba 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -17,7 +17,7 @@ var translator = require('../public/src/modules/translator'); var transports = { sendmail: nodemailer.createTransport(sendmailTransport()), - gmail: undefined + gmail: undefined, }; var app; @@ -29,15 +29,16 @@ var fallbackTransport; // Enable Gmail transport if enabled in ACP if (parseInt(meta.config['email:GmailTransport:enabled'], 10) === 1) { - fallbackTransport = transports.gmail = nodemailer.createTransport(smtpTransport({ + transports.gmail = nodemailer.createTransport(smtpTransport({ host: 'smtp.gmail.com', port: 465, secure: true, auth: { user: meta.config['email:GmailTransport:user'], - pass: meta.config['email:GmailTransport:pass'] - } + pass: meta.config['email:GmailTransport:pass'], + }, })); + fallbackTransport = transports.gmail; } else { fallbackTransport = transports.sendmail; } @@ -56,7 +57,7 @@ var fallbackTransport; function (next) { async.parallel({ email: async.apply(User.getUserField, uid, 'email'), - settings: async.apply(User.getSettings, uid) + settings: async.apply(User.getSettings, uid), }, next); }, function (results, next) { @@ -66,7 +67,7 @@ var fallbackTransport; } params.uid = uid; Emailer.sendToEmail(template, results.email, results.settings.userLang, params, next); - } + }, ], callback); }; @@ -85,7 +86,7 @@ var fallbackTransport; translator.translate(params.subject, lang, function (translated) { next(null, translated); }); - } + }, }, next); }, function (results, next) { @@ -97,12 +98,12 @@ var fallbackTransport; subject: results.subject, html: results.html, plaintext: htmlToText.fromString(results.html, { - ignoreImage: true + ignoreImage: true, }), template: template, uid: params.uid, pid: params.pid, - fromUid: params.fromUid + fromUid: params.fromUid, }; Plugins.fireHook('filter:email.modify', data, next); }, @@ -112,7 +113,7 @@ var fallbackTransport; } else { Emailer.sendViaFallback(data, next); } - } + }, ], function (err) { if (err && err.code === 'ENOENT') { callback(new Error('[[error:sendmail-not-found]]')); @@ -163,6 +164,5 @@ var fallbackTransport; return parsed.hostname; } - }(module.exports)); diff --git a/src/emitter.js b/src/emitter.js index ca262257b7..140c35f639 100644 --- a/src/emitter.js +++ b/src/emitter.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var eventEmitter = new (require('events')).EventEmitter(); @@ -32,4 +32,4 @@ eventEmitter.any = function (events, callback) { }); }; -module.exports = eventEmitter; \ No newline at end of file +module.exports = eventEmitter; diff --git a/src/events.js b/src/events.js index 3f061566b9..ab2864bc23 100644 --- a/src/events.js +++ b/src/events.js @@ -4,7 +4,7 @@ var async = require('async'); var validator = require('validator'); -var db = require('./database'); +var db = require('./database'); var batch = require('./batch'); var user = require('./user'); var utils = require('../public/src/utils'); @@ -27,10 +27,10 @@ var utils = require('../public/src/utils'); }, function (next) { db.setObject('event:' + eid, data, next); - } + }, ], next); - } - ], function (err, result) { + }, + ], function (err) { callback(err); }); }; @@ -61,12 +61,16 @@ var utils = require('../public/src/utils'); } }); var e = utils.merge(event); - e.eid = e.uid = e.type = e.ip = e.user = undefined; + e.eid = undefined; + e.uid = undefined; + e.type = undefined; + e.ip = undefined; + e.user = undefined; event.jsonString = JSON.stringify(e, null, 4); event.timestampISO = new Date(parseInt(event.timestamp, 10)).toUTCString(); }); next(null, eventsData); - } + }, ], callback); }; @@ -87,7 +91,7 @@ var utils = require('../public/src/utils'); }, userData: function (next) { user.getUsersFields(uids, ['username', 'userslug', 'picture'], next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -121,7 +125,7 @@ var utils = require('../public/src/utils'); }, function (next) { db.sortedSetRemove('events:time', eids, next); - } + }, ], callback); }; @@ -130,8 +134,6 @@ var utils = require('../public/src/utils'); batch.processSortedSet('events:time', function (eids, next) { events.deleteEvents(eids, next); - }, {alwaysStartAt: 0}, callback); + }, { alwaysStartAt: 0 }, callback); }; - - }(module.exports)); diff --git a/src/file.js b/src/file.js index afdcef82bf..78d428c41e 100644 --- a/src/file.js +++ b/src/file.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var fs = require('fs'); var nconf = require('nconf'); @@ -35,7 +35,7 @@ file.saveFileToLocal = function (filename, folder, tempPath, callback) { is.on('end', function () { callback(null, { url: '/assets/uploads/' + folder + '/' + filename, - path: uploadPath + path: uploadPath, }); }); @@ -49,7 +49,7 @@ file.base64ToLocal = function (imageData, uploadPath, callback) { uploadPath = path.join(nconf.get('upload_path'), uploadPath); fs.writeFile(uploadPath, buffer, { - encoding: 'base64' + encoding: 'base64', }, function (err) { callback(err, uploadPath); }); @@ -101,8 +101,7 @@ file.existsSync = function (path) { var exists = false; try { exists = fs.statSync(path); - } - catch (err) { + } catch (err) { exists = false; } @@ -112,8 +111,7 @@ file.existsSync = function (path) { file.link = function link(filePath, destPath, cb) { if (process.platform === 'win32') { fs.link(filePath, destPath, cb); - } - else { + } else { fs.symlink(filePath, destPath, 'file', cb); } }; diff --git a/src/groups.js b/src/groups.js index 51c1d97dc8..fd8c4a958f 100644 --- a/src/groups.js +++ b/src/groups.js @@ -6,217 +6,197 @@ var validator = require('validator'); var user = require('./user'); var db = require('./database'); var plugins = require('./plugins'); -var posts = require('./posts'); -var privileges = require('./privileges'); var utils = require('../public/src/utils'); -(function (Groups) { +var Groups = module.exports; - require('./groups/create')(Groups); - require('./groups/delete')(Groups); - require('./groups/update')(Groups); - require('./groups/membership')(Groups); - require('./groups/ownership')(Groups); - require('./groups/search')(Groups); - require('./groups/cover')(Groups); +require('./groups/data')(Groups); +require('./groups/create')(Groups); +require('./groups/delete')(Groups); +require('./groups/update')(Groups); +require('./groups/membership')(Groups); +require('./groups/ownership')(Groups); +require('./groups/search')(Groups); +require('./groups/cover')(Groups); +require('./groups/posts')(Groups); +require('./groups/user')(Groups); - var ephemeralGroups = ['guests'], - internals = { - getEphemeralGroup: function (groupName) { - return { - name: groupName, - slug: utils.slugify(groupName), - description: '', - deleted: '0', - hidden: '0', - system: '1' - }; - }, - removeEphemeralGroups: function (groups) { - var x = groups.length; - while(x--) { - if (ephemeralGroups.indexOf(groups[x]) !== -1) { - groups.splice(x, 1); - } - } +Groups.ephemeralGroups = ['guests']; - return groups; - } - }; - - Groups.internals = internals; - - var isPrivilegeGroupRegex = /^cid:\d+:privileges:[\w:]+$/; - Groups.isPrivilegeGroup = function (groupName) { - return isPrivilegeGroupRegex.test(groupName); +Groups.getEphemeralGroup = function (groupName) { + return { + name: groupName, + slug: utils.slugify(groupName), + description: '', + deleted: '0', + hidden: '0', + system: '1', }; +}; - Groups.getEphemeralGroups = function () { - return ephemeralGroups; - }; - - Groups.getGroupsFromSet = function (set, uid, start, stop, callback) { - async.waterfall([ - function (next) { - if (set === 'groups:visible:name') { - db.getSortedSetRangeByLex(set, '-', '+', start, stop - start + 1, next); - } else { - db.getSortedSetRevRange(set, start, stop, next); - } - }, - function (groupNames, next) { - if (set === 'groups:visible:name') { - groupNames = groupNames.map(function (name) { - return name.split(':')[1]; - }); - } - - Groups.getGroupsAndMembers(groupNames, next); - } - ], callback); - }; - - Groups.getGroups = function (set, start, stop, callback) { - db.getSortedSetRevRange(set, start, stop, callback); - }; - - Groups.getGroupsAndMembers = function (groupNames, callback) { - async.parallel({ - groups: function (next) { - Groups.getGroupsData(groupNames, next); - }, - members: function (next) { - Groups.getMemberUsers(groupNames, 0, 3, next); - } - }, function (err, data) { - if (err) { - return callback(err); - } - - data.groups.forEach(function (group, index) { - if (!group) { - return; - } - - group.members = data.members[index] || []; - group.truncated = group.memberCount > data.members.length; - }); - - callback(null, data.groups); - }); - }; - - Groups.get = function (groupName, options, callback) { - if (!groupName) { - return callback(new Error('[[error:invalid-group]]')); +Groups.removeEphemeralGroups = function (groups) { + for (var x = groups.length; x >= 0; x -= 1) { + if (Groups.ephemeralGroups.indexOf(groups[x]) !== -1) { + groups.splice(x, 1); } + } - var stop = -1; + return groups; +}; - async.parallel({ - base: function (next) { - db.getObject('group:' + groupName, next); - }, - members: function (next) { - if (options.truncateUserList) { - stop = (parseInt(options.userListCount, 10) || 4) - 1; +var isPrivilegeGroupRegex = /^cid:\d+:privileges:[\w:]+$/; +Groups.isPrivilegeGroup = function (groupName) { + return isPrivilegeGroupRegex.test(groupName); +}; + +Groups.getGroupsFromSet = function (set, uid, start, stop, callback) { + async.waterfall([ + function (next) { + if (set === 'groups:visible:name') { + db.getSortedSetRangeByLex(set, '-', '+', start, stop - start + 1, next); + } else { + db.getSortedSetRevRange(set, start, stop, next); + } + }, + function (groupNames, next) { + if (set === 'groups:visible:name') { + groupNames = groupNames.map(function (name) { + return name.split(':')[1]; + }); + } + + Groups.getGroupsAndMembers(groupNames, next); + }, + ], callback); +}; + +Groups.getGroups = function (set, start, stop, callback) { + db.getSortedSetRevRange(set, start, stop, callback); +}; + +Groups.getGroupsAndMembers = function (groupNames, callback) { + async.waterfall([ + function (next) { + async.parallel({ + groups: function (next) { + Groups.getGroupsData(groupNames, next); + }, + members: function (next) { + Groups.getMemberUsers(groupNames, 0, 3, next); + }, + }, next); + }, + function (data, next) { + data.groups.forEach(function (group, index) { + if (group) { + group.members = data.members[index] || []; + group.truncated = group.memberCount > data.members.length; } + }); + next(null, data.groups); + }, + ], callback); +}; - Groups.getOwnersAndMembers(groupName, options.uid, 0, stop, next); - }, - pending: function (next) { - async.waterfall([ - function (next) { - db.getSetMembers('group:' + groupName + ':pending', next); - }, - function (uids, next) { - user.getUsersData(uids, next); +Groups.get = function (groupName, options, callback) { + if (!groupName) { + return callback(new Error('[[error:invalid-group]]')); + } + + var stop = -1; + + var results; + async.waterfall([ + function (next) { + async.parallel({ + base: function (next) { + db.getObject('group:' + groupName, next); + }, + members: function (next) { + if (options.truncateUserList) { + stop = (parseInt(options.userListCount, 10) || 4) - 1; } - ], next); - }, - invited: function (next) { - async.waterfall([ - function (next) { - db.getSetMembers('group:' + groupName + ':invited', next); - }, - function (uids, next) { - user.getUsersData(uids, next); - } - ], next); - }, - isMember: async.apply(Groups.isMember, options.uid, groupName), - isPending: async.apply(Groups.isPending, options.uid, groupName), - isInvited: async.apply(Groups.isInvited, options.uid, groupName), - isOwner: async.apply(Groups.ownership.isOwner, options.uid, groupName) - }, function (err, results) { - if (err) { - return callback(err); - } else if (!results.base) { + + Groups.getOwnersAndMembers(groupName, options.uid, 0, stop, next); + }, + pending: function (next) { + Groups.getUsersFromSet('group:' + groupName + ':pending', next); + }, + invited: function (next) { + Groups.getUsersFromSet('group:' + groupName + ':invited', next); + }, + isMember: async.apply(Groups.isMember, options.uid, groupName), + isPending: async.apply(Groups.isPending, options.uid, groupName), + isInvited: async.apply(Groups.isInvited, options.uid, groupName), + isOwner: async.apply(Groups.ownership.isOwner, options.uid, groupName), + }, next); + }, + function (_results, next) { + results = _results; + if (!results.base) { return callback(new Error('[[error:no-group]]')); } + plugins.fireHook('filter:parse.raw', results.base.description, next); + }, + function (descriptionParsed, next) { + var groupData = results.base; + Groups.escapeGroupData(groupData); - results.base['cover:url'] = results.base['cover:url'] || require('./coverPhoto').getDefaultGroupCover(groupName); - results.base['cover:position'] = validator.escape(String(results.base['cover:position'] || '50% 50%')); - results.base.labelColor = validator.escape(String(results.base.labelColor || '#000000')); - results.base.icon = validator.escape(String(results.base.icon || '')); + groupData.descriptionParsed = descriptionParsed; + groupData.userTitleEnabled = groupData.userTitleEnabled ? !!parseInt(groupData.userTitleEnabled, 10) : true; + groupData.createtimeISO = utils.toISOString(groupData.createtime); + groupData.members = results.members; + groupData.membersNextStart = stop + 1; + groupData.pending = results.pending.filter(Boolean); + groupData.invited = results.invited.filter(Boolean); + groupData.deleted = !!parseInt(groupData.deleted, 10); + groupData.hidden = !!parseInt(groupData.hidden, 10); + groupData.system = !!parseInt(groupData.system, 10); + groupData.memberCount = parseInt(groupData.memberCount, 10); + groupData.private = (groupData.private === null || groupData.private === undefined) ? true : !!parseInt(groupData.private, 10); + groupData.disableJoinRequests = parseInt(groupData.disableJoinRequests, 10) === 1; + groupData.isMember = results.isMember; + groupData.isPending = results.isPending; + groupData.isInvited = results.isInvited; + groupData.isOwner = results.isOwner; + groupData['cover:url'] = groupData['cover:url'] || require('./coverPhoto').getDefaultGroupCover(groupName); + groupData['cover:position'] = validator.escape(String(groupData['cover:position'] || '50% 50%')); + groupData.labelColor = validator.escape(String(groupData.labelColor || '#000000')); + groupData.icon = validator.escape(String(groupData.icon || '')); - plugins.fireHook('filter:parse.raw', results.base.description, function (err, descriptionParsed) { - if (err) { - return callback(err); - } + plugins.fireHook('filter:group.get', { group: groupData }, next); + }, + function (results, next) { + next(null, results.group); + }, + ], callback); +}; - Groups.escapeGroupData(results.base); - - results.base.descriptionParsed = descriptionParsed; - results.base.userTitleEnabled = results.base.userTitleEnabled ? !!parseInt(results.base.userTitleEnabled, 10) : true; - results.base.createtimeISO = utils.toISOString(results.base.createtime); - results.base.members = results.members; - results.base.membersNextStart = stop + 1; - results.base.pending = results.pending.filter(Boolean); - results.base.invited = results.invited.filter(Boolean); - results.base.deleted = !!parseInt(results.base.deleted, 10); - results.base.hidden = !!parseInt(results.base.hidden, 10); - results.base.system = !!parseInt(results.base.system, 10); - results.base.memberCount = parseInt(results.base.memberCount, 10); - results.base.private = (results.base.private === null || results.base.private === undefined) ? true : !!parseInt(results.base.private, 10); - results.base.disableJoinRequests = parseInt(results.base.disableJoinRequests, 10) === 1; - results.base.isMember = results.isMember; - results.base.isPending = results.isPending; - results.base.isInvited = results.isInvited; - results.base.isOwner = results.isOwner; - - plugins.fireHook('filter:group.get', {group: results.base}, function (err, data) { - callback(err, data ? data.group : null); - }); - }); - }); - }; - - Groups.getOwners = function (groupName, callback) { - db.getSetMembers('group:' + groupName + ':owners', callback); - }; - - Groups.getOwnersAndMembers = function (groupName, uid, start, stop, callback) { - async.parallel({ - owners: function (next) { - async.waterfall([ - function (next) { - db.getSetMembers('group:' + groupName + ':owners', next); - }, - function (uids, next) { - user.getUsers(uids, uid, next); - } - ], next); - }, - members: function (next) { - user.getUsersFromSet('group:' + groupName + ':members', uid, start, stop, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } +Groups.getOwners = function (groupName, callback) { + db.getSetMembers('group:' + groupName + ':owners', callback); +}; +Groups.getOwnersAndMembers = function (groupName, uid, start, stop, callback) { + async.waterfall([ + function (next) { + async.parallel({ + owners: function (next) { + async.waterfall([ + function (next) { + db.getSetMembers('group:' + groupName + ':owners', next); + }, + function (uids, next) { + user.getUsers(uids, uid, next); + }, + ], next); + }, + members: function (next) { + user.getUsersFromSet('group:' + groupName + ':members', uid, start, stop, next); + }, + }, next); + }, + function (results, next) { var ownerUids = []; results.owners.forEach(function (user) { if (user) { @@ -230,230 +210,94 @@ var utils = require('../public/src/utils'); }); results.members = results.owners.concat(results.members); - callback(null, results.members); - }); - }; + next(null, results.members); + }, + ], callback); +}; - Groups.escapeGroupData = function (group) { - if (group) { - group.nameEncoded = encodeURIComponent(group.name); - group.displayName = validator.escape(String(group.name)); - group.description = validator.escape(String(group.description || '')); - group.userTitle = validator.escape(String(group.userTitle || '')) || group.displayName; - } - }; +Groups.escapeGroupData = function (group) { + if (group) { + group.nameEncoded = encodeURIComponent(group.name); + group.displayName = validator.escape(String(group.name)); + group.description = validator.escape(String(group.description || '')); + group.userTitle = validator.escape(String(group.userTitle || '')) || group.displayName; + } +}; - Groups.getByGroupslug = function (slug, options, callback) { - db.getObjectField('groupslug:groupname', slug, function (err, groupName) { - if (err) { - return callback(err); - } else if (!groupName) { - return callback(new Error('[[error:no-group]]')); +Groups.getByGroupslug = function (slug, options, callback) { + async.waterfall([ + function (next) { + db.getObjectField('groupslug:groupname', slug, next); + }, + function (groupName, next) { + if (!groupName) { + return next(new Error('[[error:no-group]]')); } + Groups.get(groupName, options, next); + }, + ], callback); +}; - Groups.get(groupName, options, callback); +Groups.getGroupNameByGroupSlug = function (slug, callback) { + db.getObjectField('groupslug:groupname', slug, callback); +}; + +Groups.isPrivate = function (groupName, callback) { + isFieldOn(groupName, 'private', callback); +}; + +Groups.isHidden = function (groupName, callback) { + isFieldOn(groupName, 'hidden', callback); +}; + +function isFieldOn(groupName, field, callback) { + async.waterfall([ + function (next) { + db.getObjectField('group:' + groupName, field, next); + }, + function (value, next) { + next(null, parseInt(value, 10) === 1); + }, + ], callback); +} + +Groups.exists = function (name, callback) { + if (Array.isArray(name)) { + var slugs = name.map(function (groupName) { + return utils.slugify(groupName); }); - }; - - Groups.getGroupNameByGroupSlug = function (slug, callback) { - db.getObjectField('groupslug:groupname', slug, callback); - }; - - Groups.getGroupFields = function (groupName, fields, callback) { - Groups.getMultipleGroupFields([groupName], fields, function (err, groups) { - callback(err, groups ? groups[0] : null); - }); - }; - - Groups.getMultipleGroupFields = function (groups, fields, callback) { - db.getObjectsFields(groups.map(function (group) { - return 'group:' + group; - }), fields, callback); - }; - - Groups.setGroupField = function (groupName, field, value, callback) { - db.setObjectField('group:' + groupName, field, value, function (err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:group.set', {field: field, value: value, type: 'set'}); - callback(); - }); - }; - - Groups.isPrivate = function (groupName, callback) { - db.getObjectField('group:' + groupName, 'private', function (err, isPrivate) { - if (err) { - return callback(err); - } - - callback(null, (parseInt(isPrivate, 10) === 0) ? false : true); - }); - }; - - Groups.isHidden = function (groupName, callback) { - db.getObjectField('group:' + groupName, 'hidden', function (err, isHidden) { - if (err) { - return callback(err); - } - - callback(null, parseInt(isHidden, 10) === 1); - }); - }; - - Groups.exists = function (name, callback) { - if (Array.isArray(name)) { - var slugs = name.map(function (groupName) { - return utils.slugify(groupName); - }); - async.parallel([ - function (next) { - next(null, slugs.map(function (slug) { - return ephemeralGroups.indexOf(slug) !== -1; - })); - }, - async.apply(db.isSortedSetMembers, 'groups:createtime', name) - ], function (err, results) { - if (err) { - return callback(err); - } - callback(null, name.map(function (n, index) { - return results[0][index] || results[1][index]; + async.parallel([ + function (next) { + next(null, slugs.map(function (slug) { + return Groups.ephemeralGroups.indexOf(slug) !== -1; })); - }); - } else { - var slug = utils.slugify(name); - async.parallel([ - function (next) { - next(null, ephemeralGroups.indexOf(slug) !== -1); - }, - async.apply(db.isSortedSetMember, 'groups:createtime', name) - ], function (err, results) { - callback(err, !err ? (results[0] || results[1]) : null); - }); - } - }; - - Groups.existsBySlug = function (slug, callback) { - if (Array.isArray(slug)) { - db.isObjectFields('groupslug:groupname', slug, callback); - } else { - db.isObjectField('groupslug:groupname', slug, callback); - } - }; - - Groups.getLatestMemberPosts = function (groupName, max, uid, callback) { - async.waterfall([ - function (next) { - Groups.getMembers(groupName, 0, -1, next); }, - function (uids, next) { - if (!Array.isArray(uids) || !uids.length) { - return callback(null, []); - } - var keys = uids.map(function (uid) { - return 'uid:' + uid + ':posts'; - }); - db.getSortedSetRevRange(keys, 0, max - 1, next); - }, - function (pids, next) { - privileges.posts.filter('read', pids, uid, next); - }, - function (pids, next) { - posts.getPostSummaryByPids(pids, uid, {stripTags: false}, next); - } - ], callback); - }; - - Groups.getGroupData = function (groupName, callback) { - Groups.getGroupsData([groupName], function (err, groupsData) { - callback(err, Array.isArray(groupsData) && groupsData[0] ? groupsData[0] : null); - }); - }; - - Groups.getGroupsData = function (groupNames, callback) { - if (!Array.isArray(groupNames) || !groupNames.length) { - return callback(null, []); - } - - var keys = groupNames.map(function (groupName) { - return 'group:' + groupName; - }); - - var ephemeralIdx = groupNames.reduce(function (memo, cur, idx) { - if (ephemeralGroups.indexOf(cur) !== -1) { - memo.push(idx); - } - return memo; - }, []); - - db.getObjects(keys, function (err, groupData) { + async.apply(db.isSortedSetMembers, 'groups:createtime', name), + ], function (err, results) { if (err) { return callback(err); } - - if (ephemeralIdx.length) { - ephemeralIdx.forEach(function (idx) { - groupData[idx] = internals.getEphemeralGroup(groupNames[idx]); - }); - } - - groupData.forEach(function (group) { - if (group) { - Groups.escapeGroupData(group); - group.userTitleEnabled = group.userTitleEnabled ? parseInt(group.userTitleEnabled, 10) === 1 : true; - group.labelColor = validator.escape(String(group.labelColor || '#000000')); - group.icon = validator.escape(String(group.icon || '')); - group.createtimeISO = utils.toISOString(group.createtime); - group.hidden = parseInt(group.hidden, 10) === 1; - group.system = parseInt(group.system, 10) === 1; - group.private = (group.private === null || group.private === undefined) ? true : !!parseInt(group.private, 10); - group.disableJoinRequests = parseInt(group.disableJoinRequests) === 1; - - group['cover:url'] = group['cover:url'] || require('./coverPhoto').getDefaultGroupCover(group.name); - group['cover:thumb:url'] = group['cover:thumb:url'] || group['cover:url']; - group['cover:position'] = validator.escape(String(group['cover:position'] || '50% 50%')); - } - }); - - plugins.fireHook('filter:groups.get', {groups: groupData}, function (err, data) { - callback(err, data ? data.groups : null); - }); + callback(null, name.map(function (n, index) { + return results[0][index] || results[1][index]; + })); }); - }; - - Groups.getUserGroups = function (uids, callback) { - Groups.getUserGroupsFromSet('groups:visible:createtime', uids, callback); - }; - - Groups.getUserGroupsFromSet = function (set, uids, callback) { - async.waterfall([ + } else { + var slug = utils.slugify(name); + async.parallel([ function (next) { - db.getSortedSetRevRange(set, 0, -1, next); + next(null, Groups.ephemeralGroups.indexOf(slug) !== -1); }, - function (groupNames, next) { - var groupSets = groupNames.map(function (name) { - return 'group:' + name + ':members'; - }); + async.apply(db.isSortedSetMember, 'groups:createtime', name), + ], function (err, results) { + callback(err, !err ? (results[0] || results[1]) : null); + }); + } +}; - async.map(uids, function (uid, next) { - db.isMemberOfSortedSets(groupSets, uid, function (err, isMembers) { - if (err) { - return next(err); - } - - var memberOf = []; - isMembers.forEach(function (isMember, index) { - if (isMember) { - memberOf.push(groupNames[index]); - } - }); - - Groups.getGroupsData(memberOf, next); - }); - }, next); - } - ], callback); - }; - -}(module.exports)); +Groups.existsBySlug = function (slug, callback) { + if (Array.isArray(slug)) { + db.isObjectFields('groupslug:groupname', slug, callback); + } else { + db.isObjectField('groupslug:groupname', slug, callback); + } +}; diff --git a/src/groups/cover.js b/src/groups/cover.js index 8f18c60ad7..a7d7550fa0 100644 --- a/src/groups/cover.js +++ b/src/groups/cover.js @@ -1,10 +1,7 @@ 'use strict'; var async = require('async'); -var nconf = require('nconf'); -var path = require('path'); var fs = require('fs'); -var crypto = require('crypto'); var Jimp = require('jimp'); var mime = require('mime'); var winston = require('winston'); @@ -14,7 +11,6 @@ var image = require('../image'); var uploadsController = require('../controllers/uploads'); module.exports = function (Groups) { - Groups.updateCoverPosition = function (groupName, position, callback) { if (!groupName) { return callback(new Error('[[error:invalid-data]]')); @@ -23,7 +19,6 @@ module.exports = function (Groups) { }; Groups.updateCover = function (uid, data, callback) { - // Position only? That's fine if (!data.imageData && !data.file && data.position) { return Groups.updateCoverPosition(data.groupName, data.position, callback); @@ -45,7 +40,7 @@ module.exports = function (Groups) { uploadsController.uploadGroupCover(uid, { name: 'groupCover', path: tempPath, - type: type + type: type, }, next); }, function (uploadData, next) { @@ -59,7 +54,7 @@ module.exports = function (Groups) { uploadsController.uploadGroupCover(uid, { name: 'groupCoverThumb', path: tempPath, - type: type + type: type, }, next); }, function (uploadData, next) { @@ -71,13 +66,13 @@ module.exports = function (Groups) { } else { next(null); } - } + }, ], function (err) { fs.unlink(tempPath, function (unlinkErr) { if (unlinkErr) { winston.error(unlinkErr); } - callback(err, {url: url}); + callback(err, { url: url }); }); }); }; @@ -92,7 +87,7 @@ module.exports = function (Groups) { }, function (image, next) { image.write(path, next); - } + }, ], function (err) { callback(err); }); @@ -101,5 +96,4 @@ module.exports = function (Groups) { Groups.removeCover = function (data, callback) { db.deleteObjectFields('group:' + data.groupName, ['cover:url', 'cover:thumb:url', 'cover:position'], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/groups/create.js b/src/groups/create.js index a59567afe6..4b680b8992 100644 --- a/src/groups/create.js +++ b/src/groups/create.js @@ -7,7 +7,6 @@ var utils = require('../../public/src/utils'); var db = require('../database'); module.exports = function (Groups) { - Groups.create = function (data, callback) { var system = isSystemGroup(data); var groupData; @@ -42,14 +41,14 @@ module.exports = function (Groups) { hidden: parseInt(data.hidden, 10) === 1 ? 1 : 0, system: system ? 1 : 0, private: isPrivate, - disableJoinRequests: disableJoinRequests + disableJoinRequests: disableJoinRequests, }; - plugins.fireHook('filter:group.create', {group: groupData, data: data}, next); + plugins.fireHook('filter:group.create', { group: groupData, data: data }, next); }, function (results, next) { var tasks = [ async.apply(db.sortedSetAdd, 'groups:createtime', groupData.createtime, groupData.name), - async.apply(db.setObject, 'group:' + groupData.name, groupData) + async.apply(db.setObject, 'group:' + groupData.name, groupData), ]; if (data.hasOwnProperty('ownerUid')) { @@ -72,9 +71,8 @@ module.exports = function (Groups) { function (results, next) { plugins.fireHook('action:group.create', groupData); next(null, groupData); - } + }, ], callback); - }; function isSystemGroup(data) { diff --git a/src/groups/data.js b/src/groups/data.js new file mode 100644 index 0000000000..24e7f99a02 --- /dev/null +++ b/src/groups/data.js @@ -0,0 +1,93 @@ +'use strict'; + +var async = require('async'); +var validator = require('validator'); + +var db = require('../database'); +var plugins = require('../plugins'); +var utils = require('../../public/src/utils'); + +module.exports = function (Groups) { + Groups.getGroupsData = function (groupNames, callback) { + if (!Array.isArray(groupNames) || !groupNames.length) { + return callback(null, []); + } + + var keys = groupNames.map(function (groupName) { + return 'group:' + groupName; + }); + + var ephemeralIdx = groupNames.reduce(function (memo, cur, idx) { + if (Groups.ephemeralGroups.indexOf(cur) !== -1) { + memo.push(idx); + } + return memo; + }, []); + + async.waterfall([ + function (next) { + db.getObjects(keys, next); + }, + function (groupData, next) { + if (ephemeralIdx.length) { + ephemeralIdx.forEach(function (idx) { + groupData[idx] = Groups.getEphemeralGroup(groupNames[idx]); + }); + } + + groupData.forEach(function (group) { + if (group) { + Groups.escapeGroupData(group); + group.userTitleEnabled = group.userTitleEnabled ? parseInt(group.userTitleEnabled, 10) === 1 : true; + group.labelColor = validator.escape(String(group.labelColor || '#000000')); + group.icon = validator.escape(String(group.icon || '')); + group.createtimeISO = utils.toISOString(group.createtime); + group.hidden = parseInt(group.hidden, 10) === 1; + group.system = parseInt(group.system, 10) === 1; + group.private = (group.private === null || group.private === undefined) ? true : !!parseInt(group.private, 10); + group.disableJoinRequests = parseInt(group.disableJoinRequests, 10) === 1; + + group['cover:url'] = group['cover:url'] || require('../coverPhoto').getDefaultGroupCover(group.name); + group['cover:thumb:url'] = group['cover:thumb:url'] || group['cover:url']; + group['cover:position'] = validator.escape(String(group['cover:position'] || '50% 50%')); + } + }); + + plugins.fireHook('filter:groups.get', { groups: groupData }, next); + }, + function (results, next) { + next(null, results.groups); + }, + ], callback); + }; + + Groups.getGroupData = function (groupName, callback) { + Groups.getGroupsData([groupName], function (err, groupsData) { + callback(err, Array.isArray(groupsData) && groupsData[0] ? groupsData[0] : null); + }); + }; + + Groups.getGroupFields = function (groupName, fields, callback) { + Groups.getMultipleGroupFields([groupName], fields, function (err, groups) { + callback(err, groups ? groups[0] : null); + }); + }; + + Groups.getMultipleGroupFields = function (groups, fields, callback) { + db.getObjectsFields(groups.map(function (group) { + return 'group:' + group; + }), fields, callback); + }; + + Groups.setGroupField = function (groupName, field, value, callback) { + async.waterfall([ + function (next) { + db.setObjectField('group:' + groupName, field, value, next); + }, + function (next) { + plugins.fireHook('action:group.set', { field: field, value: value, type: 'set' }); + next(); + }, + ], callback); + }; +}; diff --git a/src/groups/delete.js b/src/groups/delete.js index 0838dd2407..6aed7173a2 100644 --- a/src/groups/delete.js +++ b/src/groups/delete.js @@ -6,7 +6,6 @@ var utils = require('../../public/src/utils'); var db = require('./../database'); module.exports = function (Groups) { - Groups.destroy = function (groupName, callback) { Groups.getGroupsData([groupName], function (err, groupsData) { if (err) { @@ -39,7 +38,7 @@ module.exports = function (Groups) { db.sortedSetRemove('group:' + group + ':members', groupName, next); }, next); }); - } + }, ], function (err) { if (err) { return callback(err); diff --git a/src/groups/membership.js b/src/groups/membership.js index 68a9724c9c..6bcafd2343 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -15,11 +15,10 @@ var LRU = require('lru-cache'); var cache = LRU({ max: 40000, - maxAge: 1000 * 60 * 60 + maxAge: 1000 * 60 * 60, }); module.exports = function (Groups) { - Groups.cache = cache; Groups.join = function (groupName, uid, callback) { @@ -46,7 +45,7 @@ module.exports = function (Groups) { Groups.create({ name: groupName, description: '', - hidden: 1 + hidden: 1, }, function (err) { if (err && err.message !== '[[error:group-already-exists]]') { winston.error('[groups.join] Could not create new hidden group: ' + err.message); @@ -62,13 +61,13 @@ module.exports = function (Groups) { }, isHidden: function (next) { Groups.isHidden(groupName, next); - } + }, }, next); }, function (results, next) { var tasks = [ async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', Date.now(), uid), - async.apply(db.incrObjectField, 'group:' + groupName, 'memberCount') + async.apply(db.incrObjectField, 'group:' + groupName, 'memberCount'), ]; if (results.isAdmin) { tasks.push(async.apply(db.setAdd, 'group:' + groupName + ':owners', uid)); @@ -85,10 +84,10 @@ module.exports = function (Groups) { function (next) { plugins.fireHook('action:group.join', { groupName: groupName, - uid: uid + uid: uid, }); next(); - } + }, ], callback); }; @@ -120,12 +119,12 @@ module.exports = function (Groups) { bodyLong: '[[groups:request.notification_text, ' + username + ', ' + groupName + ']]', nid: 'group:' + groupName + ':uid:' + uid + ':request', path: '/groups/' + utils.slugify(groupName), - from: uid + from: uid, }, next); }, owners: function (next) { Groups.getOwners(groupName, next); - } + }, }, next); }, function (results, next) { @@ -133,7 +132,7 @@ module.exports = function (Groups) { return next(); } notifications.push(results.notification, results.owners, next); - } + }, ], callback); }; @@ -141,14 +140,14 @@ module.exports = function (Groups) { async.waterfall([ async.apply(db.setRemove, 'group:' + groupName + ':pending', uid), async.apply(db.setRemove, 'group:' + groupName + ':invited', uid), - async.apply(Groups.join, groupName, uid) + async.apply(Groups.join, groupName, uid), ], callback); }; Groups.rejectMembership = function (groupName, uid, callback) { async.parallel([ async.apply(db.setRemove, 'group:' + groupName + ':pending', uid), - async.apply(db.setRemove, 'group:' + groupName + ':invited', uid) + async.apply(db.setRemove, 'group:' + groupName + ':invited', uid), ], callback); }; @@ -159,11 +158,11 @@ module.exports = function (Groups) { bodyShort: '[[groups:invited.notification_title, ' + groupName + ']]', bodyLong: '', nid: 'group:' + groupName + ':uid:' + uid + ':invite', - path: '/groups/' + utils.slugify(groupName) + path: '/groups/' + utils.slugify(groupName), }), function (notification, next) { notifications.push(notification, [uid], next); - } + }, ], callback); }; @@ -180,7 +179,7 @@ module.exports = function (Groups) { exists: async.apply(Groups.exists, groupName), isMember: async.apply(Groups.isMember, uid, groupName), isPending: async.apply(Groups.isPending, uid, groupName), - isInvited: async.apply(Groups.isInvited, uid, groupName) + isInvited: async.apply(Groups.isInvited, uid, groupName), }, next); }, function (checks, next) { @@ -199,10 +198,10 @@ module.exports = function (Groups) { function (next) { plugins.fireHook(hookName, { groupName: groupName, - uid: uid + uid: uid, }); next(); - } + }, ], callback); } @@ -227,7 +226,7 @@ module.exports = function (Groups) { async.parallel([ async.apply(db.sortedSetRemove, 'group:' + groupName + ':members', uid), async.apply(db.setRemove, 'group:' + groupName + ':owners', uid), - async.apply(db.decrObjectField, 'group:' + groupName, 'memberCount') + async.apply(db.decrObjectField, 'group:' + groupName, 'memberCount'), ], next); }, function (results, next) { @@ -240,21 +239,19 @@ module.exports = function (Groups) { } if (Groups.isPrivilegeGroup(groupName) && parseInt(groupData.memberCount, 10) === 0) { Groups.destroy(groupName, next); + } else if (parseInt(groupData.hidden, 10) !== 1) { + db.sortedSetAdd('groups:visible:memberCount', groupData.memberCount, groupName, next); } else { - if (parseInt(groupData.hidden, 10) !== 1) { - db.sortedSetAdd('groups:visible:memberCount', groupData.memberCount, groupName, next); - } else { - next(); - } + next(); } }, function (next) { plugins.fireHook('action:group.leave', { groupName: groupName, - uid: uid + uid: uid, }); next(); - } + }, ], callback); }; @@ -277,10 +274,10 @@ module.exports = function (Groups) { }, function (next) { Groups.rejectMembership(groupName, uid, next); - } + }, ], next); }, next); - } + }, ], callback); }; @@ -316,7 +313,7 @@ module.exports = function (Groups) { }); function clearCache(uid, groupName) { - pubsub.publish('group:cache:del', {uid: uid, groupName: groupName}); + pubsub.publish('group:cache:del', { uid: uid, groupName: groupName }); cache.del(uid + ':' + groupName); } @@ -341,7 +338,7 @@ module.exports = function (Groups) { function (isMember, next) { cache.set(cacheKey, isMember); next(null, isMember); - } + }, ], callback); }; @@ -353,7 +350,7 @@ module.exports = function (Groups) { } if (!groupName || !uids.length) { - return callback(null, uids.map(function () {return false;})); + return callback(null, uids.map(function () { return false; })); } var nonCachedUids = uids.filter(function (uid) { @@ -374,7 +371,7 @@ module.exports = function (Groups) { }); getFromCache(next); - } + }, ], callback); }; @@ -386,7 +383,7 @@ module.exports = function (Groups) { } if (!uid || parseInt(uid, 10) <= 0 || !groups.length) { - return callback(null, groups.map(function () {return false;})); + return callback(null, groups.map(function () { return false; })); } var nonCachedGroups = groups.filter(function (groupName) { @@ -411,37 +408,38 @@ module.exports = function (Groups) { }); getFromCache(next); - } + }, ], callback); }; Groups.getMemberCount = function (groupName, callback) { - db.getObjectField('group:' + groupName, 'memberCount', function (err, count) { - if (err) { - return callback(err); - } - callback(null, parseInt(count, 10)); - }); + async.waterfall([ + function (next) { + db.getObjectField('group:' + groupName, 'memberCount', next); + }, + function (count, next) { + next(null, parseInt(count, 10)); + }, + ], callback); }; Groups.isMemberOfGroupList = function (uid, groupListKey, callback) { - db.getSortedSetRange('group:' + groupListKey + ':members', 0, -1, function (err, groupNames) { - if (err) { - return callback(err); - } - groupNames = Groups.internals.removeEphemeralGroups(groupNames); - if (groupNames.length === 0) { - return callback(null, false); - } - - Groups.isMemberOfGroups(uid, groupNames, function (err, isMembers) { - if (err) { - return callback(err); + async.waterfall([ + function (next) { + db.getSortedSetRange('group:' + groupListKey + ':members', 0, -1, next); + }, + function (groupNames, next) { + groupNames = Groups.removeEphemeralGroups(groupNames); + if (groupNames.length === 0) { + return callback(null, false); } - callback(null, isMembers.indexOf(true) !== -1); - }); - }); + Groups.isMemberOfGroups(uid, groupNames, next); + }, + function (isMembers, next) { + next(null, isMembers.indexOf(true) !== -1); + }, + ], callback); }; Groups.isMemberOfGroupsList = function (uid, groupListKeys, callback) { @@ -449,19 +447,20 @@ module.exports = function (Groups) { return 'group:' + groupName + ':members'; }); - db.getSortedSetsMembers(sets, function (err, members) { - if (err) { - return callback(err); - } - - var uniqueGroups = _.unique(_.flatten(members)); - uniqueGroups = Groups.internals.removeEphemeralGroups(uniqueGroups); - - Groups.isMemberOfGroups(uid, uniqueGroups, function (err, isMembers) { - if (err) { - return callback(err); - } + var uniqueGroups; + var members; + async.waterfall([ + function (next) { + db.getSortedSetsMembers(sets, next); + }, + function (_members, next) { + members = _members; + uniqueGroups = _.unique(_.flatten(members)); + uniqueGroups = Groups.removeEphemeralGroups(uniqueGroups); + Groups.isMemberOfGroups(uid, uniqueGroups, next); + }, + function (isMembers, next) { var map = {}; uniqueGroups.forEach(function (groupName, index) { @@ -469,7 +468,7 @@ module.exports = function (Groups) { }); var result = members.map(function (groupNames) { - for (var i = 0; i < groupNames.length; ++i) { + for (var i = 0; i < groupNames.length; i += 1) { if (map[groupNames[i]]) { return true; } @@ -477,62 +476,63 @@ module.exports = function (Groups) { return false; }); - callback(null, result); - }); - }); + next(null, result); + }, + ], callback); }; Groups.isMembersOfGroupList = function (uids, groupListKey, callback) { - db.getSortedSetRange('group:' + groupListKey + ':members', 0, -1, function (err, groupNames) { - if (err) { - return callback(err); - } + var groupNames; + var results = []; + uids.forEach(function () { + results.push(false); + }); - var results = []; - uids.forEach(function () { - results.push(false); - }); + async.waterfall([ + function (next) { + db.getSortedSetRange('group:' + groupListKey + ':members', 0, -1, next); + }, + function (_groupNames, next) { + groupNames = Groups.removeEphemeralGroups(_groupNames); - groupNames = Groups.internals.removeEphemeralGroups(groupNames); - if (groupNames.length === 0) { - return callback(null, results); - } + if (groupNames.length === 0) { + return callback(null, results); + } - async.each(groupNames, function (groupName, next) { - Groups.isMembers(uids, groupName, function (err, isMembers) { - if (err) { - return next(err); - } + async.map(groupNames, function (groupName, next) { + Groups.isMembers(uids, groupName, next); + }, next); + }, + function (isGroupMembers, next) { + isGroupMembers.forEach(function (isMembers) { results.forEach(function (isMember, index) { if (!isMember && isMembers[index]) { results[index] = true; } }); - next(); }); - }, function (err) { - callback(err, results); - }); - }); + next(null, results); + }, + ], callback); }; Groups.isInvited = function (uid, groupName, callback) { if (!uid) { - return callback(null, false); + return setImmediate(callback, null, false); } db.isSetMember('group:' + groupName + ':invited', uid, callback); }; Groups.isPending = function (uid, groupName, callback) { if (!uid) { - return callback(null, false); + return setImmediate(callback, null, false); } db.isSetMember('group:' + groupName + ':pending', uid, callback); }; Groups.getPending = function (groupName, callback) { if (!groupName) { - return callback(null, []); + return setImmediate(callback, null, []); } db.getSetMembers('group:' + groupName + ':pending', callback); }; @@ -549,7 +549,7 @@ module.exports = function (Groups) { return next(new Error('[[error:group-needs-owner]]')); } Groups.leave(groupName, uid, next); - } + }, ], callback); } else { Groups.leave(groupName, uid, callback); diff --git a/src/groups/ownership.js b/src/groups/ownership.js index f397abe5e7..0b386bbe35 100644 --- a/src/groups/ownership.js +++ b/src/groups/ownership.js @@ -1,11 +1,10 @@ 'use strict'; -var async = require('async'), - db = require('../database'), - plugins = require('../plugins'); +var async = require('async'); +var db = require('../database'); +var plugins = require('../plugins'); module.exports = function (Groups) { - Groups.ownership = {}; Groups.ownership.isOwner = function (uid, groupName, callback) { @@ -30,9 +29,9 @@ module.exports = function (Groups) { db.setAdd('group:' + groupName + ':owners', toUid, next); }, function (next) { - plugins.fireHook('action:group.grantOwnership', {uid: toUid, groupName: groupName}); + plugins.fireHook('action:group.grantOwnership', { uid: toUid, groupName: groupName }); next(); - } + }, ], callback); }; @@ -51,9 +50,9 @@ module.exports = function (Groups) { db.setRemove('group:' + groupName + ':owners', toUid, next); }, function (next) { - plugins.fireHook('action:group.rescindOwnership', {uid: toUid, groupName: groupName}); + plugins.fireHook('action:group.rescindOwnership', { uid: toUid, groupName: groupName }); next(); - } + }, ], callback); }; }; diff --git a/src/groups/posts.js b/src/groups/posts.js new file mode 100644 index 0000000000..6f4d65520d --- /dev/null +++ b/src/groups/posts.js @@ -0,0 +1,32 @@ +'use strict'; + +var async = require('async'); + +var db = require('../database'); +var privileges = require('../privileges'); +var posts = require('../posts'); + +module.exports = function (Groups) { + Groups.getLatestMemberPosts = function (groupName, max, uid, callback) { + async.waterfall([ + function (next) { + Groups.getMembers(groupName, 0, -1, next); + }, + function (uids, next) { + if (!Array.isArray(uids) || !uids.length) { + return callback(null, []); + } + var keys = uids.map(function (uid) { + return 'uid:' + uid + ':posts'; + }); + db.getSortedSetRevRange(keys, 0, max - 1, next); + }, + function (pids, next) { + privileges.posts.filter('read', pids, uid, next); + }, + function (pids, next) { + posts.getPostSummaryByPids(pids, uid, { stripTags: false }, next); + }, + ], callback); + }; +}; diff --git a/src/groups/search.js b/src/groups/search.js index 3b6bfab9cd..62df79696c 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -7,7 +7,6 @@ var db = require('./../database'); module.exports = function (Groups) { - Groups.search = function (query, options, callback) { if (!query) { return callback(null, []); @@ -17,7 +16,7 @@ module.exports = function (Groups) { async.apply(db.getObjectValues, 'groupslug:groupname'), function (groupNames, next) { // Ephemeral groups and the registered-users groups are searchable - groupNames = Groups.getEphemeralGroups().concat(groupNames).concat('registered-users'); + groupNames = Groups.ephemeralGroups.concat(groupNames).concat('registered-users'); groupNames = groupNames.filter(function (name) { return name.toLowerCase().indexOf(query) !== -1 && name !== 'administrators' && !Groups.isPrivilegeGroup(name); }); @@ -33,38 +32,37 @@ module.exports = function (Groups) { } Groups.sort(options.sort, groupsData, next); - } + }, ], callback); }; Groups.sort = function (strategy, groups, next) { - switch(strategy) { - case 'count': - groups = groups.sort(function (a, b) { - return a.slug > b.slug; - }).sort(function (a, b) { - return b.memberCount - a.memberCount; - }); - break; + switch (strategy) { + case 'count': + groups = groups.sort(function (a, b) { + return a.slug > b.slug; + }).sort(function (a, b) { + return b.memberCount - a.memberCount; + }); + break; - case 'date': - groups = groups.sort(function (a, b) { - return b.createtime - a.createtime; - }); - break; + case 'date': + groups = groups.sort(function (a, b) { + return b.createtime - a.createtime; + }); + break; - case 'alpha': // intentional fall-through - default: - groups = groups.sort(function (a, b) { - return a.slug > b.slug ? 1 : -1; - }); + case 'alpha': // intentional fall-through + default: + groups = groups.sort(function (a, b) { + return a.slug > b.slug ? 1 : -1; + }); } next(null, groups); }; Groups.searchMembers = function (data, callback) { - function findUids(query, searchBy, callback) { query = query.toLowerCase(); @@ -77,14 +75,14 @@ module.exports = function (Groups) { }, function (users, next) { var uids = []; - for(var i = 0; i < users.length; ++i) { + for (var i = 0; i < users.length; i += 1) { var field = users[i][searchBy]; if (field.toLowerCase().startsWith(query)) { uids.push(users[i].uid); } } next(null, uids); - } + }, ], callback); } @@ -93,7 +91,7 @@ module.exports = function (Groups) { if (err) { return callback(err); } - callback(null, {users: users}); + callback(null, { users: users }); }); return; } @@ -112,24 +110,22 @@ module.exports = function (Groups) { Groups.ownership.isOwners(uids, data.groupName, next); }, function (isOwners, next) { - results.users.forEach(function (user, index) { if (user) { user.isOwner = isOwners[index]; } }); - results.users.sort(function (a,b) { + results.users.sort(function (a, b) { if (a.isOwner && !b.isOwner) { return -1; } else if (!a.isOwner && b.isOwner) { return 1; - } else { - return 0; } + return 0; }); next(null, results); - } + }, ], callback); }; }; diff --git a/src/groups/update.js b/src/groups/update.js index 4dfe760a96..9bf53886e5 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -9,7 +9,6 @@ var db = require('../database'); module.exports = function (Groups) { - Groups.update = function (groupName, values, callback) { callback = callback || function () {}; @@ -23,7 +22,7 @@ module.exports = function (Groups) { } plugins.fireHook('filter:group.update', { groupName: groupName, - values: values + values: values, }, next); }, function (result, next) { @@ -32,7 +31,7 @@ module.exports = function (Groups) { var payload = { description: values.description || '', icon: values.icon || '', - labelColor: values.labelColor || '#000000' + labelColor: values.labelColor || '#000000', }; if (values.hasOwnProperty('userTitle')) { @@ -71,16 +70,16 @@ module.exports = function (Groups) { } }, async.apply(db.setObject, 'group:' + groupName, payload), - async.apply(renameGroup, groupName, values.name) + async.apply(renameGroup, groupName, values.name), ], next); }, function (result, next) { plugins.fireHook('action:group.update', { name: groupName, - values: values + values: values, }); next(); - } + }, ], callback); }; @@ -92,16 +91,18 @@ module.exports = function (Groups) { async.apply(db.sortedSetRemove, 'groups:visible:name', groupName.toLowerCase() + ':' + groupName), ], callback); } else { - db.getObjectFields('group:' + groupName, ['createtime', 'memberCount'], function (err, groupData) { - if (err) { - return callback(err); - } - async.parallel([ - async.apply(db.sortedSetAdd, 'groups:visible:createtime', groupData.createtime, groupName), - async.apply(db.sortedSetAdd, 'groups:visible:memberCount', groupData.memberCount, groupName), - async.apply(db.sortedSetAdd, 'groups:visible:name', 0, groupName.toLowerCase() + ':' + groupName), - ], callback); - }); + async.waterfall([ + function (next) { + db.getObjectFields('group:' + groupName, ['createtime', 'memberCount'], next); + }, + function (groupData, next) { + async.parallel([ + async.apply(db.sortedSetAdd, 'groups:visible:createtime', groupData.createtime, groupName), + async.apply(db.sortedSetAdd, 'groups:visible:memberCount', groupData.memberCount, groupName), + async.apply(db.sortedSetAdd, 'groups:visible:name', 0, groupName.toLowerCase() + ':' + groupName), + ], next); + }, + ], callback); } } @@ -118,7 +119,7 @@ module.exports = function (Groups) { callback = callback || function () {}; async.parallel([ async.apply(db.setObjectField, 'group:' + groupName, 'hidden', hidden ? 1 : 0), - async.apply(updateVisibility, groupName, hidden) + async.apply(updateVisibility, groupName, hidden), ], function (err) { callback(err); }); @@ -131,7 +132,7 @@ module.exports = function (Groups) { }, function (currentValue, next) { var currentlyPrivate = parseInt(currentValue.private, 10) === 1; - if (!currentlyPrivate || currentlyPrivate === isPrivate) { + if (!currentlyPrivate || currentlyPrivate === isPrivate) { return callback(); } db.getSetMembers('group:' + groupName + ':pending', next); @@ -146,9 +147,9 @@ module.exports = function (Groups) { winston.verbose('[groups.update] Group is now public, automatically adding ' + uids.length + ' new members, who were pending prior.'); async.series([ async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', scores, uids), - async.apply(db.delete, 'group:' + groupName + ':pending') + async.apply(db.delete, 'group:' + groupName + ':pending'), ], next); - } + }, ], function (err) { callback(err); }); @@ -156,40 +157,48 @@ module.exports = function (Groups) { function checkNameChange(currentName, newName, callback) { if (currentName === newName) { - return callback(); + return setImmediate(callback); } var currentSlug = utils.slugify(currentName); var newSlug = utils.slugify(newName); if (currentSlug === newSlug) { - return callback(); + return setImmediate(callback); } - Groups.existsBySlug(newSlug, function (err, exists) { - if (err || exists) { - return callback(err || new Error('[[error:group-already-exists]]')); - } - callback(); - }); + async.waterfall([ + function (next) { + Groups.existsBySlug(newSlug, next); + }, + function (exists, next) { + next(exists ? new Error('[[error:group-already-exists]]') : null); + }, + ], callback); } function renameGroup(oldName, newName, callback) { if (oldName === newName || !newName || newName.length === 0) { - return callback(); + return setImmediate(callback); } - - db.getObject('group:' + oldName, function (err, group) { - if (err || !group) { - return callback(err); - } - - if (parseInt(group.system, 10) === 1) { - return callback(); - } - - Groups.exists(newName, function (err, exists) { - if (err || exists) { - return callback(err || new Error('[[error:group-already-exists]]')); + var group; + async.waterfall([ + function (next) { + db.getObject('group:' + oldName, next); + }, + function (_group, next) { + group = _group; + if (!group) { + return callback(); } + if (parseInt(group.system, 10) === 1) { + return callback(new Error('[[error:not-allowed-to-rename-system-group]]')); + } + + Groups.exists(newName, next); + }, + function (exists, next) { + if (exists) { + return callback(new Error('[[error:group-already-exists]]')); + } async.series([ async.apply(db.setObjectField, 'group:' + oldName, 'name', newName), async.apply(db.setObjectField, 'group:' + oldName, 'slug', utils.slugify(newName)), @@ -218,34 +227,38 @@ module.exports = function (Groups) { function (next) { plugins.fireHook('action:group.rename', { old: oldName, - new: newName + new: newName, }); next(); - } - ], callback); - }); + }, + ], next); + }, + ], function (err) { + callback(err); }); } function renameGroupMember(group, oldName, newName, callback) { - db.isSortedSetMember(group, oldName, function (err, isMember) { - if (err || !isMember) { - return callback(err); - } - var score; - async.waterfall([ - function (next) { - db.sortedSetScore(group, oldName, next); - }, - function (_score, next) { - score = _score; - db.sortedSetRemove(group, oldName, next); - }, - function (next) { - db.sortedSetAdd(group, score, newName, next); + var score; + async.waterfall([ + function (next) { + db.isSortedSetMember(group, oldName, next); + }, + function (isMember, next) { + if (!isMember) { + return callback(); } - ], callback); - }); + + db.sortedSetScore(group, oldName, next); + }, + function (_score, next) { + score = _score; + db.sortedSetRemove(group, oldName, next); + }, + function (next) { + db.sortedSetAdd(group, score, newName, next); + }, + ], callback); } }; diff --git a/src/groups/user.js b/src/groups/user.js new file mode 100644 index 0000000000..9a68478ade --- /dev/null +++ b/src/groups/user.js @@ -0,0 +1,50 @@ +'use strict'; + +var async = require('async'); + +var db = require('../database'); +var user = require('../user'); + +module.exports = function (Groups) { + Groups.getUsersFromSet = function (set, callback) { + async.waterfall([ + function (next) { + db.getSetMembers(set, next); + }, + function (uids, next) { + user.getUsersData(uids, next); + }, + ], callback); + }; + + Groups.getUserGroups = function (uids, callback) { + Groups.getUserGroupsFromSet('groups:visible:createtime', uids, callback); + }; + + Groups.getUserGroupsFromSet = function (set, uids, callback) { + async.waterfall([ + function (next) { + db.getSortedSetRevRange(set, 0, -1, next); + }, + function (groupNames, next) { + async.map(uids, function (uid, next) { + async.waterfall([ + function (next) { + Groups.isMemberOfGroups(uid, groupNames, next); + }, + function (isMembers, next) { + var memberOf = []; + isMembers.forEach(function (isMember, index) { + if (isMember) { + memberOf.push(groupNames[index]); + } + }); + + Groups.getGroupsData(memberOf, next); + }, + ], next); + }, next); + }, + ], callback); + }; +}; diff --git a/src/hotswap.js b/src/hotswap.js index ece8f205d7..76cb2f774b 100644 --- a/src/hotswap.js +++ b/src/hotswap.js @@ -1,8 +1,8 @@ -"use strict"; +'use strict'; -var HotSwap = {}, - winston = require('winston'), - stack; +var HotSwap = {}; +var winston = require('winston'); +var stack; HotSwap.prepare = function (app) { stack = app._router.stack; @@ -10,7 +10,7 @@ HotSwap.prepare = function (app) { HotSwap.find = function (id) { if (stack) { - for(var x = 0,numEntries = stack.length; x < numEntries; x++) { + for (var x = 0, numEntries = stack.length; x < numEntries; x += 1) { if (stack[x].handle.hotswapId === id) { return x; } @@ -31,4 +31,4 @@ HotSwap.replace = function (id, router) { } }; -module.exports = HotSwap; \ No newline at end of file +module.exports = HotSwap; diff --git a/src/image.js b/src/image.js index 7b428f2331..1609993731 100644 --- a/src/image.js +++ b/src/image.js @@ -19,7 +19,7 @@ image.resizeImage = function (data, callback) { target: data.target, extension: data.extension, width: data.width, - height: data.height + height: data.height, }, function (err) { callback(err); }); @@ -29,13 +29,13 @@ image.resizeImage = function (data, callback) { return callback(err); } - var w = image.bitmap.width, - h = image.bitmap.height, - origRatio = w / h, - desiredRatio = data.width && data.height ? data.width / data.height : origRatio, - x = 0, - y = 0, - crop; + var w = image.bitmap.width; + var h = image.bitmap.height; + var origRatio = w / h; + var desiredRatio = data.width && data.height ? data.width / data.height : origRatio; + var x = 0; + var y = 0; + var crop; if (origRatio !== desiredRatio) { if (desiredRatio > origRatio) { @@ -47,7 +47,7 @@ image.resizeImage = function (data, callback) { crop = async.apply(image.crop.bind(image), x, y, h * desiredRatio, h); } else { x = 0; // width is the smaller dimension here - y = Math.floor(h / 2 - (w * desiredRatio / 2)); + y = Math.floor((h / 2) - (w * desiredRatio / 2)); crop = async.apply(image.crop.bind(image), x, y, w, w * desiredRatio); } } else { @@ -71,7 +71,7 @@ image.resizeImage = function (data, callback) { }, function (image, next) { image.write(data.target || data.path, next); - } + }, ], function (err) { callback(err); }); @@ -83,7 +83,7 @@ image.normalise = function (path, extension, callback) { if (plugins.hasListeners('filter:image.normalise')) { plugins.fireHook('filter:image.normalise', { path: path, - extension: extension + extension: extension, }, function (err) { callback(err, path + '.png'); }); @@ -138,8 +138,8 @@ image.writeImageDataToTempFile = function (imageData, callback) { var buffer = new Buffer(imageData.slice(imageData.indexOf('base64') + 7), 'base64'); fs.writeFile(filepath, buffer, { - encoding: 'base64' + encoding: 'base64', }, function (err) { callback(err, filepath); }); -}; \ No newline at end of file +}; diff --git a/src/install.js b/src/install.js index c5ae1e214b..a06a138f26 100644 --- a/src/install.js +++ b/src/install.js @@ -15,7 +15,7 @@ questions.main = [ { name: 'url', description: 'URL used to access this NodeBB', - 'default': + default: nconf.get('url') || (nconf.get('base_url') ? (nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '')) : null) || // backwards compatibility (remove for v0.7.0) 'http://localhost:4567', @@ -25,20 +25,20 @@ questions.main = [ { name: 'secret', description: 'Please enter a NodeBB secret', - 'default': nconf.get('secret') || utils.generateUUID() + default: nconf.get('secret') || utils.generateUUID(), }, { name: 'database', description: 'Which database to use', - 'default': nconf.get('database') || 'mongo' - } + default: nconf.get('database') || 'mongo', + }, ]; questions.optional = [ { name: 'port', - default: nconf.get('port') || 4567 - } + default: nconf.get('port') || 4567, + }, ]; function checkSetupFlag(next) { @@ -75,7 +75,7 @@ function checkSetupFlag(next) { } } else if (nconf.get('database')) { install.values = { - database: nconf.get('database') + database: nconf.get('database'), }; next(); } else { @@ -133,7 +133,7 @@ function setupConfig(next) { var allQuestions = questions.main.concat(questions.optional).concat(redisQuestions).concat(mongoQuestions); allQuestions.forEach(function (question) { - config[question.name] = install.values[question.name] || question['default'] || undefined; + config[question.name] = install.values[question.name] || question.default || undefined; }); setImmediate(next, null, config); } else { @@ -145,7 +145,7 @@ function setupConfig(next) { }, function (config, next) { completeConfigSetup(config, next); - } + }, ], next); } @@ -153,7 +153,7 @@ function completeConfigSetup(config, next) { // Add CI object if (install.ciVals) { config.test_database = {}; - for(var prop in install.ciVals) { + for (var prop in install.ciVals) { if (install.ciVals.hasOwnProperty(prop)) { config.test_database[prop] = install.ciVals[prop]; } @@ -169,7 +169,7 @@ function completeConfigSetup(config, next) { }, function (next) { require('./database').createIndices(next); - } + }, ], next); } @@ -199,7 +199,7 @@ function enableDefaultTheme(next) { process.stdout.write('Enabling default theme: ' + defaultTheme + '\n'); meta.themes.set({ type: 'local', - id: defaultTheme + id: defaultTheme, }, next); }); } @@ -228,84 +228,84 @@ function createAdmin(callback) { winston.warn('No administrators have been detected, running initial user setup\n'); var questions = [{ - name: 'username', - description: 'Administrator username', - required: true, - type: 'string' - }, { - name: 'email', - description: 'Administrator email address', - pattern: /.+@.+/, - required: true - }], - passwordQuestions = [{ - name: 'password', - description: 'Password', - required: true, - hidden: true, - type: 'string' - }, { - name: 'password:confirm', - description: 'Confirm Password', - required: true, - hidden: true, - type: 'string' - }], - success = function (err, results) { + name: 'username', + description: 'Administrator username', + required: true, + type: 'string', + }, { + name: 'email', + description: 'Administrator email address', + pattern: /.+@.+/, + required: true, + }]; + var passwordQuestions = [{ + name: 'password', + description: 'Password', + required: true, + hidden: true, + type: 'string', + }, { + name: 'password:confirm', + description: 'Confirm Password', + required: true, + hidden: true, + type: 'string', + }]; + function success(err, results) { + if (err) { + return callback(err); + } + if (!results) { + return callback(new Error('aborted')); + } + + if (results['password:confirm'] !== results.password) { + winston.warn('Passwords did not match, please try again'); + return retryPassword(results); + } + + if (results.password.length < meta.config.minimumPasswordLength) { + winston.warn('Password too short, please try again'); + return retryPassword(results); + } + + var adminUid; + async.waterfall([ + function (next) { + User.create({ username: results.username, password: results.password, email: results.email }, next); + }, + function (uid, next) { + adminUid = uid; + Groups.join('administrators', uid, next); + }, + function (next) { + Groups.show('administrators', next); + }, + function (next) { + Groups.ownership.grant(adminUid, 'administrators', next); + }, + ], function (err) { if (err) { return callback(err); } + callback(null, password ? results : undefined); + }); + } + function retryPassword(originalResults) { + // Ask only the password questions + prompt.get(passwordQuestions, function (err, results) { if (!results) { return callback(new Error('aborted')); } - if (results['password:confirm'] !== results.password) { - winston.warn("Passwords did not match, please try again"); - return retryPassword(results); - } - - if (results.password.length < meta.config.minimumPasswordLength) { - winston.warn("Password too short, please try again"); - return retryPassword(results); - } - - var adminUid; - async.waterfall([ - function (next) { - User.create({username: results.username, password: results.password, email: results.email}, next); - }, - function (uid, next) { - adminUid = uid; - Groups.join('administrators', uid, next); - }, - function (next) { - Groups.show('administrators', next); - }, - function (next) { - Groups.ownership.grant(adminUid, 'administrators', next); - } - ], function (err) { - if (err) { - return callback(err); - } - callback(null, password ? results : undefined); - }); - }, - retryPassword = function (originalResults) { - // Ask only the password questions - prompt.get(passwordQuestions, function (err, results) { - if (!results) { - return callback(new Error('aborted')); - } + // Update the original data with newly collected password + originalResults.password = results.password; + originalResults['password:confirm'] = results['password:confirm']; - // Update the original data with newly collected password - originalResults.password = results.password; - originalResults['password:confirm'] = results['password:confirm']; - - // Send back to success to handle - success(err, originalResults); - }); - }; + // Send back to success to handle + success(err, originalResults); + }); + } // Add the password questions questions = questions.concat(passwordQuestions); @@ -323,7 +323,7 @@ function createAdmin(callback) { username: install.values['admin:username'] || nconf.get('admin:username') || 'admin', email: install.values['admin:email'] || nconf.get('admin:email') || '', password: install.values['admin:password'] || nconf.get('admin:password') || password, - 'password:confirm': install.values['admin:password:confirm'] || nconf.get('admin:password') || password + 'password:confirm': install.values['admin:password:confirm'] || nconf.get('admin:password') || password, }; success(null, results); @@ -347,12 +347,12 @@ function createGlobalModeratorsGroup(next) { description: 'Forum wide moderators', hidden: 0, private: 1, - disableJoinRequests: 1 + disableJoinRequests: 1, }, next); }, function (groupData, next) { groups.show('Global Moderators', next); - } + }, ], next); } @@ -397,8 +397,8 @@ function createMenuItems(next) { } function createWelcomePost(next) { - var db = require('./database'), - Topics = require('./topics'); + var db = require('./database'); + var Topics = require('./topics'); async.parallel([ function (next) { @@ -406,14 +406,14 @@ function createWelcomePost(next) { }, function (next) { db.getObjectField('global', 'topicCount', next); - } + }, ], function (err, results) { if (err) { return next(err); } - var content = results[0], - numTopics = results[1]; + var content = results[0]; + var numTopics = results[1]; if (!parseInt(numTopics, 10)) { process.stdout.write('Creating welcome post!\n'); @@ -421,7 +421,7 @@ function createWelcomePost(next) { uid: 1, cid: 2, title: 'Welcome to your NodeBB!', - content: content.toString() + content: content.toString(), }, next); } else { next(); @@ -430,20 +430,19 @@ function createWelcomePost(next) { } function enableDefaultPlugins(next) { - process.stdout.write('Enabling default plugins\n'); var defaultEnabled = [ - 'nodebb-plugin-composer-default', - 'nodebb-plugin-markdown', - 'nodebb-plugin-mentions', - 'nodebb-widget-essentials', - 'nodebb-rewards-essentials', - 'nodebb-plugin-soundpack-default', - 'nodebb-plugin-emoji-extended', - 'nodebb-plugin-emoji-one' - ], - customDefaults = nconf.get('defaultPlugins'); + 'nodebb-plugin-composer-default', + 'nodebb-plugin-markdown', + 'nodebb-plugin-mentions', + 'nodebb-widget-essentials', + 'nodebb-rewards-essentials', + 'nodebb-plugin-soundpack-default', + 'nodebb-plugin-emoji-extended', + 'nodebb-plugin-emoji-one', + ]; + var customDefaults = nconf.get('defaultPlugins'); winston.info('[install/defaultPlugins] customDefaults', customDefaults); @@ -478,7 +477,7 @@ function setCopyrightWidget(next) { }, footer: function (next) { db.getObjectField('widgets:global', 'footer', next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -493,7 +492,6 @@ function setCopyrightWidget(next) { } install.setup = function (callback) { - async.series([ checkSetupFlag, checkCIFlag, @@ -513,10 +511,13 @@ install.setup = function (callback) { if (err) { return next(err); } - if (!uptodate) { upgrade.upgrade(next); } - else { next(); } + if (!uptodate) { + upgrade.upgrade(next); + } else { + next(); + } }); - } + }, ], function (err, results) { if (err) { winston.warn('NodeBB Setup Aborted.\n ' + err.stack); @@ -549,7 +550,7 @@ install.save = function (server_conf, callback) { process.stdout.write('Configuration Saved OK\n'); nconf.file({ - file: path.join(__dirname, '..', 'config.json') + file: path.join(__dirname, '..', 'config.json'), }); callback(); diff --git a/src/logger.js b/src/logger.js index 4d6b8f717c..73180d7add 100644 --- a/src/logger.js +++ b/src/logger.js @@ -4,35 +4,33 @@ * Logger module: ability to dynamically turn on/off logging for http requests & socket.io events */ -var fs = require('fs'), - path = require('path'), - winston = require('winston'), - util = require('util'), +var fs = require('fs'); +var path = require('path'); +var winston = require('winston'); +var util = require('util'); - file = require('./file'), - meta = require('./meta'), - morgan = require('morgan'); +var file = require('./file'); +var meta = require('./meta'); +var morgan = require('morgan'); var opts = { /* * state used by Logger */ - express : { - app : {}, - set : 0, - ofn : null, + express: { + app: {}, + set: 0, + ofn: null, + }, + streams: { + log: { f: process.stdout }, }, - streams : { - log : { f : process.stdout }, - } }; /* -- Logger -- */ (function (Logger) { - - Logger.init = function (app) { opts.express.app = app; /* Open log file stream & initialize express logging if meta.config.logger* variables are set */ @@ -59,15 +57,14 @@ var opts = { * If logging is currently enabled, create a stream. * Otherwise, close the current stream */ - if(meta.config.loggerStatus > 0 || meta.config.loggerIOStatus) { + if (meta.config.loggerStatus > 0 || meta.config.loggerIOStatus) { var stream = Logger.open(value); - if(stream) { + if (stream) { opts.streams.log.f = stream; } else { opts.streams.log.f = process.stdout; } - } - else { + } else { Logger.close(opts.streams.log); } }; @@ -75,22 +72,21 @@ var opts = { Logger.open = function (value) { /* Open the streams to log to: either a path or stdout */ var stream; - if(value) { - if(file.existsSync(value)) { + if (value) { + if (file.existsSync(value)) { var stats = fs.statSync(value); - if(stats) { - if(stats.isDirectory()) { - stream = fs.createWriteStream(path.join(value, 'nodebb.log'), {flags: 'a'}); + if (stats) { + if (stats.isDirectory()) { + stream = fs.createWriteStream(path.join(value, 'nodebb.log'), { flags: 'a' }); } else { - stream = fs.createWriteStream(value, {flags: 'a'}); + stream = fs.createWriteStream(value, { flags: 'a' }); } } } else { - stream = fs.createWriteStream(value, {flags: 'a'}); - + stream = fs.createWriteStream(value, { flags: 'a' }); } - if(stream) { + if (stream) { stream.on('error', function (err) { winston.error(err.message); }); @@ -102,7 +98,7 @@ var opts = { }; Logger.close = function (stream) { - if(stream.f !== process.stdout && stream.f) { + if (stream.f !== process.stdout && stream.f) { stream.end(); } stream.f = null; @@ -112,33 +108,32 @@ var opts = { /* * This monitor's when a user clicks "save" in the Logger section of the admin panel */ - Logger.setup_one(data.key,data.value); + Logger.setup_one(data.key, data.value); Logger.io_close(socket); Logger.io(socket); }; Logger.express_open = function () { - if(opts.express.set !== 1) { + if (opts.express.set !== 1) { opts.express.set = 1; opts.express.app.use(Logger.expressLogger); } /* * Always initialize "ofn" (original function) with the original logger function */ - opts.express.ofn = morgan('combined', {stream : opts.streams.log.f}); + opts.express.ofn = morgan('combined', { stream: opts.streams.log.f }); }; - Logger.expressLogger = function (req,res,next) { + Logger.expressLogger = function (req, res, next) { /* * The new express.logger * * This hijack allows us to turn logger on/off dynamically within express */ - if(meta.config.loggerStatus > 0) { - return opts.express.ofn(req,res,next); - } else { - return next(); + if (meta.config.loggerStatus > 0) { + return opts.express.ofn(req, res, next); } + return next(); }; Logger.prepare_io_string = function (_type, _uid, _args) { @@ -149,9 +144,9 @@ var opts = { */ try { return 'io: ' + _uid + ' ' + _type + ' ' + util.inspect(Array.prototype.slice.call(_args)) + '\n'; - } catch(err) { - winston.info("Logger.prepare_io_string: Failed", err); - return "error"; + } catch (err) { + winston.info('Logger.prepare_io_string: Failed', err); + return 'error'; } }; @@ -166,11 +161,11 @@ var opts = { for (var sid in clients) { if (clients.hasOwnProperty(sid)) { var client = clients[sid]; - if(client.oEmit && client.oEmit !== client.emit) { + if (client.oEmit && client.oEmit !== client.emit) { client.emit = client.oEmit; } - if(client.$oEmit && client.$oEmit !== client.$emit) { + if (client.$oEmit && client.$oEmit !== client.$emit) { client.$emit = client.$oEmit; } } @@ -187,7 +182,7 @@ var opts = { } var clients = socket.io.sockets.sockets; - for(var sid in clients) { + for (var sid in clients) { if (clients.hasOwnProperty(sid)) { Logger.io_one(clients[sid], clients[sid].uid); } @@ -200,13 +195,13 @@ var opts = { */ function override(method, name, errorMsg) { return function () { - if(opts.streams.log.f) { + if (opts.streams.log.f) { opts.streams.log.f.write(Logger.prepare_io_string(name, uid, arguments)); } try { method.apply(socket, arguments); - } catch(err) { + } catch (err) { winston.info(errorMsg, err); } }; @@ -223,5 +218,4 @@ var opts = { socket.$emit = override($emit, 'on', 'Logger.io_one: $emit.apply: Failed'); } }; - }(exports)); diff --git a/src/messaging.js b/src/messaging.js index a37503e3e3..e141adff4f 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -57,7 +57,7 @@ Messaging.getMessages = function (params, callback) { messageData.index = indices[messageData.messageId.toString()]; }); next(null, messageData); - } + }, ], callback); }; @@ -65,7 +65,7 @@ function canGet(hook, callerUid, uid, callback) { plugins.fireHook(hook, { callerUid: callerUid, uid: uid, - canGet: parseInt(callerUid, 10) === parseInt(uid, 10) + canGet: parseInt(callerUid, 10) === parseInt(uid, 10), }, function (err, data) { callback(err, data ? data.canGet : false); }); @@ -84,7 +84,7 @@ Messaging.parse = function (message, fromuid, uid, roomId, isNew, callback) { uid: uid, roomId: roomId, isNew: isNew, - parsedMessage: parsed + parsedMessage: parsed, }; plugins.fireHook('filter:messaging.parse', messageData, function (err, messageData) { @@ -106,7 +106,7 @@ Messaging.isNewSet = function (uid, roomId, timestamp, callback) { } else { next(null, true); } - } + }, ], callback); }; @@ -139,7 +139,7 @@ Messaging.getRecentChats = function (callerUid, uid, start, stop, callback) { uids = uids.filter(function (value) { return value && parseInt(value, 10) !== parseInt(uid, 10); }); - user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'] , next); + user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'], next); }); }, next); }, @@ -147,7 +147,7 @@ Messaging.getRecentChats = function (callerUid, uid, start, stop, callback) { async.map(roomIds, function (roomId, next) { Messaging.getTeaser(uid, roomId, next); }, next); - } + }, }, next); }, function (results, next) { @@ -170,8 +170,8 @@ Messaging.getRecentChats = function (callerUid, uid, start, stop, callback) { room.usernames = Messaging.generateUsernames(room.users, uid); }); - next(null, {rooms: results.roomData, nextStart: stop + 1}); - } + next(null, { rooms: results.roomData, nextStart: stop + 1 }); + }, ], callback); }; @@ -206,19 +206,19 @@ Messaging.getTeaser = function (uid, roomId, callback) { } teaser.timestampISO = utils.toISOString(teaser.timestamp); - user.getUserFields(teaser.fromuid, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'] , next); + user.getUserFields(teaser.fromuid, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'], next); }, function (user, next) { teaser.user = user; plugins.fireHook('filter:messaging.getTeaser', { teaser: teaser }, function (err, data) { next(err, data.teaser); }); - } + }, ], callback); }; Messaging.canMessageUser = function (uid, toUid, callback) { - if (parseInt(meta.config.disableChat) === 1 || !uid || uid === toUid) { + if (parseInt(meta.config.disableChat, 10) === 1 || !uid || uid === toUid) { return callback(new Error('[[error:chat-disabled]]')); } @@ -248,7 +248,7 @@ Messaging.canMessageUser = function (uid, toUid, callback) { async.parallel({ settings: async.apply(user.getSettings, toUid), isAdmin: async.apply(user.isAdministrator, uid), - isFollowing: async.apply(user.isFollowing, toUid, uid) + isFollowing: async.apply(user.isFollowing, toUid, uid), }, next); }, function (results, next) { @@ -256,13 +256,13 @@ Messaging.canMessageUser = function (uid, toUid, callback) { return next(); } - next(new Error('[[error:chat-restricted]]')); - } + next(new Error('[[error:chat-restricted]]')); + }, ], callback); }; Messaging.canMessageRoom = function (uid, roomId, callback) { - if (parseInt(meta.config.disableChat) === 1 || !uid) { + if (parseInt(meta.config.disableChat, 10) === 1 || !uid) { return callback(new Error('[[error:chat-disabled]]')); } @@ -294,7 +294,7 @@ Messaging.canMessageRoom = function (uid, roomId, callback) { } next(); - } + }, ], callback); }; @@ -306,7 +306,7 @@ Messaging.hasPrivateChat = function (uid, withUid, callback) { function (next) { async.parallel({ myRooms: async.apply(db.getSortedSetRevRange, 'uid:' + uid + ':chat:rooms', 0, -1), - theirRooms: async.apply(db.getSortedSetRevRange, 'uid:' + withUid + ':chat:rooms', 0, -1) + theirRooms: async.apply(db.getSortedSetRevRange, 'uid:' + withUid + ':chat:rooms', 0, -1), }, next); }, function (results, next) { @@ -331,13 +331,13 @@ Messaging.hasPrivateChat = function (uid, withUid, callback) { roomId = roomIds[index]; next(null, roomId); } else { - ++ index; + index += 1; next(); } }); }, function (err) { next(err, roomId); }); - } + }, ], callback); }; diff --git a/src/messaging/create.js b/src/messaging/create.js index face15f589..2c6ac84ffb 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -8,7 +8,6 @@ var db = require('../database'); module.exports = function (Messaging) { - Messaging.sendMessage = function (uid, roomId, content, timestamp, callback) { async.waterfall([ function (next) { @@ -23,7 +22,7 @@ module.exports = function (Messaging) { } Messaging.addMessage(uid, roomId, content, timestamp, next); - } + }, ], callback); }; @@ -56,7 +55,7 @@ module.exports = function (Messaging) { content: content, timestamp: timestamp, fromuid: fromuid, - roomId: roomId + roomId: roomId, }; plugins.fireHook('filter:messaging.save', message, next); @@ -76,13 +75,13 @@ module.exports = function (Messaging) { async.apply(Messaging.addRoomToUsers, roomId, uids, timestamp), async.apply(Messaging.addMessageToUsers, roomId, uids, mid, timestamp), async.apply(Messaging.markUnread, uids, roomId), - async.apply(Messaging.addUsersToRoom, fromuid, [fromuid], roomId) + async.apply(Messaging.addUsersToRoom, fromuid, [fromuid], roomId), ], next); }, function (results, next) { async.parallel({ markRead: async.apply(Messaging.markRead, fromuid, roomId), - messages: async.apply(Messaging.getMessagesData, [mid], fromuid, roomId, true) + messages: async.apply(Messaging.getMessagesData, [mid], fromuid, roomId, true), }, next); }, function (results, next) { @@ -94,7 +93,7 @@ module.exports = function (Messaging) { results.messages[0].mid = mid; results.messages[0].roomId = roomId; next(null, results.messages[0]); - } + }, ], callback); }; @@ -117,4 +116,4 @@ module.exports = function (Messaging) { }); db.sortedSetsAdd(keys, timestamp, mid, callback); }; -}; \ No newline at end of file +}; diff --git a/src/messaging/data.js b/src/messaging/data.js index d1a00bd8f4..e3cb67fbd8 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -8,7 +8,6 @@ var user = require('../user'); var utils = require('../../public/src/utils'); module.exports = function (Messaging) { - Messaging.getMessageField = function (mid, field, callback) { Messaging.getMessageFields(mid, [field], function (err, fields) { callback(err, fields ? fields[field] : null); @@ -28,7 +27,6 @@ module.exports = function (Messaging) { }; Messaging.getMessagesData = function (mids, uid, roomId, isNew, callback) { - var messages; async.waterfall([ @@ -110,7 +108,7 @@ module.exports = function (Messaging) { }, function (mid, next) { Messaging.getMessageFields(mid, ['fromuid', 'timestamp'], next); - } + }, ], function (err, fields) { if (err) { return next(err); @@ -129,8 +127,7 @@ module.exports = function (Messaging) { } else { next(null, []); } - } + }, ], callback); }; - }; diff --git a/src/messaging/delete.js b/src/messaging/delete.js index e9f48232d1..6fdf5177ef 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -4,7 +4,6 @@ var async = require('async'); var db = require('../database'); module.exports = function (Messaging) { - Messaging.deleteMessage = function (mid, roomId, callback) { async.waterfall([ function (next) { @@ -21,7 +20,7 @@ module.exports = function (Messaging) { }, function (next) { db.delete('message:' + mid, next); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/messaging/edit.js b/src/messaging/edit.js index b472aea261..f9c664d67f 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -9,7 +9,6 @@ var sockets = require('../socket.io'); module.exports = function (Messaging) { - Messaging.editMessage = function (uid, mid, roomId, content, callback) { var uids; async.waterfall([ @@ -23,7 +22,7 @@ module.exports = function (Messaging) { Messaging.setMessageFields(mid, { content: content, - edited: Date.now() + edited: Date.now(), }, next); }, function (next) { @@ -36,11 +35,11 @@ module.exports = function (Messaging) { function (messages, next) { uids.forEach(function (uid) { sockets.in('uid_' + uid).emit('event:chats.edit', { - messages: messages + messages: messages, }); }); next(); - } + }, ], callback); }; @@ -75,8 +74,7 @@ module.exports = function (Messaging) { }, function (isAdmin, next) { next(null, isAdmin); - } + }, ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 2eeb562b5c..eb7a1a1a74 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -11,7 +11,6 @@ var meta = require('../meta'); var sockets = require('../socket.io'); module.exports = function (Messaging) { - Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser Messaging.notificationSendDelay = 1000 * 60; @@ -25,11 +24,11 @@ module.exports = function (Messaging) { var data = { roomId: roomId, fromUid: fromUid, - message: messageObj + message: messageObj, }; uids.forEach(function (uid) { - data.self = parseInt(uid, 10) === parseInt(fromUid) ? 1 : 0; + data.self = parseInt(uid, 10) === parseInt(fromUid, 10) ? 1 : 0; Messaging.pushUnreadCount(uid); sockets.in('uid_' + uid).emit('event:chats.receive', data); }); @@ -40,16 +39,17 @@ module.exports = function (Messaging) { queueObj.message.content += '\n' + messageObj.content; clearTimeout(queueObj.timeout); } else { - queueObj = Messaging.notifyQueue[fromUid + ':' + roomId] = { - message: messageObj + queueObj = { + message: messageObj, }; + Messaging.notifyQueue[fromUid + ':' + roomId] = queueObj; } queueObj.timeout = setTimeout(function () { sendNotifications(fromUid, uids, roomId, queueObj.message); }, Messaging.notificationSendDelay); next(); - } + }, ]); }; @@ -72,9 +72,9 @@ module.exports = function (Messaging) { bodyLong: messageObj.content, nid: 'chat_' + fromuid + '_' + roomId, from: fromuid, - path: '/chats/' + messageObj.roomId + path: '/chats/' + messageObj.roomId, }, next); - } + }, ], function (err, notification) { if (!err) { delete Messaging.notifyQueue[fromuid + ':' + roomId]; @@ -99,9 +99,10 @@ module.exports = function (Messaging) { }, userSettings: function (next) { user.getMultipleUserSettings(uids, next); - } + }, }, next); }, + function (results, next) { results.userData = results.userData.filter(function (userData, index) { return userData && results.userSettings[index] && results.userSettings[index].sendChatNotifications; @@ -115,14 +116,14 @@ module.exports = function (Messaging) { url: nconf.get('url'), roomId: messageObj.roomId, username: userData.username, - userslug: userData.userslug + userslug: userData.userslug, }, next); }, next); - } + }, ], function (err) { if (err) { return winston.error(err); } }); } -}; \ No newline at end of file +}; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index bea909946a..ead62fee4d 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -8,7 +8,6 @@ var user = require('../user'); var plugins = require('../plugins'); module.exports = function (Messaging) { - Messaging.getRoomData = function (roomId, callback) { db.getObject('chat:room:' + roomId, function (err, data) { if (err || !data) { @@ -55,7 +54,7 @@ module.exports = function (Messaging) { roomId = _roomId; var room = { owner: uid, - roomId: roomId + roomId: roomId, }; db.setObject('chat:room:' + roomId, room, next); }, @@ -70,7 +69,7 @@ module.exports = function (Messaging) { }, function (next) { next(null, roomId); - } + }, ], callback); }; @@ -80,11 +79,11 @@ module.exports = function (Messaging) { db.isSortedSetMember('chat:room:' + roomId + ':uids', uid, next); }, function (inRoom, next) { - plugins.fireHook('filter:messaging.isUserInRoom', {uid: uid, roomId: roomId, inRoom: inRoom}, next); + plugins.fireHook('filter:messaging.isUserInRoom', { uid: uid, roomId: roomId, inRoom: inRoom }, next); }, function (data, next) { next(null, data.inRoom); - } + }, ], callback); }; @@ -124,7 +123,7 @@ module.exports = function (Messaging) { function (next) { async.parallel({ userCount: async.apply(db.sortedSetCard, 'chat:room:' + roomId + ':uids'), - roomData: async.apply(db.getObject, 'chat:room:' + roomId) + roomData: async.apply(db.getObject, 'chat:room:' + roomId), }, next); }, function (results, next) { @@ -132,7 +131,7 @@ module.exports = function (Messaging) { return db.setObjectField('chat:room:' + roomId, 'groupChat', 1, next); } next(); - } + }, ], callback); }; @@ -141,7 +140,7 @@ module.exports = function (Messaging) { function (next) { async.parallel({ isOwner: async.apply(Messaging.isRoomOwner, uid, roomId), - userCount: async.apply(Messaging.getUserCountInRoom, roomId) + userCount: async.apply(Messaging.getUserCountInRoom, roomId), }, next); }, function (results, next) { @@ -152,7 +151,7 @@ module.exports = function (Messaging) { return next(new Error('[[error:cant-remove-last-user]]')); } Messaging.leaveRoom(uids, roomId, next); - } + }, ], callback); }; @@ -169,7 +168,7 @@ module.exports = function (Messaging) { return 'uid:' + uid + ':chat:rooms:unread'; })); db.sortedSetsRemove(keys, roomId, next); - } + }, ], callback); }; @@ -184,7 +183,7 @@ module.exports = function (Messaging) { }, function (uids, next) { user.getUsersFields(uids, ['uid', 'username', 'picture', 'status'], next); - } + }, ], callback); }; @@ -205,7 +204,7 @@ module.exports = function (Messaging) { return next(new Error('[[error:no-privileges]]')); } db.setObjectField('chat:room:' + roomId, 'roomName', newName, next); - } + }, ], callback); }; @@ -215,12 +214,11 @@ module.exports = function (Messaging) { db.isSortedSetMember('chat:room:' + roomId + ':uids', uid, next); }, function (inRoom, next) { - plugins.fireHook('filter:messaging.canReply', {uid: uid, roomId: roomId, inRoom: inRoom, canReply: inRoom}, next); + plugins.fireHook('filter:messaging.canReply', { uid: uid, roomId: roomId, inRoom: inRoom, canReply: inRoom }, next); }, function (data, next) { next(null, data.canReply); - } + }, ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/messaging/unread.js b/src/messaging/unread.js index 91c9a364ac..660eece5ce 100644 --- a/src/messaging/unread.js +++ b/src/messaging/unread.js @@ -6,7 +6,6 @@ var db = require('../database'); var sockets = require('../socket.io'); module.exports = function (Messaging) { - Messaging.getUnreadCount = function (uid, callback) { if (!parseInt(uid, 10)) { return callback(null, 0); @@ -16,7 +15,7 @@ module.exports = function (Messaging) { Messaging.pushUnreadCount = function (uid) { if (!parseInt(uid, 10)) { - return callback(null, 0); + return; } Messaging.getUnreadCount(uid, function (err, unreadCount) { if (err) { @@ -48,8 +47,7 @@ module.exports = function (Messaging) { }); db.sortedSetsAdd(keys, Date.now(), roomId, next); - } + }, ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/meta.js b/src/meta.js index 2333e54d89..6cbccd70a1 100644 --- a/src/meta.js +++ b/src/meta.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -32,7 +32,7 @@ var utils = require('../public/src/utils'); slug = utils.slugify(slug); async.parallel([ async.apply(user.existsBySlug, slug), - async.apply(groups.existsBySlug, slug) + async.apply(groups.existsBySlug, slug), ], function (err, results) { callback(err, results ? results.some(function (result) { return result; }) : false); }); @@ -47,7 +47,7 @@ var utils = require('../public/src/utils'); }; Meta.restart = function () { - pubsub.publish('meta:restart', {hostname: os.hostname()}); + pubsub.publish('meta:restart', { hostname: os.hostname() }); restart(); }; @@ -62,7 +62,7 @@ var utils = require('../public/src/utils'); function restart() { if (process.send) { process.send({ - action: 'restart' + action: 'restart', }); } else { winston.error('[meta.restart] Could not restart, are you sure NodeBB was started with `./nodebb start`?'); diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index a078b89815..31ce06af8c 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -8,14 +8,14 @@ var db = require('../database'); var pubsub = require('../pubsub'); var Blacklist = { - _rules: [] + _rules: [], }; Blacklist.load = function (callback) { callback = callback || function () {}; async.waterfall([ - async.apply(Blacklist.get), - async.apply(Blacklist.validate) + Blacklist.get, + Blacklist.validate, ], function (err, rules) { if (err) { return callback(err); @@ -29,7 +29,7 @@ Blacklist.load = function (callback) { Blacklist._rules = { ipv4: rules.ipv4, ipv6: rules.ipv6, - cidr: rules.cidr + cidr: rules.cidr, }; callback(); @@ -46,7 +46,7 @@ Blacklist.save = function (rules, callback) { function (next) { Blacklist.load(next); pubsub.publish('blacklist:reload'); - } + }, ], callback); }; @@ -107,18 +107,18 @@ Blacklist.validate = function (rules, callback) { if (ip.isV4Format(rule)) { ipv4.push(rule); return true; - } else if (ip.isV6Format(rule)) { + } + if (ip.isV6Format(rule)) { ipv6.push(rule); return true; - } else if (isCidrSubnet.test(rule)) { + } + if (isCidrSubnet.test(rule)) { cidr.push(rule); return true; - } else { - invalid.push(rule); - return false; } - return true; + invalid.push(rule); + return false; }); callback(null, { @@ -127,8 +127,8 @@ Blacklist.validate = function (rules, callback) { ipv6: ipv6, cidr: cidr, valid: rules, - invalid: invalid + invalid: invalid, }); }; -module.exports = Blacklist; \ No newline at end of file +module.exports = Blacklist; diff --git a/src/meta/build.js b/src/meta/build.js index 29cfbc45be..9ba5ec89bf 100644 --- a/src/meta/build.js +++ b/src/meta/build.js @@ -31,7 +31,7 @@ exports.build = function build(targets, callback) { async.series([ async.apply(db.init), async.apply(meta.themes.setupPaths), - async.apply(plugins.prepareForBuild) + async.apply(plugins.prepareForBuild), ], function (err) { if (err) { winston.error('[build] Encountered error preparing for build: ' + err.message); @@ -52,7 +52,7 @@ exports.buildTargets = function (targets, callback) { var step = function (startTime, target, next, err) { if (err) { - winston.error('Build failed: ' + err.message); + winston.error('Build failed: ' + err.stack); process.exit(1); } winston.info('[build] ' + target + ' => Completed in ' + ((Date.now() - startTime) / 1000) + 's'); @@ -74,7 +74,7 @@ exports.buildTargets = function (targets, callback) { meta.js.buildModules, meta.js.linkStatics, async.apply(meta.js.minify, 'nodebb.min.js'), - async.apply(meta.js.minify, 'acp.min.js') + async.apply(meta.js.minify, 'acp.min.js'), ], step.bind(this, startTime, 'js', next)); } else { setImmediate(next); @@ -83,47 +83,47 @@ exports.buildTargets = function (targets, callback) { function (next) { async.eachSeries(targets, function (target, next) { var startTime; - switch(target) { - case 'js': - setImmediate(next); - break; - case 'clientCSS': - winston.info('[build] Building client-side CSS'); - startTime = Date.now(); - meta.css.minify('client', step.bind(this, startTime, target, next)); - break; + switch (target) { + case 'js': + setImmediate(next); + break; + case 'clientCSS': + winston.info('[build] Building client-side CSS'); + startTime = Date.now(); + meta.css.minify('client', step.bind(this, startTime, target, next)); + break; - case 'acpCSS': - winston.info('[build] Building admin control panel CSS'); - startTime = Date.now(); - meta.css.minify('admin', step.bind(this, startTime, target, next)); - break; + case 'acpCSS': + winston.info('[build] Building admin control panel CSS'); + startTime = Date.now(); + meta.css.minify('admin', step.bind(this, startTime, target, next)); + break; - case 'tpl': - winston.info('[build] Building templates'); - startTime = Date.now(); - meta.templates.compile(step.bind(this, startTime, target, next)); - break; + case 'tpl': + winston.info('[build] Building templates'); + startTime = Date.now(); + meta.templates.compile(step.bind(this, startTime, target, next)); + break; - case 'lang': - winston.info('[build] Building language files'); - startTime = Date.now(); - meta.languages.build(step.bind(this, startTime, target, next)); - break; + case 'lang': + winston.info('[build] Building language files'); + startTime = Date.now(); + meta.languages.build(step.bind(this, startTime, target, next)); + break; - case 'sound': - winston.info('[build] Linking sound files'); - startTime = Date.now(); - meta.sounds.build(step.bind(this, startTime, target, next)); - break; + case 'sound': + winston.info('[build] Linking sound files'); + startTime = Date.now(); + meta.sounds.build(step.bind(this, startTime, target, next)); + break; - default: - winston.warn('[build] Unknown build target: \'' + target + '\''); - setImmediate(next); - break; + default: + winston.warn('[build] Unknown build target: \'' + target + '\''); + setImmediate(next); + break; } }, next); - } + }, ], function (err) { if (err) { winston.error('[build] Encountered error during build step: ' + err.message); @@ -147,4 +147,4 @@ exports.buildTargets = function (targets, callback) { } }); }); -}; \ No newline at end of file +}; diff --git a/src/meta/configs.js b/src/meta/configs.js index 907e0ef477..82d8640e4c 100644 --- a/src/meta/configs.js +++ b/src/meta/configs.js @@ -9,7 +9,6 @@ var pubsub = require('../pubsub'); var cacheBuster = require('./cacheBuster'); module.exports = function (Meta) { - Meta.config = {}; Meta.configs = {}; @@ -25,13 +24,13 @@ module.exports = function (Meta) { if (err) { return next(err); } - + config['cache-buster'] = 'v=' + (buster || Date.now()); Meta.config = config; next(); }); - } + }, ], callback); }; @@ -75,7 +74,7 @@ module.exports = function (Meta) { function (next) { updateConfig(data); setImmediate(next); - } + }, ], callback); }; @@ -91,13 +90,13 @@ module.exports = function (Meta) { async.waterfall([ function (next) { less.render(data.customCSS, { - compress: true + compress: true, }, next); }, function (lessObject, next) { data.renderedCustomCSS = lessObject.css; setImmediate(next); - } + }, ], callback); } @@ -133,12 +132,11 @@ module.exports = function (Meta) { } else { setImmediate(next); } - } + }, ], callback); }; Meta.configs.remove = function (field, callback) { db.deleteObjectField('config', field, callback); }; - }; diff --git a/src/meta/css.js b/src/meta/css.js index df613ee39f..33bd0877e0 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -16,7 +16,6 @@ var file = require('../file'); var utils = require('../../public/src/utils'); module.exports = function (Meta) { - Meta.css = {}; var buildImports = { @@ -65,7 +64,7 @@ module.exports = function (Meta) { var paths = [ baseThemePath, path.join(__dirname, '../../node_modules'), - path.join(__dirname, '../../public/vendor/fontawesome/less') + path.join(__dirname, '../../public/vendor/fontawesome/less'), ]; var source = ''; @@ -83,7 +82,7 @@ module.exports = function (Meta) { function (src, next) { source += src; next(); - } + }, ], function (err) { if (err) { return callback(err); @@ -95,8 +94,8 @@ module.exports = function (Meta) { }; function getStyleSource(files, prefix, extension, callback) { - var pluginDirectories = [], - source = ''; + var pluginDirectories = []; + var source = ''; files.forEach(function (styleFile) { if (styleFile.endsWith(extension)) { @@ -141,7 +140,7 @@ module.exports = function (Meta) { function minify(source, paths, target, callback) { callback = callback || function () {}; less.render(source, { - paths: paths + paths: paths, }, function (err, lessOutput) { if (err) { winston.error('[meta/css] Could not minify LESS/CSS: ' + err.message); @@ -151,7 +150,7 @@ module.exports = function (Meta) { postcss(global.env === 'development' ? [autoprefixer] : [ autoprefixer, clean({ - processImportFrom: ['local'] + processImportFrom: ['local'], }), ]).process(lessOutput.css).then(function (result) { result.warnings().forEach(function (warn) { diff --git a/src/meta/dependencies.js b/src/meta/dependencies.js index 3f892c37ab..939f14b674 100644 --- a/src/meta/dependencies.js +++ b/src/meta/dependencies.js @@ -5,7 +5,7 @@ var fs = require('fs'); var async = require('async'); var semver = require('semver'); var winston = require('winston'); -var colors = require('colors'); +require('colors'); var pkg = require('../../package.json'); @@ -21,7 +21,7 @@ module.exports = function (Meta) { async.every(modules, function (module, next) { fs.readFile(path.join(__dirname, '../../node_modules/', module, 'package.json'), { - encoding: 'utf-8' + encoding: 'utf-8', }, function (err, pkgData) { // If a bundled plugin/theme is not present, skip the dep check (#3384) if (err && err.code === 'ENOENT' && (module === 'nodebb-rewards-essentials' || module.startsWith('nodebb-plugin') || module.startsWith('nodebb-theme'))) { @@ -31,7 +31,7 @@ module.exports = function (Meta) { try { pkgData = JSON.parse(pkgData); - } catch(e) { + } catch (e) { process.stdout.write('[' + 'missing'.red + '] ' + module.bold + ' is a required dependency but could not be found\n'); depsMissing = true; return next(true); @@ -47,7 +47,7 @@ module.exports = function (Meta) { next(true); } }); - }, function (ok) { + }, function () { if (depsMissing) { callback(new Error('dependencies-missing')); } else if (depsOutdated) { diff --git a/src/meta/errors.js b/src/meta/errors.js index 58e381e270..fb169764ba 100644 --- a/src/meta/errors.js +++ b/src/meta/errors.js @@ -1,12 +1,12 @@ 'use strict'; +var async = require('async'); var validator = require('validator'); var db = require('../database'); var analytics = require('../analytics'); module.exports = function (Meta) { - Meta.errors = {}; Meta.errors.log404 = function (route, callback) { @@ -17,18 +17,19 @@ module.exports = function (Meta) { }; Meta.errors.get = function (escape, callback) { - db.getSortedSetRevRangeWithScores('errors:404', 0, -1, function (err, data) { - if (err) { - return callback(err); - } + async.waterfall([ + function (next) { + db.getSortedSetRevRangeWithScores('errors:404', 0, -1, next); + }, + function (data, next) { + data = data.map(function (nfObject) { + nfObject.value = escape ? validator.escape(String(nfObject.value || '')) : nfObject.value; + return nfObject; + }); - data = data.map(function (nfObject) { - nfObject.value = escape ? validator.escape(String(nfObject.value || '')) : nfObject.value; - return nfObject; - }); - - callback(null, data); - }); + next(null, data); + }, + ], callback); }; Meta.errors.clear = function (callback) { diff --git a/src/meta/js.js b/src/meta/js.js index 90f757361a..72e41c578f 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -16,7 +16,6 @@ var utils = require('../../public/src/utils'); var minifierPath = path.join(__dirname, 'minifier.js'); module.exports = function (Meta) { - Meta.js = { target: {}, scripts: { @@ -43,7 +42,7 @@ module.exports = function (Meta) { 'public/src/ajaxify.js', 'public/src/overrides.js', 'public/src/widgets.js', - "./node_modules/promise-polyfill/promise.js" + './node_modules/promise-polyfill/promise.js', ], // files listed below are only available client-side, or are bundled in to reduce # of network requests on cold load @@ -60,6 +59,7 @@ module.exports = function (Meta) { 'public/src/client/topic/fork.js', 'public/src/client/topic/move.js', 'public/src/client/topic/posts.js', + 'public/src/client/topic/images.js', 'public/src/client/topic/postTools.js', 'public/src/client/topic/threadTools.js', 'public/src/client/categories.js', @@ -79,18 +79,18 @@ module.exports = function (Meta) { 'public/src/modules/taskbar.js', 'public/src/modules/helpers.js', 'public/src/modules/sounds.js', - 'public/src/modules/string.js' + 'public/src/modules/string.js', ], // modules listed below are built (/src/modules) so they can be defined anonymously modules: { - "Chart.js": './node_modules/chart.js/dist/Chart.min.js', - "mousetrap.js": './node_modules/mousetrap/mousetrap.min.js', - "jqueryui.js": 'public/vendor/jquery/js/jquery-ui.js', - "buzz.js": 'public/vendor/buzz/buzz.js', - "cropper.js": './node_modules/cropperjs/dist/cropper.min.js' - } - } + 'Chart.js': './node_modules/chart.js/dist/Chart.min.js', + 'mousetrap.js': './node_modules/mousetrap/mousetrap.min.js', + 'jqueryui.js': 'public/vendor/jquery/js/jquery-ui.js', + 'buzz.js': 'public/vendor/buzz/buzz.js', + 'cropper.js': './node_modules/cropperjs/dist/cropper.min.js', + }, + }, }; function minifyModules(modules, callback) { @@ -108,6 +108,12 @@ module.exports = function (Meta) { if (err) { return cb(err); } + + if (filePath.endsWith('.min.js')) { + minified = { code: buffer.toString() }; + return cb(); + } + try { minified = uglifyjs.minify(buffer.toString(), { fromString: true, @@ -119,7 +125,7 @@ module.exports = function (Meta) { cb(); }); - } + }, ], function (err) { if (err) { return next(err); @@ -128,7 +134,7 @@ module.exports = function (Meta) { fs.writeFile(destPath, minified.code, next); }); }, callback); - }; + } function linkModules(callback) { var modules = Meta.js.scripts.modules; @@ -145,7 +151,7 @@ module.exports = function (Meta) { file.link(filePath, destPath, next); }); }, callback); - }; + } var moduleDirs = ['modules', 'admin', 'client']; @@ -167,12 +173,16 @@ module.exports = function (Meta) { return next(err); } - modules = modules.concat(files.map(function (filePath) { + var mods = files.filter(function (filePath) { + return path.extname(filePath) === '.js'; + }).map(function (filePath) { return { filePath: filePath, destPath: path.join(__dirname, '../../build/public/src', path.relative(path.dirname(dir), filePath)), }; - })); + }); + + modules = modules.concat(mods); next(); }); @@ -204,7 +214,7 @@ module.exports = function (Meta) { }, function (modules, next) { minifyModules(modules, next); - } + }, ], callback); }; @@ -232,7 +242,8 @@ module.exports = function (Meta) { winston.verbose('[meta/js] Minifying ' + target); var forkProcessParams = setupDebugging(); - var minifier = Meta.js.minifierProc = fork(minifierPath, [], forkProcessParams); + var minifier = fork(minifierPath, [], forkProcessParams); + Meta.js.minifierProc = minifier; Meta.js.target[target] = {}; @@ -243,12 +254,12 @@ module.exports = function (Meta) { minifier.send({ action: 'js', minify: global.env !== 'development', - scripts: Meta.js.target[target].scripts + scripts: Meta.js.target[target].scripts, }); }); minifier.on('message', function (message) { - switch(message.type) { + switch (message.type) { case 'end': Meta.js.target[target].cache = message.minified; Meta.js.target[target].map = message.sourceMap; @@ -324,17 +335,17 @@ module.exports = function (Meta) { * Check if the parent process is running with the debug option --debug (or --debug-brk) */ var forkProcessParams = {}; - if(global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { + if (global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { /** * use the line below if you want to debug minifier.js script too (or even --debug-brk option, but * you'll have to setup your debugger and connect to the forked process) */ - //forkProcessParams = {execArgv: ['--debug=' + (global.process.debugPort + 1), '--nolazy']}; + // forkProcessParams = {execArgv: ['--debug=' + (global.process.debugPort + 1), '--nolazy']}; /** * otherwise, just clean up --debug/--debug-brk options which are set up by default from the parent one */ - forkProcessParams = {execArgv: []}; + forkProcessParams = { execArgv: [] }; } return forkProcessParams; diff --git a/src/meta/languages.js b/src/meta/languages.js index b7c79db5ba..67bd9fabd5 100644 --- a/src/meta/languages.js +++ b/src/meta/languages.js @@ -38,12 +38,13 @@ function getTranslationTree(callback) { // generate list of languages and namespaces function (plugins, next) { - var languages = [], namespaces = []; + var languages = []; + var namespaces = []; // pull languages and namespaces from paths function extrude(languageDir, paths) { paths.forEach(function (p) { - var rel = p.split(languageDir)[1].split(/[\/\\]/).slice(1); + var rel = p.split(languageDir)[1].split(/[/\\]/).slice(1); var language = rel.shift().replace('_', '-').replace('@', '-x-'); var namespace = rel.join('/').replace(/\.json$/, ''); diff --git a/src/meta/logs.js b/src/meta/logs.js index 32f6d7a141..e85c0a5e11 100644 --- a/src/meta/logs.js +++ b/src/meta/logs.js @@ -7,12 +7,12 @@ var winston = require('winston'); module.exports = function (Meta) { Meta.logs = { - path: path.join(nconf.get('base_dir'), 'logs', 'output.log') + path: path.join(nconf.get('base_dir'), 'logs', 'output.log'), }; Meta.logs.get = function (callback) { fs.readFile(Meta.logs.path, { - encoding: 'utf-8' + encoding: 'utf-8', }, function (err, logs) { if (err) { winston.error('[meta/logs] Could not retrieve logs: ' + err.message); @@ -25,5 +25,4 @@ module.exports = function (Meta) { Meta.logs.clear = function (callback) { fs.truncate(Meta.logs.path, 0, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/meta/minifier.js b/src/meta/minifier.js index 5c47bc3e4e..6152112c59 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var uglifyjs = require('uglify-js'); var async = require('async'); @@ -6,12 +6,11 @@ var fs = require('fs'); var file = require('../file'); var Minifier = { - js: {} + js: {}, }; /* Javascript */ Minifier.js.minify = function (scripts, minify, callback) { - scripts = scripts.filter(function (file) { return file && file.endsWith('.js'); }); @@ -33,13 +32,13 @@ Minifier.js.minify = function (scripts, minify, callback) { }; process.on('message', function (payload) { - switch(payload.action) { + switch (payload.action) { case 'js': - Minifier.js.minify(payload.scripts, payload.minify, function (minified/*, sourceMap*/) { + Minifier.js.minify(payload.scripts, payload.minify, function (minified/* , sourceMap*/) { process.send({ type: 'end', // sourceMap: sourceMap, - minified: minified + minified: minified, }); }); break; @@ -51,15 +50,15 @@ function minifyScripts(scripts, callback) { // Follow along here: https://github.com/mishoo/UglifyJS2/issues/700 try { var minified = uglifyjs.minify(scripts, { - // outSourceMap: "nodebb.min.js.map", - compress: false - }); + // outSourceMap: "nodebb.min.js.map", + compress: false, + }); - callback(minified.code/*, minified.map*/); - } catch(err) { + callback(minified.code/* , minified.map*/); + } catch (err) { process.send({ type: 'error', - message: err.message + message: err.message, }); } } @@ -69,7 +68,7 @@ function concatenateScripts(scripts, callback) { if (err) { process.send({ type: 'error', - message: err.message + message: err.message, }); return; } @@ -78,4 +77,4 @@ function concatenateScripts(scripts, callback) { callback(scripts); }); -} \ No newline at end of file +} diff --git a/src/meta/settings.js b/src/meta/settings.js index 785d22961f..a1d13b248d 100644 --- a/src/meta/settings.js +++ b/src/meta/settings.js @@ -6,7 +6,6 @@ var db = require('../database'); var plugins = require('../plugins'); module.exports = function (Meta) { - Meta.settings = {}; Meta.settings.get = function (hash, callback) { @@ -27,12 +26,12 @@ module.exports = function (Meta) { function (next) { plugins.fireHook('action:settings.set', { plugin: hash, - settings: values + settings: values, }); Meta.reloadRequired = true; next(); - } + }, ], callback); }; @@ -59,7 +58,7 @@ module.exports = function (Meta) { } else { next(); } - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/meta/sounds.js b/src/meta/sounds.js index 00bcbc2410..3de45b388c 100644 --- a/src/meta/sounds.js +++ b/src/meta/sounds.js @@ -9,7 +9,6 @@ var async = require('async'); var file = require('../file'); var plugins = require('../plugins'); var user = require('../user'); -var db = require('../database'); var soundsPath = path.join(__dirname, '../../build/public/sounds'); var uploadsPath = path.join(__dirname, '../../public/uploads/sounds'); @@ -99,11 +98,11 @@ module.exports = function (Meta) { Meta.sounds.getUserSoundMap = function getUserSoundMap(uid, callback) { async.parallel({ defaultMapping: function (next) { - db.getObject('settings:sounds', next); + Meta.configs.getFields(keys, next); }, userSettings: function (next) { user.getSettings(uid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -120,9 +119,9 @@ module.exports = function (Meta) { keys.forEach(function (key) { if (userSettings[key] || userSettings[key] === '') { - soundMapping[key] = userSettings[key] || null; + soundMapping[key] = userSettings[key] || ''; } else { - soundMapping[key] = defaultMapping[key] || null; + soundMapping[key] = defaultMapping[key] || ''; } }); diff --git a/src/meta/tags.js b/src/meta/tags.js index 0cd680a70a..5b1097d427 100644 --- a/src/meta/tags.js +++ b/src/meta/tags.js @@ -14,30 +14,30 @@ module.exports = function (Meta) { tags: function (next) { var defaultTags = [{ name: 'viewport', - content: 'width=device-width, initial-scale=1.0' + content: 'width=device-width, initial-scale=1.0', }, { name: 'content-type', content: 'text/html; charset=UTF-8', - noEscape: true + noEscape: true, }, { name: 'apple-mobile-web-app-capable', - content: 'yes' + content: 'yes', }, { name: 'mobile-web-app-capable', - content: 'yes' + content: 'yes', }, { property: 'og:site_name', - content: Meta.config.title || 'NodeBB' + content: Meta.config.title || 'NodeBB', }, { name: 'msapplication-badge', content: 'frequency=30; polling-uri=' + nconf.get('url') + '/sitemap.xml', - noEscape: true + noEscape: true, }]; if (Meta.config.keywords) { defaultTags.push({ name: 'keywords', - content: Meta.config.keywords + content: Meta.config.keywords, }); } @@ -45,7 +45,7 @@ module.exports = function (Meta) { defaultTags.push({ name: 'msapplication-square150x150logo', content: Meta.config['brand:logo'], - noEscape: true + noEscape: true, }); } @@ -53,47 +53,55 @@ module.exports = function (Meta) { }, links: function (next) { var defaultLinks = [{ - rel: "icon", - type: "image/x-icon", - href: nconf.get('relative_path') + '/favicon.ico' + (Meta.config['cache-buster'] ? '?' + Meta.config['cache-buster'] : '') + rel: 'icon', + type: 'image/x-icon', + href: nconf.get('relative_path') + '/favicon.ico' + (Meta.config['cache-buster'] ? '?' + Meta.config['cache-buster'] : ''), }, { - rel: "manifest", - href: nconf.get('relative_path') + '/manifest.json' + rel: 'manifest', + href: nconf.get('relative_path') + '/manifest.json', }]; + if (plugins.hasListeners('filter:search.query')) { + defaultLinks.push({ + rel: 'search', + type: 'application/opensearchdescription+xml', + href: nconf.get('relative_path') + '/osd.xml', + }); + } + // Touch icons for mobile-devices if (Meta.config['brand:touchIcon']) { defaultLinks.push({ rel: 'apple-touch-icon', - href: nconf.get('relative_path') + '/apple-touch-icon' + href: nconf.get('relative_path') + '/apple-touch-icon', }, { rel: 'icon', sizes: '36x36', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-36.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-36.png', }, { rel: 'icon', sizes: '48x48', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-48.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-48.png', }, { rel: 'icon', sizes: '72x72', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-72.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-72.png', }, { rel: 'icon', sizes: '96x96', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-96.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-96.png', }, { rel: 'icon', sizes: '144x144', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-144.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-144.png', }, { rel: 'icon', sizes: '192x192', - href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-192.png' + href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-192.png', }); } plugins.fireHook('filter:meta.getLinkTags', defaultLinks, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -118,7 +126,7 @@ module.exports = function (Meta) { callback(null, { meta: meta, - link: link + link: link, }); }); }; @@ -131,10 +139,10 @@ module.exports = function (Meta) { } }); - if (!hasDescription) { + if (!hasDescription && Meta.config.description) { meta.push({ name: 'description', - content: validator.escape(String(Meta.config.description || '')) + content: validator.escape(String(Meta.config.description)), }); } } diff --git a/src/meta/templates.js b/src/meta/templates.js index fd5c1f71e1..4c2a8b1fb9 100644 --- a/src/meta/templates.js +++ b/src/meta/templates.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var mkdirp = require('mkdirp'); var rimraf = require('rimraf'); @@ -21,8 +21,9 @@ Templates.compile = function (callback) { function getBaseTemplates(theme) { - var baseTemplatesPaths = [], - baseThemePath, baseThemeConfig; + var baseTemplatesPaths = []; + var baseThemePath; + var baseThemeConfig; while (theme) { baseThemePath = path.join(nconf.get('themes_path'), theme); @@ -51,7 +52,7 @@ function preparePaths(baseTemplatesPaths, callback) { }, function (next) { plugins.getTemplates(next); - } + }, ], function (err, pluginTemplates) { if (err) { return callback(err); @@ -69,18 +70,18 @@ function preparePaths(baseTemplatesPaths, callback) { paths = paths.map(function (tpl) { return { base: baseTemplatePath, - path: tpl.replace(baseTemplatePath, '') + path: tpl.replace(baseTemplatePath, ''), }; }); next(err, paths); }); }, next); - } + }, }, function (err, data) { - var baseThemes = data.baseThemes, - coreTpls = data.coreTpls, - paths = {}; + var baseThemes = data.baseThemes; + var coreTpls = data.coreTpls; + var paths = {}; coreTpls.forEach(function (el, i) { paths[coreTpls[i].replace(coreTemplatesPath, '')] = coreTpls[i]; @@ -104,9 +105,9 @@ function preparePaths(baseTemplatesPaths, callback) { } function compile(callback) { - var themeConfig = require(nconf.get('theme_config')), - baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')], - viewsPath = nconf.get('views_dir'); + var themeConfig = require(nconf.get('theme_config')); + var baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')]; + var viewsPath = nconf.get('views_dir'); preparePaths(baseTemplatesPaths, function (err, paths) { @@ -115,19 +116,20 @@ function compile(callback) { } async.each(Object.keys(paths), function (relativePath, next) { - var file = fs.readFileSync(paths[relativePath]).toString(), - matches = null, - regex = /[ \t]*[ \t]*/; + var file = fs.readFileSync(paths[relativePath]).toString(); + var regex = /[ \t]*[ \t]*/; + var matches = file.match(regex); - while((matches = file.match(regex)) !== null) { - var partial = "/" + matches[1]; + while (matches !== null) { + var partial = '/' + matches[1]; if (paths[partial] && relativePath !== partial) { file = file.replace(regex, fs.readFileSync(paths[partial]).toString()); } else { winston.warn('[meta/templates] Partial not loaded: ' + matches[1]); - file = file.replace(regex, ""); + file = file.replace(regex, ''); } + matches = file.match(regex); } mkdirp.sync(path.join(viewsPath, relativePath.split('/').slice(0, -1).join('/'))); @@ -145,4 +147,4 @@ function compile(callback) { }); } -module.exports = Templates; \ No newline at end of file +module.exports = Templates; diff --git a/src/meta/themes.js b/src/meta/themes.js index e19dcdbf4c..8853c9a086 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -56,7 +56,6 @@ module.exports = function (Meta) { next(null, null); } }); - }, function (err, themes) { if (err) { return callback(err); @@ -75,17 +74,17 @@ module.exports = function (Meta) { 'theme:id': data.id, 'theme:staticDir': '', 'theme:templates': '', - 'theme:src': '' + 'theme:src': '', }; - switch(data.type) { + switch (data.type) { case 'local': async.waterfall([ async.apply(Meta.configs.get, 'theme:id'), function (current, next) { async.series([ async.apply(db.sortedSetRemove, 'plugins:active', current), - async.apply(db.sortedSetAdd, 'plugins:active', 0, data.id) + async.apply(db.sortedSetAdd, 'plugins:active', 0, data.id), ], function (err) { next(err); }); @@ -105,18 +104,21 @@ module.exports = function (Meta) { themeData['theme:templates'] = config.templates ? config.templates : ''; themeData['theme:src'] = ''; - db.setObject('config', themeData, next); + Meta.configs.setMultiple(themeData, next); // Re-set the themes path (for when NodeBB is reloaded) Meta.themes.setPath(config); - } + }, ], callback); Meta.reloadRequired = true; break; case 'bootswatch': - Meta.configs.set('theme:src', data.src, callback); + Meta.configs.setMultiple({ + 'theme:src': data.src, + bootswatchSkin: data.id.toLowerCase(), + }, callback); break; } }; @@ -126,7 +128,7 @@ module.exports = function (Meta) { themesData: Meta.themes.get, currentThemeId: function (next) { db.getObjectField('config', 'theme:id', next); - } + }, }, function (err, data) { if (err) { return callback(err); @@ -135,8 +137,8 @@ module.exports = function (Meta) { var themeId = data.currentThemeId || 'nodebb-theme-persona'; var themeObj = data.themesData.filter(function (themeObj) { - return themeObj.id === themeId; - })[0]; + return themeObj.id === themeId; + })[0]; if (process.env.NODE_ENV === 'development') { winston.info('[themes] Using theme ' + themeId); @@ -153,8 +155,8 @@ module.exports = function (Meta) { Meta.themes.setPath = function (themeObj) { // Theme's templates path - var themePath = nconf.get('base_templates_path'), - fallback = path.join(nconf.get('themes_path'), themeObj.id, 'templates'); + var themePath = nconf.get('base_templates_path'); + var fallback = path.join(nconf.get('themes_path'), themeObj.id, 'templates'); if (themeObj.templates) { themePath = path.join(nconf.get('themes_path'), themeObj.id, themeObj.templates); @@ -165,4 +167,4 @@ module.exports = function (Meta) { nconf.set('theme_templates_path', themePath); nconf.set('theme_config', path.join(nconf.get('themes_path'), themeObj.id, 'theme.json')); }; -}; \ No newline at end of file +}; diff --git a/src/middleware/admin.js b/src/middleware/admin.js index 9d4b43bf25..3e36b74db9 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -8,7 +8,7 @@ var plugins = require('../plugins'); var controllers = { api: require('../controllers/api'), - helpers: require('../controllers/helpers') + helpers: require('../controllers/helpers'), }; module.exports = function (middleware) { @@ -44,8 +44,8 @@ module.exports = function (middleware) { middleware.admin.renderHeader = function (req, res, data, next) { var custom_header = { - 'plugins': [], - 'authentication': [] + plugins: [], + authentication: [], }; user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'email:confirmed'], function (err, userData) { @@ -64,7 +64,7 @@ module.exports = function (middleware) { } var arr = []; scripts.forEach(function (script) { - arr.push({src: script}); + arr.push({ src: script }); }); next(null, arr); @@ -78,7 +78,7 @@ module.exports = function (middleware) { }, configs: function (next) { meta.configs.list(next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -102,12 +102,12 @@ module.exports = function (middleware) { authentication: results.custom_header.authentication, scripts: results.scripts, 'cache-buster': meta.config['cache-buster'] || '', - env: process.env.NODE_ENV ? true : false, + env: !!process.env.NODE_ENV, title: (acpPath || 'Dashboard') + ' | NodeBB Admin Control Panel', - bodyClass: data.bodyClass + bodyClass: data.bodyClass, }; - templateValues.template = {name: res.locals.template}; + templateValues.template = { name: res.locals.template }; templateValues.template[res.locals.template] = true; req.app.render('admin/header', templateValues, next); diff --git a/src/middleware/header.js b/src/middleware/header.js index 0c33e621e5..70c0755def 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -11,11 +11,10 @@ var navigation = require('../navigation'); var controllers = { api: require('../controllers/api'), - helpers: require('../controllers/helpers') + helpers: require('../controllers/helpers'), }; module.exports = function (middleware) { - middleware.buildHeader = function (req, res, next) { res.locals.renderHeader = true; res.locals.isAPI = false; @@ -29,21 +28,20 @@ module.exports = function (middleware) { controllers.api.getConfig(req, res, next); }, plugins: function (next) { - plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next); - } + plugins.fireHook('filter:middleware.buildHeader', { req: req, locals: res.locals }, next); + }, }, next); }, function (results, next) { res.locals.config = results.config; next(); - } + }, ], next); }; middleware.renderHeader = function (req, res, data, callback) { var registrationType = meta.config.registrationType || 'normal'; var templateValues = { - bootswatchCSS: meta.config['theme:src'], title: meta.config.title || '', description: meta.config.description || '', 'cache-buster': meta.config['cache-buster'] || '', @@ -55,10 +53,11 @@ module.exports = function (middleware) { searchEnabled: plugins.hasListeners('filter:search.query'), config: res.locals.config, relative_path: nconf.get('relative_path'), - bodyClass: data.bodyClass + bodyClass: data.bodyClass, }; templateValues.configJSON = JSON.stringify(res.locals.config); + async.waterfall([ function (next) { async.parallel({ @@ -83,7 +82,7 @@ module.exports = function (middleware) { picture: meta.config.defaultAvatar, status: 'offline', reputation: 0, - 'email:confirmed': false + 'email:confirmed': 0, }; if (req.uid) { user.getUserFields(req.uid, Object.keys(userData), next); @@ -100,7 +99,7 @@ module.exports = function (middleware) { navigation: async.apply(navigation.get), tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags), banned: async.apply(user.isBanned, req.uid), - banReason: async.apply(user.getBannedReason, req.uid) + banReason: async.apply(user.getBannedReason, req.uid), }, next); }, function (results, next) { @@ -117,9 +116,7 @@ module.exports = function (middleware) { results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1; results.user.isEmailConfirmSent = !!results.isEmailConfirmSent; - if (res.locals.config && parseInt(meta.config.disableCustomUserSkins, 10) !== 1 && res.locals.config.bootswatchSkin !== 'default') { - templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + res.locals.config.bootswatchSkin + '/bootstrap.min.css'; - } + setBootswatchCSS(templateValues, res.locals.config); templateValues.browserTitle = controllers.helpers.buildTitle(data.title); templateValues.navigation = results.navigation; @@ -139,11 +136,11 @@ module.exports = function (middleware) { templateValues.privateUserInfo = parseInt(meta.config.privateUserInfo, 10) === 1; templateValues.privateTagListing = parseInt(meta.config.privateTagListing, 10) === 1; - templateValues.template = {name: res.locals.template}; + templateValues.template = { name: res.locals.template }; templateValues.template[res.locals.template] = true; templateValues.scripts = results.scripts.map(function (script) { - return {src: script}; + return { src: script }; }); if (req.route && req.route.path === '/') { @@ -151,14 +148,14 @@ module.exports = function (middleware) { } plugins.fireHook('filter:middleware.renderHeader', { - req: req, + req: req, res: res, - templateValues: templateValues - }, next); + templateValues: templateValues, + }, next); }, function (data, next) { req.app.render('header', data.templateValues, next); - } + }, ], callback); }; @@ -168,12 +165,12 @@ module.exports = function (middleware) { plugins.fireHook('filter:middleware.renderFooter', { req: req, res: res, - templateValues: data, + templateValues: data, }, next); }, function (data, next) { req.app.render('footer', data.templateValues, next); - } + }, ], callback); }; @@ -192,7 +189,20 @@ module.exports = function (middleware) { return title; } + function setBootswatchCSS(obj, config) { + if (config && config.bootswatchSkin !== 'noskin') { + var skinToUse = ''; + + if (parseInt(meta.config.disableCustomUserSkins, 10) !== 1) { + skinToUse = config.bootswatchSkin; + } else if (meta.config.bootswatchSkin) { + skinToUse = meta.config.bootswatchSkin; + } + + if (skinToUse) { + obj.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + skinToUse + '/bootstrap.min.css'; + } + } + } }; - - diff --git a/src/middleware/headers.js b/src/middleware/headers.js index 66f0603b0d..ae63b19124 100644 --- a/src/middleware/headers.js +++ b/src/middleware/headers.js @@ -3,14 +3,13 @@ var meta = require('../meta'); module.exports = function (middleware) { - middleware.addHeaders = function (req, res, next) { var headers = { 'X-Powered-By': encodeURI(meta.config['powered-by'] || 'NodeBB'), 'X-Frame-Options': meta.config['allow-from-uri'] ? 'ALLOW-FROM ' + encodeURI(meta.config['allow-from-uri']) : 'SAMEORIGIN', 'Access-Control-Allow-Origin': encodeURI(meta.config['access-control-allow-origin'] || 'null'), 'Access-Control-Allow-Methods': encodeURI(meta.config['access-control-allow-methods'] || ''), - 'Access-Control-Allow-Headers': encodeURI(meta.config['access-control-allow-headers'] || '') + 'Access-Control-Allow-Headers': encodeURI(meta.config['access-control-allow-headers'] || ''), }; for (var key in headers) { @@ -24,17 +23,14 @@ module.exports = function (middleware) { middleware.addExpiresHeaders = function (req, res, next) { if (req.app.enabled('cache')) { - res.setHeader("Cache-Control", "public, max-age=5184000"); - res.setHeader("Expires", new Date(Date.now() + 5184000000).toUTCString()); + res.setHeader('Cache-Control', 'public, max-age=5184000'); + res.setHeader('Expires', new Date(Date.now() + 5184000000).toUTCString()); } else { - res.setHeader("Cache-Control", "public, max-age=0"); - res.setHeader("Expires", new Date().toUTCString()); + res.setHeader('Cache-Control', 'public, max-age=0'); + res.setHeader('Expires', new Date().toUTCString()); } next(); }; - }; - - diff --git a/src/middleware/index.js b/src/middleware/index.js index 82a7fd12cb..faf2ad832d 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var fs = require('fs'); @@ -10,7 +10,6 @@ var ensureLoggedIn = require('connect-ensure-login'); var toobusy = require('toobusy-js'); var plugins = require('../plugins'); -var languages = require('../languages'); var meta = require('../meta'); var user = require('../user'); var groups = require('../groups'); @@ -19,7 +18,7 @@ var analytics = require('../analytics'); var controllers = { api: require('./../controllers/api'), - helpers: require('../controllers/helpers') + helpers: require('../controllers/helpers'), }; var middleware = {}; @@ -42,7 +41,7 @@ middleware.authenticate = function (req, res, next) { return plugins.fireHook('action:middleware.authenticate', { req: req, res: res, - next: next + next: next, }); } @@ -54,33 +53,34 @@ middleware.ensureSelfOrGlobalPrivilege = function (req, res, next) { The "self" part of this middleware hinges on you having used middleware.exposeUid prior to invoking this middleware. */ - if (req.user) { - if (req.user.uid === res.locals.uid) { - return next(); - } - - user.isAdminOrGlobalMod(req.uid, function (err, ok) { - if (err) { - return next(err); - } else if (ok) { - return next(); - } else { - controllers.helpers.notAllowed(req, res); + async.waterfall([ + function (next) { + if (!req.uid) { + return setImmediate(next, null, false); } - }); - } else { - controllers.helpers.notAllowed(req, res); - } + + if (req.uid === parseInt(res.locals.uid, 10)) { + return setImmediate(next, null, true); + } + user.isAdminOrGlobalMod(req.uid, next); + }, + function (isAdminOrGlobalMod, next) { + if (!isAdminOrGlobalMod) { + return controllers.helpers.notAllowed(req, res); + } + next(); + }, + ], next); }; middleware.pageView = function (req, res, next) { analytics.pageView({ ip: req.ip, path: req.path, - uid: req.uid + uid: req.uid, }); - plugins.fireHook('action:middleware.pageView', {req: req}); + plugins.fireHook('action:middleware.pageView', { req: req }); if (req.user) { user.updateLastOnlineTime(req.user.uid); @@ -121,13 +121,10 @@ middleware.prepareAPI = function (req, res, next) { middleware.routeTouchIcon = function (req, res) { if (meta.config['brand:touchIcon'] && validator.isURL(meta.config['brand:touchIcon'])) { return res.redirect(meta.config['brand:touchIcon']); - } else { - var touchIconPath = meta.config['brand:touchIcon'] || 'logo.png'; - touchIconPath = path.join(nconf.get('base_dir'), 'public', touchIconPath.replace(/assets\/uploads/, 'uploads')); - return res.sendFile(touchIconPath, { - maxAge: req.app.enabled('cache') ? 5184000000 : 0 - }); } + return res.sendFile(path.join(__dirname, '../../public', meta.config['brand:touchIcon'] || '/logo.png'), { + maxAge: req.app.enabled('cache') ? 5184000000 : 0, + }); }; middleware.privateTagListing = function (req, res, next) { @@ -185,24 +182,24 @@ middleware.applyBlacklist = function (req, res, next) { }); }; -middleware.processTimeagoLocales = function (req, res, next) { - var fallback = req.path.indexOf('-short') === -1 ? 'jquery.timeago.en.js' : 'jquery.timeago.en-short.js', - localPath = path.join(__dirname, '../../public/vendor/jquery/timeago/locales', req.path), - exists; +middleware.processTimeagoLocales = function (req, res) { + var fallback = req.path.indexOf('-short') === -1 ? 'jquery.timeago.en.js' : 'jquery.timeago.en-short.js'; + var localPath = path.join(__dirname, '../../public/vendor/jquery/timeago/locales', req.path); + var exists; try { exists = fs.accessSync(localPath, fs.F_OK | fs.R_OK); - } catch(e) { + } catch (e) { exists = false; } if (exists) { res.status(200).sendFile(localPath, { - maxAge: req.app.enabled('cache') ? 5184000000 : 0 + maxAge: req.app.enabled('cache') ? 5184000000 : 0, }); } else { res.status(200).sendFile(path.join(__dirname, '../../public/vendor/jquery/timeago/locales', fallback), { - maxAge: req.app.enabled('cache') ? 5184000000 : 0 + maxAge: req.app.enabled('cache') ? 5184000000 : 0, }); } }; diff --git a/src/middleware/maintenance.js b/src/middleware/maintenance.js index 3193e820fa..4f4cb03982 100644 --- a/src/middleware/maintenance.js +++ b/src/middleware/maintenance.js @@ -5,7 +5,6 @@ var meta = require('../meta'); var user = require('../user'); module.exports = function (middleware) { - middleware.maintenanceMode = function (req, res, next) { if (parseInt(meta.config.maintenanceMode, 10) !== 1) { return next(); @@ -24,7 +23,7 @@ module.exports = function (middleware) { res.status(503); var data = { site_title: meta.config.title || 'NodeBB', - message: meta.config.maintenanceModeMessage + message: meta.config.maintenanceModeMessage, }; if (res.locals.isAPI) { @@ -36,5 +35,4 @@ module.exports = function (middleware) { }); }); }; - -}; \ No newline at end of file +}; diff --git a/src/middleware/ratelimit.js b/src/middleware/ratelimit.js index f02bf74c3e..504cb0acd7 100644 --- a/src/middleware/ratelimit.js +++ b/src/middleware/ratelimit.js @@ -1,6 +1,5 @@ - - 'use strict'; + var winston = require('winston'); var ratelimit = module.exports; @@ -13,7 +12,7 @@ ratelimit.isFlooding = function (socket) { socket.elapsedTime = socket.elapsedTime || 0; socket.lastCallTime = socket.lastCallTime || Date.now(); - ++socket.callsPerSecond; + socket.callsPerSecond += 1; var now = Date.now(); socket.elapsedTime += now - socket.lastCallTime; diff --git a/src/middleware/render.js b/src/middleware/render.js index ecd0ce8a5d..88e9879887 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -9,7 +9,6 @@ var plugins = require('../plugins'); var translator = require('../../public/src/modules/translator'); module.exports = function (middleware) { - middleware.processRender = function (req, res, next) { // res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687 var render = res.render; @@ -24,11 +23,11 @@ module.exports = function (middleware) { }; options = options || {}; - if ('function' === typeof options) { + if (typeof options === 'function') { fn = options; options = {}; } - if ('function' !== typeof fn) { + if (typeof fn !== 'function') { fn = defaultFn; } @@ -37,15 +36,15 @@ module.exports = function (middleware) { function (next) { options.loggedIn = !!req.uid; options.relative_path = nconf.get('relative_path'); - options.template = {name: template}; + options.template = { name: template }; options.template[template] = true; options.url = (req.baseUrl + req.path).replace(/^\/api/, ''); options.bodyClass = buildBodyClass(req); - plugins.fireHook('filter:' + template + '.build', {req: req, res: res, templateData: options}, next); + plugins.fireHook('filter:' + template + '.build', { req: req, res: res, templateData: options }, next); }, function (data, next) { - plugins.fireHook('filter:middleware.render', {req: res, res: res, templateData: data.templateData}, next); + plugins.fireHook('filter:middleware.render', { req: res, res: res, templateData: data.templateData }, next); }, function (data, next) { options = data.templateData; @@ -72,7 +71,7 @@ module.exports = function (middleware) { }, footer: function (next) { renderHeaderFooter('renderFooter', req, res, options, next); - } + }, }, next); }, function (results, next) { @@ -89,7 +88,7 @@ module.exports = function (middleware) { return ''; }); next(null, translated); - } + }, ], fn); }; @@ -107,7 +106,7 @@ module.exports = function (middleware) { } function translate(str, req, res, next) { - var language = res.locals.config && res.locals.config.userLang || 'en-GB'; + var language = (res.locals.config && res.locals.config.userLang) || 'en-GB'; language = req.query.lang ? validator.escape(String(req.query.lang)) : language; translator.translate(str, language, function (translated) { next(null, translator.unescape(translated)); @@ -124,10 +123,9 @@ module.exports = function (middleware) { winston.error(err.message); p = ''; } - + p = validator.escape(String(p)); parts[index] = index ? parts[0] + '-' + p : 'page-' + (p || 'home'); }); return parts.join(' '); } - }; diff --git a/src/middleware/user.js b/src/middleware/user.js index c2c3bd9dd6..85b5d6e808 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -1,18 +1,17 @@ 'use strict'; var async = require('async'); -var nconf = require('nconf'); +var nconf = require('nconf'); var meta = require('../meta'); var user = require('../user'); var privileges = require('../privileges'); var controllers = { - helpers: require('../controllers/helpers') + helpers: require('../controllers/helpers'), }; module.exports = function (middleware) { - middleware.checkGlobalPrivacySettings = function (req, res, next) { if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) { return middleware.authenticate(req, res, next); @@ -44,7 +43,7 @@ module.exports = function (middleware) { } else { next(null, false); } - } + }, ], function (err, allowed) { if (err || allowed) { return next(err); @@ -142,20 +141,18 @@ module.exports = function (middleware) { return next(); } - res.status(403).render('403', {title: '[[global:403.title]]'}); + res.status(403).render('403', { title: '[[global:403.title]]' }); }; middleware.registrationComplete = function (req, res, next) { // If the user's session contains registration data, redirect the user to complete registration if (!req.session.hasOwnProperty('registration')) { return next(); + } + if (!req.path.endsWith('/register/complete')) { + controllers.helpers.redirect(res, '/register/complete'); } else { - if (!req.path.endsWith('/register/complete')) { - controllers.helpers.redirect(res, '/register/complete'); - } else { - return next(); - } + return next(); } }; - }; diff --git a/src/navigation/admin.js b/src/navigation/admin.js index ab1c5aff42..0917e9e524 100644 --- a/src/navigation/admin.js +++ b/src/navigation/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var plugins = require('../plugins'); @@ -36,14 +36,14 @@ admin.save = function (data, callback) { }, function (next) { db.sortedSetAdd('navigation:enabled', order, items, next); - } + }, ], callback); }; admin.getAdmin = function (callback) { async.parallel({ enabled: admin.get, - available: getAvailable + available: getAvailable, }, callback); }; diff --git a/src/navigation/index.js b/src/navigation/index.js index 5563c44c4b..2cb24f3a9f 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var nconf = require('nconf'); var admin = require('./admin'); @@ -38,4 +38,4 @@ navigation.get = function (callback) { }; -module.exports = navigation; \ No newline at end of file +module.exports = navigation; diff --git a/src/notifications.js b/src/notifications.js index b99700be01..31960dc2f1 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -16,7 +16,6 @@ var plugins = require('./plugins'); var utils = require('../public/src/utils'); (function (Notifications) { - Notifications.init = function () { winston.verbose('[notifications.init] Registering jobs.'); new cron('*/30 * * * *', Notifications.prune, null, true); @@ -143,7 +142,7 @@ var utils = require('../public/src/utils'); }, function (next) { db.setObject('notifications:' + data.nid, data, next); - } + }, ], function (err) { callback(err, data); }); @@ -172,7 +171,7 @@ var utils = require('../public/src/utils'); setTimeout(function () { batch.processArray(uids, function (uids, next) { pushToUids(uids, notification, next); - }, {interval: 1000}, function (err) { + }, { interval: 1000 }, function (err) { if (err) { winston.error(err.stack); } @@ -189,7 +188,7 @@ var utils = require('../public/src/utils'); async.waterfall([ function (next) { - plugins.fireHook('filter:notification.push', {notification: notification, uids: uids}, next); + plugins.fireHook('filter:notification.push', { notification: notification, uids: uids }, next); }, function (data, next) { uids = data.uids; @@ -219,9 +218,9 @@ var utils = require('../public/src/utils'); }); } - plugins.fireHook('action:notification.pushed', {notification: notification, uids: uids}); + plugins.fireHook('action:notification.pushed', { notification: notification, uids: uids }); next(); - } + }, ], callback); } @@ -254,7 +253,7 @@ var utils = require('../public/src/utils'); async.parallel([ async.apply(db.sortedSetRemove, 'notifications', nid), - async.apply(db.delete, 'notifications:' + nid) + async.apply(db.delete, 'notifications:' + nid), ], function (err) { if (err) { winston.error('Encountered error rescinding notification (' + nid + '): ' + err.message); @@ -288,7 +287,7 @@ var utils = require('../public/src/utils'); async.parallel([ async.apply(db.sortedSetRemove, 'uid:' + uid + ':notifications:read', nid), - async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:unread', notification.datetime, nid) + async.apply(db.sortedSetAdd, 'uid:' + uid + ':notifications:unread', notification.datetime, nid), ], callback); }); }; @@ -325,7 +324,7 @@ var utils = require('../public/src/utils'); }); db.getObjectsFields(notificationKeys, ['nid', 'datetime'], next); - } + }, ], function (err, notificationData) { if (err) { return callback(err); @@ -351,7 +350,7 @@ var utils = require('../public/src/utils'); }, function (next) { db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next); - } + }, ], function (err) { callback(err); }); @@ -373,8 +372,7 @@ var utils = require('../public/src/utils'); }; Notifications.prune = function () { - var week = 604800000, - numPruned = 0; + var week = 604800000; var cutoffTime = Date.now() - week; @@ -391,15 +389,13 @@ var utils = require('../public/src/utils'); return 'notifications:' + nid; }); - numPruned = nids.length; - async.parallel([ function (next) { db.sortedSetRemove('notifications', nids, next); }, function (next) { db.deleteAll(keys, next); - } + }, ], function (err) { if (err) { return winston.error('Encountered error pruning notifications: ' + err.message); @@ -411,13 +407,17 @@ var utils = require('../public/src/utils'); Notifications.merge = function (notifications, callback) { // When passed a set of notification objects, merge any that can be merged var mergeIds = [ - 'notifications:upvoted_your_post_in', - 'notifications:user_started_following_you', - 'notifications:user_posted_to', - 'notifications:user_flagged_post_in', - 'new_register' - ], - isolated, differentiators, differentiator, modifyIndex, set; + 'notifications:upvoted_your_post_in', + 'notifications:user_started_following_you', + 'notifications:user_posted_to', + 'notifications:user_flagged_post_in', + 'new_register', + ]; + var isolated; + var differentiators; + var differentiator; + var modifyIndex; + var set; notifications = mergeIds.reduce(function (notifications, mergeId) { isolated = notifications.filter(function (notifObj) { @@ -456,35 +456,35 @@ var utils = require('../public/src/utils'); return notifications; } - switch(mergeId) { + switch (mergeId) { // intentional fall-through - case 'notifications:upvoted_your_post_in': - case 'notifications:user_started_following_you': - case 'notifications:user_posted_to': - case 'notifications:user_flagged_post_in': - var usernames = set.map(function (notifObj) { - return notifObj && notifObj.user && notifObj.user.username; - }).filter(function (username, idx, array) { - return array.indexOf(username) === idx; - }); - var numUsers = usernames.length; + case 'notifications:upvoted_your_post_in': + case 'notifications:user_started_following_you': + case 'notifications:user_posted_to': + case 'notifications:user_flagged_post_in': + var usernames = set.map(function (notifObj) { + return notifObj && notifObj.user && notifObj.user.username; + }).filter(function (username, idx, array) { + return array.indexOf(username) === idx; + }); + var numUsers = usernames.length; - var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s; - var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); - titleEscaped = titleEscaped ? (', ' + titleEscaped) : ''; + var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s; + var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); + titleEscaped = titleEscaped ? (', ' + titleEscaped) : ''; - if (numUsers === 2) { - notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]'; - } else if (numUsers > 2) { - notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]'; - } + if (numUsers === 2) { + notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]'; + } else if (numUsers > 2) { + notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]'; + } - notifications[modifyIndex].path = set[set.length - 1].path; - break; + notifications[modifyIndex].path = set[set.length - 1].path; + break; - case 'new_register': - notifications[modifyIndex].bodyShort = '[[notifications:' + mergeId + '_multiple, ' + set.length + ']]'; - break; + case 'new_register': + notifications[modifyIndex].bodyShort = '[[notifications:' + mergeId + '_multiple, ' + set.length + ']]'; + break; } // Filter out duplicates @@ -501,11 +501,10 @@ var utils = require('../public/src/utils'); }, notifications); plugins.fireHook('filter:notifications.merge', { - notifications: notifications + notifications: notifications, }, function (err, data) { callback(err, data.notifications); }); }; - }(exports)); diff --git a/src/pagination.js b/src/pagination.js index ba7dbc8436..3e57c5b201 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -7,12 +7,12 @@ var pagination = {}; pagination.create = function (currentPage, pageCount, queryObj) { if (pageCount <= 1) { return { - prev: {page: 1, active: currentPage > 1}, - next: {page: 1, active: currentPage < pageCount}, + prev: { page: 1, active: currentPage > 1 }, + next: { page: 1, active: currentPage < pageCount }, rel: [], pages: [], currentPage: 1, - pageCount: 1 + pageCount: 1, }; } pageCount = parseInt(pageCount, 10); @@ -26,7 +26,8 @@ pagination.create = function (currentPage, pageCount, queryObj) { if (startPage > pageCount - 5) { startPage -= 2 - (pageCount - currentPage); } - for(var i = 0; i < 5; ++i) { + var i; + for (i = 0; i < 5; i += 1) { pagesToShow.push(startPage + i); } @@ -42,38 +43,38 @@ pagination.create = function (currentPage, pageCount, queryObj) { var pages = pagesToShow.map(function (page) { queryObj.page = page; - return {page: page, active: page === currentPage, qs: qs.stringify(queryObj)}; + return { page: page, active: page === currentPage, qs: qs.stringify(queryObj) }; }); - for (i = pages.length - 1; i > 0; --i) { + for (i = pages.length - 1; i > 0; i -= 1) { if (pages[i].page - 2 === pages[i - 1].page) { - pages.splice(i, 0, {page: pages[i].page - 1, active: false, qs: qs.stringify(queryObj)}); + pages.splice(i, 0, { page: pages[i].page - 1, active: false, qs: qs.stringify(queryObj) }); } else if (pages[i].page - 1 !== pages[i - 1].page) { - pages.splice(i, 0, {separator: true}); + pages.splice(i, 0, { separator: true }); } } - var data = {rel: [], pages: pages, currentPage: currentPage, pageCount: pageCount}; + var data = { rel: [], pages: pages, currentPage: currentPage, pageCount: pageCount }; queryObj.page = previous; - data.prev = {page: previous, active: currentPage > 1, qs: qs.stringify(queryObj)}; + data.prev = { page: previous, active: currentPage > 1, qs: qs.stringify(queryObj) }; queryObj.page = next; - data.next = {page: next, active: currentPage < pageCount, qs: qs.stringify(queryObj)}; + data.next = { page: next, active: currentPage < pageCount, qs: qs.stringify(queryObj) }; if (currentPage < pageCount) { data.rel.push({ rel: 'next', - href: '?page=' + next + href: '?page=' + next, }); } if (currentPage > 1) { data.rel.push({ rel: 'prev', - href: '?page=' + previous + href: '?page=' + previous, }); } return data; }; -module.exports = pagination; \ No newline at end of file +module.exports = pagination; diff --git a/src/password.js b/src/password.js index 2744cbefba..d4fd1b0f8d 100644 --- a/src/password.js +++ b/src/password.js @@ -4,17 +4,17 @@ var fork = require('child_process').fork; module.hash = function (rounds, password, callback) { - forkChild({type: 'hash', rounds: rounds, password: password}, callback); + forkChild({ type: 'hash', rounds: rounds, password: password }, callback); }; module.compare = function (password, hash, callback) { - forkChild({type: 'compare', password: password, hash: hash}, callback); + forkChild({ type: 'compare', password: password, hash: hash }, callback); }; function forkChild(message, callback) { var forkProcessParams = {}; - if(global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { - forkProcessParams = {execArgv: ['--debug=' + (5859), '--nolazy']}; + if (global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { + forkProcessParams = { execArgv: ['--debug=' + (5859), '--nolazy'] }; } var child = fork('./bcrypt', [], forkProcessParams); @@ -30,4 +30,4 @@ } return module; -}(exports)); \ No newline at end of file +}(exports)); diff --git a/src/plugins.js b/src/plugins.js index 15f4b91650..7c2ecaee25 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -108,7 +108,7 @@ var middleware; if (Plugins.versionWarning.length && nconf.get('isPrimary') === 'true') { process.stdout.write('\n'); winston.warn('[plugins/load] The following plugins may not be compatible with your version of NodeBB. This may cause unintended behaviour or crashing. In the event of an unresponsive NodeBB caused by this plugin, run `./nodebb reset -p PLUGINNAME` to disable it.'); - for(var x = 0,numPlugins = Plugins.versionWarning.length; x < numPlugins; x++) { + for (var x = 0, numPlugins = Plugins.versionWarning.length; x < numPlugins; x += 1) { process.stdout.write(' * '.yellow + Plugins.versionWarning[x] + '\n'); } process.stdout.write('\n'); @@ -116,18 +116,17 @@ var middleware; Object.keys(Plugins.loadedHooks).forEach(function (hook) { var hooks = Plugins.loadedHooks[hook]; - hooks = hooks.sort(function (a, b) { + hooks.sort(function (a, b) { return a.priority - b.priority; }); }); next(); - } + }, ], callback); }; Plugins.reloadRoutes = function (callback) { - callback = callback || function () {}; var router = express.Router(); router.hotswapId = 'plugins'; @@ -136,9 +135,10 @@ var middleware; }; var controllers = require('./controllers'); - Plugins.fireHook('static:app.load', {app: app, router: router, middleware: middleware, controllers: controllers}, function (err) { + Plugins.fireHook('static:app.load', { app: app, router: router, middleware: middleware, controllers: controllers }, function (err) { if (err) { - return winston.error('[plugins] Encountered error while executing post-router plugins hooks: ' + err.message); + winston.error('[plugins] Encountered error while executing post-router plugins hooks: ' + err.message); + return callback(err); } hotswap.replace('plugins', router); @@ -148,8 +148,8 @@ var middleware; }; Plugins.getTemplates = function (callback) { - var templates = {}, - tplName; + var templates = {}; + var tplName; async.waterfall([ async.apply(db.getSortedSetRange, 'plugins:active', 0, -1), @@ -166,7 +166,7 @@ var middleware; }, function (paths, next) { async.map(paths, Plugins.loadPluginInfo, next); - } + }, ], function (err, plugins) { if (err) { return callback(err); @@ -180,7 +180,7 @@ var middleware; if (pluginTemplates) { pluginTemplates.forEach(function (pluginTemplate) { if (pluginTemplate.endsWith('.tpl')) { - tplName = "/" + pluginTemplate.replace(templatesPath, '').substring(1); + tplName = '/' + pluginTemplate.replace(templatesPath, '').substring(1); if (templates.hasOwnProperty(tplName)) { winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); @@ -191,12 +191,10 @@ var middleware; winston.warn('[plugins] Skipping ' + pluginTemplate + ' by plugin ' + plugin.id); } }); + } else if (err) { + winston.error(err); } else { - if (err) { - winston.error(err); - } else { - winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); - } + winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); } next(false); @@ -214,7 +212,7 @@ var middleware; var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; require('request')(url, { - json: true + json: true, }, function (err, res, body) { if (res.statusCode === 404 || !body.payload) { return callback(err, {}); @@ -238,7 +236,7 @@ var middleware; var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins' + (matching !== false ? '?version=' + version : ''); require('request')(url, { - json: true + json: true, }, function (err, res, body) { if (err) { winston.error('Error parsing plugins : ' + err.message); @@ -253,11 +251,11 @@ var middleware; var pluginMap = {}; var dependencies = require(path.join(nconf.get('base_dir'), 'package.json')).dependencies; apiReturn = apiReturn || []; - for(var i = 0; i < apiReturn.length; ++i) { + for (var i = 0; i < apiReturn.length; i += 1) { apiReturn[i].id = apiReturn[i].name; apiReturn[i].installed = false; apiReturn[i].active = false; - apiReturn[i].url = apiReturn[i].url ? apiReturn[i].url : apiReturn[i].repository ? apiReturn[i].repository.url : ''; + apiReturn[i].url = apiReturn[i].url || (apiReturn[i].repository ? apiReturn[i].repository.url : ''); pluginMap[apiReturn[i].name] = apiReturn[i]; } @@ -313,13 +311,12 @@ var middleware; } pluginArray.sort(function (a, b) { - if (a.name > b.name ) { + if (a.name > b.name) { return 1; - } else if (a.name < b.name ) { + } else if (a.name < b.name) { return -1; - } else { - return 0; } + return 0; }); callback(null, pluginArray); @@ -373,7 +370,7 @@ var middleware; pluginData.error = false; next(null, pluginData); }); - } + }, ], function (err, pluginData) { if (err) { return next(); // Silently fail @@ -385,8 +382,7 @@ var middleware; }, function (err) { next(err, plugins); }); - } + }, ], callback); }; - }(exports)); diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index b8e5af0e46..12303555fc 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -1,13 +1,13 @@ 'use strict'; -var winston = require('winston'), - async = require('async'); +var winston = require('winston'); +var async = require('async'); module.exports = function (Plugins) { Plugins.deprecatedHooks = { 'filter:user.custom_fields': null, // remove in v1.1.0 'filter:post.save': 'filter:post.create', - 'filter:user.profileLinks': 'filter:user.profileMenu' + 'filter:user.profileLinks': 'filter:user.profileMenu', }; /* `data` is an object consisting of (* is required): @@ -44,7 +44,7 @@ module.exports = function (Plugins) { if (parts.length > 2) { parts.pop(); } - var hook = parts.join(':'); + parts.join(':'); } if (data.hook && data.method) { @@ -57,10 +57,9 @@ module.exports = function (Plugins) { method = data.method.split('.').reduce(function (memo, prop) { if (memo && memo[prop]) { return memo[prop]; - } else { - // Couldn't find method by path, aborting - return null; } + // Couldn't find method by path, aborting + return null; }, Plugins.libraries[data.id]); // Write the actual method reference to the hookObj @@ -76,6 +75,13 @@ module.exports = function (Plugins) { } }; + Plugins.unregisterHook = function (id, hook, method) { + var hooks = Plugins.loadedHooks[hook] || []; + Plugins.loadedHooks[hook] = hooks.filter(function (hookData) { + return hookData && hookData.id !== id && hookData.method !== method; + }); + }; + Plugins.fireHook = function (hook, params, callback) { callback = typeof callback === 'function' ? callback : function () {}; @@ -83,18 +89,18 @@ module.exports = function (Plugins) { var hookType = hook.split(':')[0]; switch (hookType) { - case 'filter': - fireFilterHook(hook, hookList, params, callback); - break; - case 'action': - fireActionHook(hook, hookList, params, callback); - break; - case 'static': - fireStaticHook(hook, hookList, params, callback); - break; - default: - winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); - break; + case 'filter': + fireFilterHook(hook, hookList, params, callback); + break; + case 'action': + fireActionHook(hook, hookList, params, callback); + break; + case 'static': + fireStaticHook(hook, hookList, params, callback); + break; + default: + winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); + break; } }; @@ -126,7 +132,6 @@ module.exports = function (Plugins) { return callback(); } async.each(hookList, function (hookObj, next) { - if (typeof hookObj.method !== 'function') { if (global.env === 'development') { winston.warn('[plugins] Expected method for hook \'' + hook + '\' in plugin \'' + hookObj.id + '\' not found, skipping.'); @@ -160,7 +165,7 @@ module.exports = function (Plugins) { next.apply(null, arguments); } }); - } catch(err) { + } catch (err) { winston.error('[plugins] Error executing \'' + hook + '\' in plugin \'' + hookObj.id + '\''); winston.error(err); clearTimeout(timeoutId); diff --git a/src/plugins/install.js b/src/plugins/install.js index 840d46008a..1e0fe0838c 100644 --- a/src/plugins/install.js +++ b/src/plugins/install.js @@ -13,7 +13,6 @@ var pubsub = require('../pubsub'); module.exports = function (Plugins) { - if (nconf.get('isPrimary') === 'true') { pubsub.on('plugins:toggleInstall', function (data) { if (data.hostname !== os.hostname()) { @@ -52,18 +51,18 @@ module.exports = function (Plugins) { meta.reloadRequired = true; Plugins.fireHook(isActive ? 'action:plugin.deactivate' : 'action:plugin.activate', id); next(); - } + }, ], function (err) { if (err) { winston.warn('[plugins] Could not toggle active state on plugin \'' + id + '\''); return callback(err); } - callback(null, {id: id, active: !isActive}); + callback(null, { id: id, active: !isActive }); }); }; Plugins.toggleInstall = function (id, version, callback) { - pubsub.publish('plugins:toggleInstall', {hostname: os.hostname(), id: id, version: version}); + pubsub.publish('plugins:toggleInstall', { hostname: os.hostname(), id: id, version: version }); toggleInstall(id, version, callback); }; @@ -81,7 +80,7 @@ module.exports = function (Plugins) { }, function (active, next) { if (active) { - Plugins.toggleActive(id, function (err, status) { + Plugins.toggleActive(id, function (err) { next(err); }); return; @@ -97,7 +96,7 @@ module.exports = function (Plugins) { function (pluginData, next) { Plugins.fireHook('action:plugin.' + type, id); next(null, pluginData); - } + }, ], callback); } @@ -113,7 +112,7 @@ module.exports = function (Plugins) { } Plugins.upgrade = function (id, version, callback) { - pubsub.publish('plugins:upgrade', {hostname: os.hostname(), id: id, version: version}); + pubsub.publish('plugins:upgrade', { hostname: os.hostname(), id: id, version: version }); upgrade(id, version, callback); }; @@ -126,7 +125,7 @@ module.exports = function (Plugins) { function (isActive, next) { meta.reloadRequired = isActive; next(null, isActive); - } + }, ], callback); } @@ -145,4 +144,4 @@ module.exports = function (Plugins) { Plugins.getActive = function (callback) { db.getSortedSetRange('plugins:active', 0, -1, callback); }; -}; \ No newline at end of file +}; diff --git a/src/plugins/load.js b/src/plugins/load.js index c6a9429667..3c1c61df73 100644 --- a/src/plugins/load.js +++ b/src/plugins/load.js @@ -61,7 +61,7 @@ module.exports = function (Plugins) { async.apply(mapSoundpack, pluginData), ], next); }, next); - } + }, ], callback); }; @@ -145,7 +145,7 @@ module.exports = function (Plugins) { } else { callback(); } - } catch(err) { + } catch (err) { winston.error(err.stack); winston.warn('[plugins] Unable to parse library for: ' + pluginData.id); callback(); @@ -153,6 +153,8 @@ module.exports = function (Plugins) { } function mapStaticDirectories(pluginData, pluginPath, callback) { + var validMappedPath = /^[\w\-_]+$/; + function mapStaticDirs(mappedPath, callback) { if (Plugins.staticDirs[mappedPath]) { winston.warn('[plugins/' + pluginData.id + '] Mapped path (' + mappedPath + ') already specified!'); @@ -175,8 +177,6 @@ module.exports = function (Plugins) { } } - var validMappedPath = /^[\w\-_]+$/; - pluginData.staticDirs = pluginData.staticDirs || {}; var dirs = Object.keys(pluginData.staticDirs); @@ -230,7 +230,7 @@ module.exports = function (Plugins) { pluginData.modules.forEach(function (file) { if (strip) { - modules[file.replace(new RegExp('\.?(\/[^\/]+){' + strip + '}\/'), '')] = path.join('./node_modules/', pluginData.id, file); + modules[file.replace(new RegExp('.?(/[^/]+){' + strip + '}/'), '')] = path.join('./node_modules/', pluginData.id, file); } else { modules[path.basename(file)] = path.join('./node_modules/', pluginData.id, file); } @@ -302,11 +302,10 @@ module.exports = function (Plugins) { if (!atRootLevel && relPath) { winston.verbose('[plugins/load] File not found: ' + fullPath + ' (Ascending)'); return resolveModulePath(path.join(__dirname, '../..', relPath)); - } else { - // Already at root level, file was simply not found - winston.warn('[plugins/load] File not found: ' + fullPath + ' (Ignoring)'); - return null; } + // Already at root level, file was simply not found + winston.warn('[plugins/load] File not found: ' + fullPath + ' (Ignoring)'); + return null; } } @@ -317,7 +316,7 @@ module.exports = function (Plugins) { }, plugin: function (next) { fs.readFile(path.join(pluginPath, 'plugin.json'), next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -335,7 +334,7 @@ module.exports = function (Plugins) { pluginData.repository = packageData.repository; pluginData.nbbpm = packageData.nbbpm; pluginData.path = pluginPath; - } catch(err) { + } catch (err) { var pluginDir = pluginPath.split(path.sep); pluginDir = pluginDir[pluginDir.length - 1]; diff --git a/src/posts.js b/src/posts.js index 3a7d2d7e19..c7e7ec3e0a 100644 --- a/src/posts.js +++ b/src/posts.js @@ -11,7 +11,6 @@ var privileges = require('./privileges'); var plugins = require('./plugins'); (function (Posts) { - require('./posts/create')(Posts); require('./posts/delete')(Posts); require('./posts/edit')(Posts); @@ -44,7 +43,7 @@ var plugins = require('./plugins'); var keys = []; - for (var x = 0, numPids = pids.length; x < numPids; ++x) { + for (var x = 0, numPids = pids.length; x < numPids; x += 1) { keys.push('post:' + pids[x]); } @@ -66,7 +65,7 @@ var plugins = require('./plugins'); }, next); }, function (posts, next) { - plugins.fireHook('filter:post.getPosts', {posts: posts, uid: uid}, next); + plugins.fireHook('filter:post.getPosts', { posts: posts, uid: uid }, next); }, function (data, next) { if (!data || !Array.isArray(data.posts)) { @@ -74,7 +73,7 @@ var plugins = require('./plugins'); } data.posts = data.posts.filter(Boolean); next(null, data.posts); - } + }, ], callback); }; @@ -87,11 +86,11 @@ var plugins = require('./plugins'); privileges.posts.filter('read', pids, uid, next); }, function (pids, next) { - Posts.getPostSummaryByPids(pids, uid, {stripTags: false}, next); + Posts.getPostSummaryByPids(pids, uid, { stripTags: false }, next); }, function (posts, next) { - next(null, {posts: posts, nextStart: stop + 1}); - } + next(null, { posts: posts, nextStart: stop + 1 }); + }, ], callback); }; @@ -123,7 +122,7 @@ var plugins = require('./plugins'); data.pid = pid; - plugins.fireHook('filter:post.getFields', {posts: [data], fields: fields}, function (err, data) { + plugins.fireHook('filter:post.getFields', { posts: [data], fields: fields }, function (err, data) { callback(err, (data && Array.isArray(data.posts) && data.posts.length) ? data.posts[0] : null); }); }); @@ -142,7 +141,7 @@ var plugins = require('./plugins'); if (err) { return callback(err); } - plugins.fireHook('filter:post.getFields', {posts: posts, fields: fields}, function (err, data) { + plugins.fireHook('filter:post.getFields', { posts: posts, fields: fields }, function (err, data) { callback(err, (data && Array.isArray(data.posts)) ? data.posts : null); }); }); @@ -154,7 +153,7 @@ var plugins = require('./plugins'); return callback(err); } var data = { - pid: pid + pid: pid, }; data[field] = value; plugins.fireHook('action:post.setFields', data); @@ -212,12 +211,12 @@ var plugins = require('./plugins'); db[method](sets, pids, next); }, function (indices, next) { - for (var i = 0; i < indices.length; ++i) { + for (var i = 0; i < indices.length; i += 1) { indices[i] = utils.isNumber(indices[i]) ? parseInt(indices[i], 10) + 1 : 0; } next(null, indices); - } + }, ], callback); }; @@ -247,12 +246,12 @@ var plugins = require('./plugins'); return next(); } db.sortedSetAdd('tid:' + postData.tid + ':posts:votes', postData.votes, postData.pid, next); - } + }, ], next); }, function (next) { - Posts.setPostFields(postData.pid, {upvotes: postData.upvotes, downvotes: postData.downvotes}, next); - } + Posts.setPostFields(postData.pid, { upvotes: postData.upvotes, downvotes: postData.downvotes }, next); + }, ], function (err) { callback(err); }); @@ -266,6 +265,4 @@ var plugins = require('./plugins'); } } }; - - }(exports)); diff --git a/src/posts/bookmarks.js b/src/posts/bookmarks.js index b60da91c77..6038a50b54 100644 --- a/src/posts/bookmarks.js +++ b/src/posts/bookmarks.js @@ -6,7 +6,6 @@ var db = require('../database'); var plugins = require('../plugins'); module.exports = function (Posts) { - Posts.bookmark = function (pid, uid, callback) { toggleBookmark('bookmark', pid, uid, callback); }; @@ -30,7 +29,7 @@ module.exports = function (Posts) { }, hasBookmarked: function (next) { Posts.hasBookmarked(pid, uid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -61,7 +60,7 @@ module.exports = function (Posts) { function (count, next) { results.postData.bookmarks = count; Posts.setPostField(pid, 'bookmarks', count, next); - } + }, ], function (err) { if (err) { return callback(err); @@ -73,12 +72,12 @@ module.exports = function (Posts) { pid: pid, uid: uid, owner: results.owner, - current: current + current: current, }); callback(null, { post: results.postData, - isBookmarked: isBookmarking + isBookmarked: isBookmarking, }); }); }); diff --git a/src/posts/cache.js b/src/posts/cache.js index 62277c46e3..c73e1c8d92 100644 --- a/src/posts/cache.js +++ b/src/posts/cache.js @@ -1,10 +1,12 @@ +'use strict'; + var LRU = require('lru-cache'); var meta = require('../meta'); var cache = LRU({ max: parseInt(meta.config.postCacheSize, 10) || 1048576, length: function (n) { return n.length; }, - maxAge: 1000 * 60 * 60 + maxAge: 1000 * 60 * 60, }); -module.exports = cache; \ No newline at end of file +module.exports = cache; diff --git a/src/posts/category.js b/src/posts/category.js index 9c877d91dd..cb9a2566c4 100644 --- a/src/posts/category.js +++ b/src/posts/category.js @@ -8,7 +8,6 @@ var db = require('../database'); var topics = require('../topics'); module.exports = function (Posts) { - Posts.getCidByPid = function (pid, callback) { async.waterfall([ function (next) { @@ -16,7 +15,7 @@ module.exports = function (Posts) { }, function (tid, next) { topics.getTopicField(tid, 'cid', next); - } + }, ], callback); }; @@ -49,7 +48,7 @@ module.exports = function (Posts) { return map[post.tid]; }); next(null, cids); - } + }, ], callback); }; @@ -82,4 +81,4 @@ module.exports = function (Posts) { }); } }; -}; \ No newline at end of file +}; diff --git a/src/posts/create.js b/src/posts/create.js index 3484bc424e..e8e24a5585 100644 --- a/src/posts/create.js +++ b/src/posts/create.js @@ -12,7 +12,6 @@ var categories = require('../categories'); var utils = require('../../public/src/utils'); module.exports = function (Posts) { - Posts.create = function (data, callback) { // This is an internal method, consider using Topics.reply instead var uid = data.uid; @@ -36,14 +35,13 @@ module.exports = function (Posts) { db.incrObjectField('global', 'nextPid', next); }, function (pid, next) { - postData = { - 'pid': pid, - 'uid': uid, - 'tid': tid, - 'content': content, - 'timestamp': timestamp, - 'deleted': 0 + pid: pid, + uid: uid, + tid: tid, + content: content, + timestamp: timestamp, + deleted: 0, }; if (data.toPid) { @@ -61,7 +59,7 @@ module.exports = function (Posts) { plugins.fireHook('filter:post.save', postData, next); }, function (postData, next) { - plugins.fireHook('filter:post.create', {post: postData, data: data}, next); + plugins.fireHook('filter:post.create', { post: postData, data: data }, next); }, function (data, next) { postData = data.post; @@ -93,12 +91,12 @@ module.exports = function (Posts) { } async.parallel([ async.apply(db.sortedSetAdd, 'pid:' + postData.toPid + ':replies', timestamp, postData.pid), - async.apply(db.incrObjectField, 'post:' + postData.toPid, 'replies') + async.apply(db.incrObjectField, 'post:' + postData.toPid, 'replies'), ], next); }, function (next) { db.incrObjectField('global', 'postCount', next); - } + }, ], function (err) { if (err) { return next(err); @@ -110,9 +108,8 @@ module.exports = function (Posts) { postData.isMain = isMain; plugins.fireHook('action:post.save', _.clone(postData)); next(null, postData); - } + }, ], callback); }; }; - diff --git a/src/posts/delete.js b/src/posts/delete.js index 7a1d3d0cc8..63f511481b 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -10,15 +10,14 @@ var notifications = require('../notifications'); var plugins = require('../plugins'); module.exports = function (Posts) { - Posts.delete = function (pid, uid, callback) { var postData; async.waterfall([ function (next) { - plugins.fireHook('filter:post.delete', {pid: pid, uid: uid}, next); + plugins.fireHook('filter:post.delete', { pid: pid, uid: uid }, next); }, function (data, next) { - Posts.setPostFields(pid, {deleted: 1, deleterUid: uid}, next); + Posts.setPostFields(pid, { deleted: 1, deleterUid: uid }, next); }, function (next) { Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'timestamp'], next); @@ -37,13 +36,13 @@ module.exports = function (Posts) { }, function (next) { topics.updateTeaser(postData.tid, next); - } + }, ], next); }, function (results, next) { plugins.fireHook('action:post.delete', pid); next(null, postData); - } + }, ], callback); }; @@ -51,10 +50,10 @@ module.exports = function (Posts) { var postData; async.waterfall([ function (next) { - plugins.fireHook('filter:post.restore', {pid: pid, uid: uid}, next); + plugins.fireHook('filter:post.restore', { pid: pid, uid: uid }, next); }, function (data, next) { - Posts.setPostFields(pid, {deleted: 0, deleterUid: 0}, next); + Posts.setPostFields(pid, { deleted: 0, deleterUid: 0 }, next); }, function (next) { Posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'timestamp'], next); @@ -74,13 +73,13 @@ module.exports = function (Posts) { }, function (next) { topics.updateTeaser(postData.tid, next); - } + }, ], next); }, function (results, next) { plugins.fireHook('action:post.restore', _.clone(postData)); next(null, postData); - } + }, ], callback); }; @@ -109,7 +108,7 @@ module.exports = function (Posts) { } else { next(); } - } + }, ], callback); } @@ -122,7 +121,7 @@ module.exports = function (Posts) { if (!exists) { return callback(); } - plugins.fireHook('filter:post.purge', {pid: pid, uid: uid}, next); + plugins.fireHook('filter:post.purge', { pid: pid, uid: uid }, next); }, function (data, next) { async.parallel([ @@ -146,7 +145,7 @@ module.exports = function (Posts) { }, function (next) { Posts.dismissFlag(pid, next); - } + }, ], function (err) { if (err) { return next(err); @@ -154,7 +153,7 @@ module.exports = function (Posts) { plugins.fireHook('action:post.purge', pid); db.delete('post:' + pid, next); }); - } + }, ], callback); }; @@ -169,7 +168,7 @@ module.exports = function (Posts) { db.sortedSetsRemove([ 'tid:' + postData.tid + ':posts', 'tid:' + postData.tid + ':posts:votes', - 'uid:' + postData.uid + ':posts' + 'uid:' + postData.uid + ':posts', ], pid, next); }, function (next) { @@ -203,9 +202,9 @@ module.exports = function (Posts) { }, function (next) { notifications.rescind('new_post:tid:' + postData.tid + ':pid:' + pid + ':uid:' + postData.uid, next); - } + }, ], next); - } + }, ], function (err) { callback(err); }); @@ -252,7 +251,7 @@ module.exports = function (Posts) { }, downvoters: function (next) { db.getSetMembers('pid:' + pid + ':downvote', next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -275,7 +274,7 @@ module.exports = function (Posts) { }, function (next) { db.deleteAll(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], next); - } + }, ], callback); }); } @@ -290,10 +289,8 @@ module.exports = function (Posts) { } async.parallel([ async.apply(db.sortedSetRemove, 'pid:' + toPid + ':replies', pid), - async.apply(db.decrObjectField, 'post:' + toPid, 'replies') + async.apply(db.decrObjectField, 'post:' + toPid, 'replies'), ], callback); }); } - - }; diff --git a/src/posts/edit.js b/src/posts/edit.js index b989b24f8f..863888a6ce 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -14,7 +14,6 @@ var pubsub = require('../pubsub'); var utils = require('../../public/src/utils'); module.exports = function (Posts) { - pubsub.on('post:edit', function (pid) { cache.del(pid); }); @@ -45,7 +44,7 @@ module.exports = function (Posts) { if (data.handle) { postData.handle = data.handle; } - plugins.fireHook('filter:post.edit', {req: data.req, post: postData, data: data, uid: data.uid}, next); + plugins.fireHook('filter:post.edit', { req: data.req, post: postData, data: data, uid: data.uid }, next); }, function (result, next) { postData = result.post; @@ -58,7 +57,7 @@ module.exports = function (Posts) { }, topic: function (next) { editMainPost(data, postData, next); - } + }, }, next); }, function (_results, next) { @@ -76,7 +75,7 @@ module.exports = function (Posts) { function (postData, next) { results.post = postData; next(null, results); - } + }, ], callback); }; @@ -90,7 +89,7 @@ module.exports = function (Posts) { }, isMain: function (next) { Posts.isMain(data.pid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -101,7 +100,7 @@ module.exports = function (Posts) { tid: tid, cid: results.topic.cid, isMainPost: false, - renamed: false + renamed: false, }); } @@ -109,7 +108,7 @@ module.exports = function (Posts) { tid: tid, cid: results.topic.cid, uid: postData.uid, - mainPid: data.pid + mainPid: data.pid, }; if (title) { @@ -123,7 +122,7 @@ module.exports = function (Posts) { async.waterfall([ function (next) { - plugins.fireHook('filter:topic.edit', {req: data.req, topic: topicData, data: data}, next); + plugins.fireHook('filter:topic.edit', { req: data.req, topic: topicData, data: data }, next); }, function (results, next) { db.setObject('topic:' + tid, results.topic, next); @@ -147,12 +146,10 @@ module.exports = function (Posts) { slug: topicData.slug, isMainPost: true, renamed: title !== results.topic.title, - tags: tags + tags: tags, }); - } + }, ], callback); }); } - - }; diff --git a/src/posts/flags.js b/src/posts/flags.js index e81da20f95..214a155278 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -9,7 +9,6 @@ var user = require('../user'); var analytics = require('../analytics'); module.exports = function (Posts) { - Posts.flag = function (post, uid, reason, callback) { if (!parseInt(uid, 10) || !reason) { return callback(); @@ -19,7 +18,7 @@ module.exports = function (Posts) { function (next) { async.parallel({ hasFlagged: async.apply(Posts.isFlaggedByUser, post.pid, uid), - exists: async.apply(Posts.exists, post.pid) + exists: async.apply(Posts.exists, post.pid), }, next); }, function (results, next) { @@ -53,17 +52,17 @@ module.exports = function (Posts) { async.parallel([ async.apply(db.sortedSetIncrBy, 'users:flags', 1, post.uid), async.apply(db.incrObjectField, 'user:' + post.uid, 'flags'), - async.apply(db.sortedSetAdd, 'uid:' + post.uid + ':flag:pids', now, post.pid) + async.apply(db.sortedSetAdd, 'uid:' + post.uid + ':flag:pids', now, post.pid), ], next); } else { next(); } - } + }, ], next); }, function (data, next) { openNewFlag(post.pid, uid, next); - } + }, ], function (err) { if (err) { return callback(err); @@ -80,7 +79,7 @@ module.exports = function (Posts) { } if (count === 1) { // Only update state on new flag Posts.updateFlagData(uid, pid, { - state: 'open' + state: 'open', }, callback); } else { callback(); @@ -107,7 +106,7 @@ module.exports = function (Posts) { if (parseInt(postData.flags, 10) > 0) { async.parallel([ async.apply(db.sortedSetIncrBy, 'users:flags', -postData.flags, postData.uid), - async.apply(db.incrObjectFieldBy, 'user:' + postData.uid, 'flags', -postData.flags) + async.apply(db.incrObjectFieldBy, 'user:' + postData.uid, 'flags', -postData.flags), ], next); } else { next(); @@ -120,7 +119,7 @@ module.exports = function (Posts) { db.sortedSetsRemove([ 'posts:flagged', 'posts:flags:count', - 'uid:' + postData.uid + ':flag:pids' + 'uid:' + postData.uid + ':flag:pids', ], pid, next); }, function (next) { @@ -135,22 +134,22 @@ module.exports = function (Posts) { var nid = 'post_flag:' + pid + ':uid:' + uid; async.parallel([ async.apply(db.delete, 'notifications:' + nid), - async.apply(db.sortedSetRemove, 'notifications', 'post_flag:' + pid + ':uid:' + uid) + async.apply(db.sortedSetRemove, 'notifications', 'post_flag:' + pid + ':uid:' + uid), ], next); }, next); }); }, - async.apply(db.delete, 'pid:' + pid + ':flag:uids') + async.apply(db.delete, 'pid:' + pid + ':flag:uids'), ], next); }, async.apply(db.deleteObjectField, 'post:' + pid, 'flags'), async.apply(db.delete, 'pid:' + pid + ':flag:uid:reason'), - async.apply(db.deleteObjectFields, 'post:' + pid, ['flag:state', 'flag:assignee', 'flag:notes', 'flag:history']) + async.apply(db.deleteObjectFields, 'post:' + pid, ['flag:state', 'flag:assignee', 'flag:notes', 'flag:history']), ], next); }, function (results, next) { db.sortedSetsRemoveRangeByScore(['users:flags'], '-inf', 0, next); - } + }, ], callback); }; @@ -176,7 +175,7 @@ module.exports = function (Posts) { async.waterfall([ function (next) { if (Array.isArray(set)) { - db.getSortedSetRevIntersect({sets: set, start: start, stop: -1, aggregate: 'MAX'}, next); + db.getSortedSetRevIntersect({ sets: set, start: start, stop: -1, aggregate: 'MAX' }, next); } else { db.getSortedSetRevRange(set, start, -1, next); } @@ -194,8 +193,8 @@ module.exports = function (Posts) { function (posts, next) { var count = posts.length; var end = stop - start + 1; - next(null, {posts: posts.slice(0, stop === -1 ? undefined : end), count: count}); - } + next(null, { posts: posts.slice(0, stop === -1 ? undefined : end), count: count }); + }, ], callback); }; @@ -209,8 +208,8 @@ module.exports = function (Posts) { }, next); }, posts: function (next) { - Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags', 'flag:assignee', 'flag:state', 'flag:notes', 'flag:history']}, next); - } + Posts.getPostSummaryByPids(pids, uid, { stripTags: false, extraFields: ['flags', 'flag:assignee', 'flag:state', 'flag:notes', 'flag:history'] }, next); + }, }, next); }, function (results, next) { @@ -219,7 +218,7 @@ module.exports = function (Posts) { var uid = uidReason.split(':')[0]; var reason = uidReason.substr(uidReason.indexOf(':') + 1); user.getUserFields(uid, ['username', 'userslug', 'picture'], function (err, userData) { - next(err, {user: userData, reason: reason}); + next(err, { user: userData, reason: reason }); }); }, next); }, function (err, reasons) { @@ -240,14 +239,15 @@ module.exports = function (Posts) { function (posts, next) { // Parse out flag data into its own object inside each post hash async.map(posts, function (postObj, next) { - for(var prop in postObj) { - postObj.flagData = postObj.flagData || {}; + for (var prop in postObj) { + if (postObj.hasOwnProperty(prop)) { + postObj.flagData = postObj.flagData || {}; - if (postObj.hasOwnProperty(prop) && prop.startsWith('flag:')) { - postObj.flagData[prop.slice(5)] = postObj[prop]; + if (prop.startsWith('flag:')) { + postObj.flagData[prop.slice(5)] = postObj[prop]; - if (prop === 'flag:state') { - switch(postObj[prop]) { + if (prop === 'flag:state') { + switch (postObj[prop]) { case 'open': postObj.flagData.labelClass = 'info'; break; @@ -260,10 +260,11 @@ module.exports = function (Posts) { case 'rejected': postObj.flagData.labelClass = 'danger'; break; + } } - } - delete postObj[prop]; + delete postObj[prop]; + } } } @@ -280,7 +281,7 @@ module.exports = function (Posts) { setImmediate(next.bind(null, null, postObj)); } }, next); - } + }, ], callback); } @@ -296,14 +297,14 @@ module.exports = function (Posts) { } // Track new additions - for(prop in flagObj) { + for (prop in flagObj) { if (flagObj.hasOwnProperty(prop) && !postData.hasOwnProperty('flag:' + prop) && flagObj[prop].length) { changes.push(prop); } } // Track changed items - for(prop in postData) { + for (prop in postData) { if ( postData.hasOwnProperty(prop) && prop.startsWith('flag:') && flagObj.hasOwnProperty(prop.slice(5)) && @@ -324,23 +325,23 @@ module.exports = function (Posts) { var history = JSON.parse(postData['flag:history'] || '[]'); changes.forEach(function (property) { - switch(property) { - case 'assignee': // intentional fall-through - case 'state': - history.unshift({ - uid: uid, - type: property, - value: flagObj[property], - timestamp: Date.now() - }); - break; + switch (property) { + case 'assignee': // intentional fall-through + case 'state': + history.unshift({ + uid: uid, + type: property, + value: flagObj[property], + timestamp: Date.now(), + }); + break; - case 'notes': - history.unshift({ - uid: uid, - type: property, - timestamp: Date.now() - }); + case 'notes': + history.unshift({ + uid: uid, + type: property, + timestamp: Date.now(), + }); } }); @@ -400,7 +401,7 @@ module.exports = function (Posts) { } else { setImmediate(next); } - } + }, ], function (err) { next(err, event); }); diff --git a/src/posts/parse.js b/src/posts/parse.js index e4b4cc7d3c..8ac2028bbd 100644 --- a/src/posts/parse.js +++ b/src/posts/parse.js @@ -1,5 +1,6 @@ 'use strict'; +var async = require('async'); var nconf = require('nconf'); var url = require('url'); var winston = require('winston'); @@ -13,45 +14,40 @@ var translator = require('../../public/src/modules/translator'); var urlRegex = /href="([^"]+)"/g; module.exports = function (Posts) { - Posts.parsePost = function (postData, callback) { - postData.content = postData.content || ''; + postData.content = String(postData.content || ''); if (postData.pid && cache.has(String(postData.pid))) { postData.content = cache.get(String(postData.pid)); return callback(null, postData); } - // Casting post content into a string, just in case - if (typeof postData.content !== 'string') { - postData.content = postData.content.toString(); - } + async.waterfall([ + function (next) { + plugins.fireHook('filter:parse.post', { postData: postData }, next); + }, + function (data, next) { + data.postData.content = translator.escape(data.postData.content); - plugins.fireHook('filter:parse.post', {postData: postData}, function (err, data) { - if (err) { - return callback(err); - } - - data.postData.content = translator.escape(data.postData.content); - - if (global.env === 'production' && data.postData.pid) { - cache.set(String(data.postData.pid), data.postData.content); - } - - callback(null, data.postData); - }); + if (global.env === 'production' && data.postData.pid) { + cache.set(String(data.postData.pid), data.postData.content); + } + next(null, data.postData); + }, + ], callback); }; Posts.parseSignature = function (userData, uid, callback) { userData.signature = sanitizeSignature(userData.signature || ''); - plugins.fireHook('filter:parse.signature', {userData: userData, uid: uid}, callback); + plugins.fireHook('filter:parse.signature', { userData: userData, uid: uid }, callback); }; Posts.relativeToAbsolute = function (content) { // Turns relative links in post body to absolute urls - var parsed, current, absolute; - - while ((current = urlRegex.exec(content)) !== null) { + var parsed; + var current = urlRegex.exec(content); + var absolute; + while (current !== null) { if (current[1]) { try { parsed = url.parse(current[1]); @@ -66,18 +62,19 @@ module.exports = function (Posts) { content = content.slice(0, current.index + 6) + absolute + content.slice(current.index + 6 + current[1].length); } - } catch(err) { + } catch (err) { winston.verbose(err.messsage); } } + current = urlRegex.exec(content); } return content; }; function sanitizeSignature(signature) { - var string = S(signature), - tagsToStrip = []; + var string = S(signature); + var tagsToStrip = []; if (parseInt(meta.config['signatures:disableLinks'], 10) === 1) { tagsToStrip.push('a'); diff --git a/src/posts/recent.js b/src/posts/recent.js index 5cc5cd1fae..320febff19 100644 --- a/src/posts/recent.js +++ b/src/posts/recent.js @@ -9,7 +9,7 @@ module.exports = function (Posts) { var terms = { day: 86400000, week: 604800000, - month: 2592000000 + month: 2592000000, }; Posts.getRecentPosts = function (uid, start, stop, term, callback) { @@ -28,8 +28,8 @@ module.exports = function (Posts) { privileges.posts.filter('read', pids, uid, next); }, function (pids, next) { - Posts.getPostSummaryByPids(pids, uid, {stripTags: true}, next); - } + Posts.getPostSummaryByPids(pids, uid, { stripTags: true }, next); + }, ], callback); }; @@ -48,7 +48,7 @@ module.exports = function (Posts) { return uid && array.indexOf(uid) === index; }); next(null, uids); - } + }, ], callback); - }; + }; }; diff --git a/src/posts/summary.js b/src/posts/summary.js index 2173057e3a..93e322229d 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -13,7 +13,6 @@ var utils = require('../../public/src/utils'); module.exports = function (Posts) { - Posts.getPostSummaryByPids = function (pids, uid, options, callback) { if (!Array.isArray(pids) || !pids.length) { return callback(null, []); @@ -50,7 +49,7 @@ module.exports = function (Posts) { }, topicsAndCategories: function (next) { getTopicAndCategories(topicKeys, next); - } + }, }, next); }, function (results, next) { @@ -81,11 +80,11 @@ module.exports = function (Posts) { parsePosts(posts, options, next); }, function (posts, next) { - plugins.fireHook('filter:post.getPostSummaryByPids', {posts: posts, uid: uid}, next); + plugins.fireHook('filter:post.getPostSummaryByPids', { posts: posts, uid: uid }, next); }, function (data, next) { next(null, data.posts); - } + }, ], callback); }; @@ -129,14 +128,14 @@ module.exports = function (Posts) { }); categories.getCategoriesFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid', 'bgColor', 'color'], function (err, categories) { - callback(err, {topics: topics, categories: categories}); + callback(err, { topics: topics, categories: categories }); }); }); } function toObject(key, data) { var obj = {}; - for(var i = 0; i < data.length; ++i) { + for (var i = 0; i < data.length; i += 1) { obj[data[i][key]] = data[i]; } return obj; diff --git a/src/posts/tools.js b/src/posts/tools.js index 82d55b1192..c395eae457 100644 --- a/src/posts/tools.js +++ b/src/posts/tools.js @@ -30,7 +30,7 @@ module.exports = function (Posts) { function (deleted, next) { if (parseInt(deleted, 10) === 1 && isDelete) { return next(new Error('[[error:post-already-deleted]]')); - } else if(parseInt(deleted, 10) !== 1 && !isDelete) { + } else if (parseInt(deleted, 10) !== 1 && !isDelete) { return next(new Error('[[error:post-already-restored]]')); } @@ -52,7 +52,7 @@ module.exports = function (Posts) { Posts.parsePost(postData, next); }); } - } + }, ], callback); } @@ -67,9 +67,8 @@ module.exports = function (Posts) { } cache.del(pid); Posts.purge(pid, uid, next); - } + }, ], callback); }; - }; diff --git a/src/posts/topics.js b/src/posts/topics.js index 0653c880e6..eca6da493a 100644 --- a/src/posts/topics.js +++ b/src/posts/topics.js @@ -7,7 +7,6 @@ var topics = require('../topics'); var utils = require('../../public/src/utils'); module.exports = function (Posts) { - Posts.getPostsFromSet = function (set, start, stop, uid, reverse, callback) { async.waterfall([ function (next) { @@ -15,7 +14,7 @@ module.exports = function (Posts) { }, function (pids, next) { Posts.getPostsByPids(pids, uid, next); - } + }, ], callback); }; @@ -29,7 +28,7 @@ module.exports = function (Posts) { }, function (mainPid, next) { next(null, parseInt(pid, 10) === parseInt(mainPid, 10)); - } + }, ], callback); }; @@ -40,7 +39,7 @@ module.exports = function (Posts) { }, function (tid, next) { topics.getTopicFields(tid, fields, next); - } + }, ], callback); }; @@ -66,7 +65,7 @@ module.exports = function (Posts) { }); topics.getTopicsFields(tids, ['slug'], next); - } + }, }, next); }, function (results, next) { @@ -81,8 +80,7 @@ module.exports = function (Posts) { }); next(null, paths); - } + }, ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/posts/user.js b/src/posts/user.js index 7f387ef894..59906bf2ca 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -9,7 +9,6 @@ var meta = require('../meta'); var plugins = require('../plugins'); module.exports = function (Posts) { - Posts.getUserInfoForPosts = function (uids, uid, callback) { var groupsMap = {}; var userData; @@ -25,7 +24,7 @@ module.exports = function (Posts) { return groupTitle && array.indexOf(groupTitle) === index; }); groups.getGroupsData(groupTitles, next); - } + }, ], function (err, groupsData) { if (err) { return callback(err); @@ -38,7 +37,7 @@ module.exports = function (Posts) { slug: group.slug, labelColor: group.labelColor, icon: group.icon, - userTitle: group.userTitle + userTitle: group.userTitle, }; } }); @@ -72,8 +71,8 @@ module.exports = function (Posts) { Posts.parseSignature(userData, uid, next); }, customProfileInfo: function (next) { - plugins.fireHook('filter:posts.custom_profile_info', {profile: [], uid: userData.uid}, next); - } + plugins.fireHook('filter:posts.custom_profile_info', { profile: [], uid: userData.uid }, next); + }, }, function (err, results) { if (err) { return next(err); @@ -95,7 +94,7 @@ module.exports = function (Posts) { uid = parseInt(uid, 10); if (Array.isArray(pid)) { if (!uid) { - return callback(null, pid.map(function () {return false;})); + return callback(null, pid.map(function () { return false; })); } Posts.getPostsFields(pid, ['uid'], function (err, posts) { if (err) { @@ -118,7 +117,7 @@ module.exports = function (Posts) { Posts.isModerator = function (pids, uid, callback) { if (!parseInt(uid, 10)) { - return callback(null, pids.map(function () {return false;})); + return callback(null, pids.map(function () { return false; })); } Posts.getCidsByPids(pids, function (err, cids) { if (err) { @@ -127,4 +126,4 @@ module.exports = function (Posts) { user.isModerator(uid, cids, callback); }); }; -}; \ No newline at end of file +}; diff --git a/src/posts/votes.js b/src/posts/votes.js index 428685257a..ddc860f5b6 100644 --- a/src/posts/votes.js +++ b/src/posts/votes.js @@ -8,7 +8,6 @@ var user = require('../user'); var plugins = require('../plugins'); module.exports = function (Posts) { - var votesInProgress = {}; Posts.upvote = function (pid, uid, callback) { @@ -64,7 +63,7 @@ module.exports = function (Posts) { Posts.hasVoted = function (pid, uid, callback) { if (!parseInt(uid, 10)) { - return callback(null, {upvoted: false, downvoted: false}); + return callback(null, { upvoted: false, downvoted: false }); } db.isMemberOfSets(['pid:' + pid + ':upvote', 'pid:' + pid + ':downvote'], uid, function (err, hasVoted) { @@ -72,19 +71,19 @@ module.exports = function (Posts) { return callback(err); } - callback (null, {upvoted: hasVoted[0], downvoted: hasVoted[1]}); + callback(null, { upvoted: hasVoted[0], downvoted: hasVoted[1] }); }); }; Posts.getVoteStatusByPostIDs = function (pids, uid, callback) { if (!parseInt(uid, 10)) { var data = pids.map(function () { return false; }); - return callback(null, {upvotes: data, downvotes: data}); + return callback(null, { upvotes: data, downvotes: data }); } var upvoteSets = []; var downvoteSets = []; - for (var i = 0; i < pids.length; ++i) { + for (var i = 0; i < pids.length; i += 1) { upvoteSets.push('pid:' + pids[i] + ':upvote'); downvoteSets.push('pid:' + pids[i] + ':downvote'); } @@ -95,7 +94,7 @@ module.exports = function (Posts) { }, downvotes: function (next) { db.isMemberOfSets(downvoteSets, uid, next); - } + }, }, callback); }; @@ -144,7 +143,7 @@ module.exports = function (Posts) { }, reputation: function (next) { user.getUserField(uid, 'reputation', next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -154,15 +153,15 @@ module.exports = function (Posts) { return callback(new Error('self-vote')); } - if (command === 'downvote' && parseInt(results.reputation) < parseInt(meta.config['privileges:downvote'], 10)) { + if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['privileges:downvote'], 10)) { return callback(new Error('[[error:not-enough-reputation-to-downvote]]')); } - var voteStatus = results.voteStatus, - hook, - current = voteStatus.upvoted ? 'upvote' : 'downvote'; + var voteStatus = results.voteStatus; + var hook; + var current = voteStatus.upvoted ? 'upvote' : 'downvote'; - if (voteStatus.upvoted && command === 'downvote' || voteStatus.downvoted && command === 'upvote') { // e.g. User *has* upvoted, and clicks downvote + if ((voteStatus.upvoted && command === 'downvote') || (voteStatus.downvoted && command === 'upvote')) { // e.g. User *has* upvoted, and clicks downvote hook = command; } else if (voteStatus.upvoted || voteStatus.downvoted) { // e.g. User *has* upvoted, clicks upvote (so we "unvote") hook = 'unvote'; @@ -175,7 +174,7 @@ module.exports = function (Posts) { pid: pid, uid: uid, owner: results.owner, - current: current + current: current, }); if (!voteStatus || (!voteStatus.upvoted && !voteStatus.downvoted)) { @@ -224,11 +223,11 @@ module.exports = function (Posts) { adjustPostVotes(postData, uid, type, unvote, function (err) { callback(err, { user: { - reputation: newreputation + reputation: newreputation, }, post: postData, upvote: type === 'upvote' && !unvote, - downvote: type === 'downvote' && !unvote + downvote: type === 'downvote' && !unvote, }); }); }); @@ -248,7 +247,7 @@ module.exports = function (Posts) { }, function (next) { db.setRemove('pid:' + postData.pid + ':' + notType, uid, next); - } + }, ], function (err) { if (err) { return callback(err); @@ -260,7 +259,7 @@ module.exports = function (Posts) { }, downvotes: function (next) { db.setCount('pid:' + postData.pid + ':downvote', next); - } + }, }, function (err, results) { if (err) { return callback(err); diff --git a/src/privileges.js b/src/privileges.js index d933d72877..cccbd089d6 100644 --- a/src/privileges.js +++ b/src/privileges.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var privileges = module.exports; @@ -14,7 +14,7 @@ privileges.userPrivilegeList = [ 'upload:post:image', 'upload:post:file', 'purge', - 'mods' + 'mods', ]; privileges.groupPrivilegeList = [ @@ -29,7 +29,7 @@ privileges.groupPrivilegeList = [ 'groups:upload:post:image', 'groups:upload:post:file', 'groups:purge', - 'groups:moderate' + 'groups:moderate', ]; privileges.privilegeList = privileges.userPrivilegeList.concat(privileges.groupPrivilegeList); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 67b004e19e..6678f5d5aa 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -11,32 +11,31 @@ var helpers = require('./helpers'); var plugins = require('../plugins'); module.exports = function (privileges) { - privileges.categories = {}; privileges.categories.list = function (cid, callback) { // Method used in admin/category controller to show all users/groups with privs in that given cid var privilegeLabels = [ - {name: 'Find Category'}, - {name: 'Access Category'}, - {name: 'Access Topics'}, - {name: 'Create Topics'}, - {name: 'Reply to Topics'}, - {name: 'Edit Posts'}, - {name: 'Delete Posts'}, - {name: 'Delete Topics'}, - {name: 'Upload Images'}, - {name: 'Upload Files'}, - {name: 'Purge'}, - {name: 'Moderate'} + { name: 'Find Category' }, + { name: 'Access Category' }, + { name: 'Access Topics' }, + { name: 'Create Topics' }, + { name: 'Reply to Topics' }, + { name: 'Edit Posts' }, + { name: 'Delete Posts' }, + { name: 'Delete Topics' }, + { name: 'Upload Images' }, + { name: 'Upload Files' }, + { name: 'Purge' }, + { name: 'Moderate' }, ]; async.parallel({ labels: function (next) { async.parallel({ users: async.apply(plugins.fireHook, 'filter:privileges.list_human', privilegeLabels), - groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', privilegeLabels) + groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', privilegeLabels), }, next); }, users: function (next) { @@ -50,7 +49,6 @@ module.exports = function (privileges) { }), next); }, function (memberSets, next) { - memberSets = memberSets.map(function (set) { return set.map(function (uid) { return parseInt(uid, 10); @@ -66,14 +64,14 @@ module.exports = function (privileges) { memberData.forEach(function (member) { member.privileges = {}; - for(var x = 0,numPrivs = userPrivileges.length; x < numPrivs; x++) { + for (var x = 0, numPrivs = userPrivileges.length; x < numPrivs; x += 1) { member.privileges[userPrivileges[x]] = memberSets[x].indexOf(parseInt(member.uid, 10)) !== -1; } }); next(null, memberData); }); - } + }, ], next); }, groups: function (next) { @@ -87,7 +85,6 @@ module.exports = function (privileges) { }), next); }, function (memberSets, next) { - var uniqueGroups = _.unique(_.flatten(memberSets)); groups.getGroups('groups:createtime', 0, -1, function (err, groupNames) { @@ -99,7 +96,7 @@ module.exports = function (privileges) { return groupName.indexOf(':privileges:') === -1 && uniqueGroups.indexOf(groupName) !== -1; }); - groupNames = groups.getEphemeralGroups().concat(groupNames); + groupNames = groups.ephemeralGroups.concat(groupNames); var registeredUsersIndex = groupNames.indexOf('registered-users'); if (registeredUsersIndex !== -1) { groupNames.splice(0, 0, groupNames.splice(registeredUsersIndex, 1)[0]); @@ -117,7 +114,7 @@ module.exports = function (privileges) { var memberData = groupNames.map(function (member) { memberPrivs = {}; - for(var x = 0,numPrivs = groupPrivileges.length; x < numPrivs; x++) { + for (var x = 0, numPrivs = groupPrivileges.length; x < numPrivs; x += 1) { memberPrivs[groupPrivileges[x]] = memberSets[x].indexOf(member) !== -1; } return { @@ -141,9 +138,9 @@ module.exports = function (privileges) { next(null, member); }); }, next); - } + }, ], next); - } + }, }, function (err, payload) { if (err) { return callback(err); @@ -158,34 +155,36 @@ module.exports = function (privileges) { privileges.categories.get = function (cid, uid, callback) { var privs = ['topics:create', 'topics:read', 'read']; - async.parallel({ - privileges: function (next) { - helpers.isUserAllowedTo(privs, uid, cid, next); + async.waterfall([ + function (next) { + async.parallel({ + privileges: function (next) { + helpers.isUserAllowedTo(privs, uid, cid, next); + }, + isAdministrator: function (next) { + user.isAdministrator(uid, next); + }, + isModerator: function (next) { + user.isModerator(uid, cid, next); + }, + }, next); }, - isAdministrator: function (next) { - user.isAdministrator(uid, next); - }, - isModerator: function (next) { - user.isModerator(uid, cid, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } - var privData = _.object(privs, results.privileges); - var isAdminOrMod = results.isAdministrator || results.isModerator; + function (results, next) { + var privData = _.object(privs, results.privileges); + var isAdminOrMod = results.isAdministrator || results.isModerator; - plugins.fireHook('filter:privileges.categories.get', { - 'topics:create': privData['topics:create'] || isAdminOrMod, - 'topics:read': privData['topics:read'] || isAdminOrMod, - read: privData.read || isAdminOrMod, - cid: cid, - uid: uid, - editable: isAdminOrMod, - view_deleted: isAdminOrMod, - isAdminOrMod: isAdminOrMod - }, callback); - }); + plugins.fireHook('filter:privileges.categories.get', { + 'topics:create': privData['topics:create'] || isAdminOrMod, + 'topics:read': privData['topics:read'] || isAdminOrMod, + read: privData.read || isAdminOrMod, + cid: cid, + uid: uid, + editable: isAdminOrMod, + view_deleted: isAdminOrMod, + isAdminOrMod: isAdminOrMod, + }, next); + }, + ], callback); }; privileges.categories.isAdminOrMod = function (cid, uid, callback) { @@ -198,7 +197,7 @@ module.exports = function (privileges) { }, function (next) { user.isAdministrator(uid, next); - } + }, ], callback); }; @@ -216,29 +215,29 @@ module.exports = function (privileges) { return callback(null, false); } - categories.getCategoryField(cid, 'disabled', function (err, disabled) { - if (err) { - return callback(err); - } - - if (parseInt(disabled, 10) === 1) { - return callback(null, false); - } - - helpers.some([ - function (next) { - helpers.isUserAllowedTo(privilege, uid, [cid], function (err, results) { - next(err, Array.isArray(results) && results.length ? results[0] : false); - }); - }, - function (next) { - user.isModerator(uid, cid, next); - }, - function (next) { - user.isAdministrator(uid, next); + async.waterfall([ + function (next) { + categories.getCategoryField(cid, 'disabled', next); + }, + function (disabled, next) { + if (parseInt(disabled, 10) === 1) { + return callback(null, false); } - ], callback); - }); + helpers.some([ + function (next) { + helpers.isUserAllowedTo(privilege, uid, [cid], function (err, results) { + next(err, Array.isArray(results) && results.length ? results[0] : false); + }); + }, + function (next) { + user.isModerator(uid, cid, next); + }, + function (next) { + user.isAdministrator(uid, next); + }, + ], next); + }, + ], callback); }; privileges.categories.filterCids = function (privilege, cids, uid, callback) { @@ -250,18 +249,19 @@ module.exports = function (privileges) { return array.indexOf(cid) === index; }); - privileges.categories.getBase(privilege, cids, uid, function (err, results) { - if (err) { - return callback(err); - } + async.waterfall([ + function (next) { + privileges.categories.getBase(privilege, cids, uid, next); + }, + function (results, next) { + cids = cids.filter(function (cid, index) { + return !results.categories[index].disabled && + (results.allowedTo[index] || results.isAdmin || results.isModerators[index]); + }); - cids = cids.filter(function (cid, index) { - return !results.categories[index].disabled && - (results.allowedTo[index] || results.isAdmin || results.isModerators[index]); - }); - - callback(null, cids.filter(Boolean)); - }); + next(null, cids.filter(Boolean)); + }, + ], callback); }; privileges.categories.getBase = function (privilege, cids, uid, callback) { @@ -277,7 +277,7 @@ module.exports = function (privileges) { }, isAdmin: function (next) { user.isAdministrator(uid, next); - } + }, }, callback); }; @@ -290,26 +290,27 @@ module.exports = function (privileges) { return array.indexOf(uid) === index; }); - async.parallel({ - allowedTo: function (next) { - helpers.isUsersAllowedTo(privilege, uids, cid, next); + async.waterfall([ + function (next) { + async.parallel({ + allowedTo: function (next) { + helpers.isUsersAllowedTo(privilege, uids, cid, next); + }, + isModerators: function (next) { + user.isModerator(uids, cid, next); + }, + isAdmin: function (next) { + user.isAdministrator(uids, next); + }, + }, next); }, - isModerators: function (next) { - user.isModerator(uids, cid, next); + function (results, next) { + uids = uids.filter(function (uid, index) { + return results.allowedTo[index] || results.isModerators[index] || results.isAdmin[index]; + }); + next(null, uids); }, - isAdmin: function (next) { - user.isAdministrator(uids, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } - - uids = uids.filter(function (uid, index) { - return results.allowedTo[index] || results.isModerators[index] || results.isAdmin[index]; - }); - callback(null, uids); - }); + ], callback); }; privileges.categories.give = function (privileges, cid, groupName, callback) { @@ -327,23 +328,24 @@ module.exports = function (privileges) { } privileges.categories.canMoveAllTopics = function (currentCid, targetCid, uid, callback) { - async.parallel({ - isAdministrator: function (next) { - user.isAdministrator(uid, next); + async.waterfall([ + function (next) { + async.parallel({ + isAdministrator: function (next) { + user.isAdministrator(uid, next); + }, + moderatorOfCurrent: function (next) { + user.isModerator(uid, currentCid, next); + }, + moderatorOfTarget: function (next) { + user.isModerator(uid, targetCid, next); + }, + }, next); }, - moderatorOfCurrent: function (next) { - user.isModerator(uid, currentCid, next); + function (results, next) { + next(null, results.isAdministrator || (results.moderatorOfCurrent && results.moderatorOfTarget)); }, - moderatorOfTarget: function (next) { - user.isModerator(uid, targetCid, next); - } - }, function (err, results) { - if (err) { - return callback(err); - } - - callback(null, results.isAdministrator || (results.moderatorOfCurrent && results.moderatorOfTarget)); - }); + ], callback); }; privileges.categories.userPrivileges = function (cid, uid, callback) { @@ -372,7 +374,7 @@ module.exports = function (privileges) { }, mods: function (next) { user.isModerator(uid, cid, next); - } + }, }, callback); }; @@ -399,8 +401,7 @@ module.exports = function (privileges) { }, 'groups:topics:read': function (next) { groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:topics:read', next); - } + }, }, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index 9df9d8cd7b..23f555f89d 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -31,8 +31,9 @@ function isUserAllowedToCids(privilege, uid, cids, callback) { return isGuestAllowedToCids(privilege, cids, callback); } - var userKeys = [], groupKeys = []; - for (var i = 0; i < cids.length; ++i) { + var userKeys = []; + var groupKeys = []; + for (var i = 0; i < cids.length; i += 1) { userKeys.push('cid:' + cids[i] + ':privileges:' + privilege); groupKeys.push('cid:' + cids[i] + ':privileges:groups:' + privilege); } @@ -43,14 +44,14 @@ function isUserAllowedToCids(privilege, uid, cids, callback) { }, hasGroupPrivilege: function (next) { groups.isMemberOfGroupsList(uid, groupKeys, next); - } + }, }, function (err, results) { if (err) { return callback(err); } var result = []; - for (var i = 0; i < cids.length; ++i) { + for (var i = 0; i < cids.length; i += 1) { result.push(results.hasUserPrivilege[i] || results.hasGroupPrivilege[i]); } @@ -63,8 +64,9 @@ function isUserAllowedToPrivileges(privileges, uid, cid, callback) { return isGuestAllowedToPrivileges(privileges, cid, callback); } - var userKeys = [], groupKeys = []; - for (var i = 0; i < privileges.length; ++i) { + var userKeys = []; + var groupKeys = []; + for (var i = 0; i < privileges.length; i += 1) { userKeys.push('cid:' + cid + ':privileges:' + privileges[i]); groupKeys.push('cid:' + cid + ':privileges:groups:' + privileges[i]); } @@ -75,14 +77,14 @@ function isUserAllowedToPrivileges(privileges, uid, cid, callback) { }, hasGroupPrivilege: function (next) { groups.isMemberOfGroupsList(uid, groupKeys, next); - } + }, }, function (err, results) { if (err) { return callback(err); } var result = []; - for (var i = 0; i < privileges.length; ++i) { + for (var i = 0; i < privileges.length; i += 1) { result.push(results.hasUserPrivilege[i] || results.hasGroupPrivilege[i]); } @@ -98,14 +100,14 @@ helpers.isUsersAllowedTo = function (privilege, uids, cid, callback) { }, hasGroupPrivilege: function (next) { groups.isMembersOfGroupList(uids, 'cid:' + cid + ':privileges:groups:' + privilege, next); - } + }, }, function (err, results) { if (err) { return callback(err); } var result = []; - for(var i = 0; i < uids.length; ++i) { + for (var i = 0; i < uids.length; i += 1) { result.push(results.hasUserPrivilege[i] || results.hasGroupPrivilege[i]); } @@ -115,7 +117,7 @@ helpers.isUsersAllowedTo = function (privilege, uids, cid, callback) { function isGuestAllowedToCids(privilege, cids, callback) { var groupKeys = []; - for (var i = 0; i < cids.length; ++i) { + for (var i = 0; i < cids.length; i += 1) { groupKeys.push('cid:' + cids[i] + ':privileges:groups:' + privilege); } @@ -124,11 +126,11 @@ function isGuestAllowedToCids(privilege, cids, callback) { function isGuestAllowedToPrivileges(privileges, cid, callback) { var groupKeys = []; - for (var i = 0; i < privileges.length; ++i) { + for (var i = 0; i < privileges.length; i += 1) { groupKeys.push('cid:' + cid + ':privileges:groups:' + privileges[i]); } groups.isMemberOfGroups('guests', groupKeys, callback); } -module.exports = helpers; \ No newline at end of file +module.exports = helpers; diff --git a/src/privileges/posts.js b/src/privileges/posts.js index d68edc6e14..8a31ad4129 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -11,7 +11,6 @@ var helpers = require('./helpers'); var plugins = require('../plugins'); module.exports = function (privileges) { - privileges.posts = {}; privileges.posts.get = function (pids, uid, callback) { @@ -32,7 +31,7 @@ module.exports = function (privileges) { read: async.apply(helpers.isUserAllowedTo, 'read', uid, cids), 'posts:edit': async.apply(helpers.isUserAllowedTo, 'posts:edit', uid, cids), }, next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -40,7 +39,7 @@ module.exports = function (privileges) { var privileges = []; - for (var i = 0; i < pids.length; ++i) { + for (var i = 0; i < pids.length; i += 1) { var isAdminOrMod = results.isAdmin || results.isModerator[i]; var editable = isAdminOrMod || (results.isOwner[i] && results['posts:edit'][i]); @@ -50,7 +49,7 @@ module.exports = function (privileges) { move: isAdminOrMod, isAdminOrMod: isAdminOrMod, 'topics:read': results['topics:read'][i] || isAdminOrMod, - read: results.read[i] || isAdminOrMod + read: results.read[i] || isAdminOrMod, }); } @@ -91,7 +90,6 @@ module.exports = function (privileges) { topics.getTopicsFields(tids, ['deleted', 'cid'], next); }, function (topicData, next) { - topicData.forEach(function (topic, index) { if (topic) { tidToTopic[tids[index]] = topic; @@ -111,7 +109,6 @@ module.exports = function (privileges) { privileges.categories.getBase(privilege, cids, uid, next); }, function (results, next) { - var isModOf = {}; cids = cids.filter(function (cid, index) { isModOf[cid] = results.isModerators[index]; @@ -130,24 +127,24 @@ module.exports = function (privileges) { plugins.fireHook('filter:privileges.posts.filter', { privilege: privilege, uid: uid, - pids: pids + pids: pids, }, function (err, data) { next(err, data ? data.pids : null); }); - } + }, ], callback); }; privileges.posts.canEdit = function (pid, uid, callback) { async.parallel({ isEditable: async.apply(isPostEditable, pid, uid), - isAdminOrMod: async.apply(isAdminOrMod, pid, uid) + isAdminOrMod: async.apply(isAdminOrMod, pid, uid), }, function (err, results) { if (err) { return callback(err); } if (results.isAdminOrMod) { - return callback(null, {flag: true}); + return callback(null, { flag: true }); } callback(null, results.isEditable); @@ -166,33 +163,33 @@ module.exports = function (privileges) { isAdminOrMod: async.apply(isAdminOrMod, pid, uid), isLocked: async.apply(topics.isLocked, postData.tid), isOwner: async.apply(posts.isOwner, pid, uid), - 'posts:delete': async.apply(privileges.posts.can, 'posts:delete', pid, uid) + 'posts:delete': async.apply(privileges.posts.can, 'posts:delete', pid, uid), }, next); - } + }, ], function (err, results) { if (err) { return callback(err); } if (results.isAdminOrMod) { - return callback(null, {flag: true}); + return callback(null, { flag: true }); } if (results.isLocked) { - return callback(null, {flag: false, message: '[[error:topic-locked]]'}); + return callback(null, { flag: false, message: '[[error:topic-locked]]' }); } if (!results['posts:delete']) { - return callback(null, {flag: false, message: '[[error:no-privileges]]'}); + return callback(null, { flag: false, message: '[[error:no-privileges]]' }); } var postDeleteDuration = parseInt(meta.config.postDeleteDuration, 10); if (postDeleteDuration && (Date.now() - parseInt(postData.timestamp, 10) > postDeleteDuration * 1000)) { - return callback(null, {flag: false, message: '[[error:post-delete-duration-expired, ' + meta.config.postDeleteDuration + ']]'}); + return callback(null, { flag: false, message: '[[error:post-delete-duration-expired, ' + meta.config.postDeleteDuration + ']]' }); } var deleterUid = parseInt(postData.deleterUid, 10) || 0; var flag = results.isOwner && (deleterUid === 0 || deleterUid === parseInt(postData.uid, 10)); - callback(null, {flag: flag, message: '[[error:no-privileges]]'}); + callback(null, { flag: flag, message: '[[error:no-privileges]]' }); }); }; @@ -214,42 +211,40 @@ module.exports = function (privileges) { async.parallel({ purge: async.apply(privileges.categories.isUserAllowedTo, 'purge', cid, uid), owner: async.apply(posts.isOwner, pid, uid), - isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid) + isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid), }, next); }, function (results, next) { next(null, results.isAdminOrMod || (results.purge && results.owner)); - } + }, ], callback); }; function isPostEditable(pid, uid, callback) { - var tid; async.waterfall([ function (next) { posts.getPostFields(pid, ['tid', 'timestamp'], next); }, function (postData, next) { - tid = postData.tid; var postEditDuration = parseInt(meta.config.postEditDuration, 10); if (postEditDuration && Date.now() - parseInt(postData.timestamp, 10) > postEditDuration * 1000) { - return callback(null, {flag: false, message: '[[error:post-edit-duration-expired, ' + meta.config.postEditDuration + ']]'}); + return callback(null, { flag: false, message: '[[error:post-edit-duration-expired, ' + meta.config.postEditDuration + ']]' }); } topics.isLocked(postData.tid, next); }, function (isLocked, next) { if (isLocked) { - return callback(null, {flag: false, message: '[[error:topic-locked]]'}); + return callback(null, { flag: false, message: '[[error:topic-locked]]' }); } async.parallel({ owner: async.apply(posts.isOwner, pid, uid), - edit: async.apply(privileges.posts.can, 'posts:edit', pid, uid) + edit: async.apply(privileges.posts.can, 'posts:edit', pid, uid), }, next); }, function (result, next) { - next(null, {flag: result.owner && result.edit, message: '[[error:no-privileges]]'}); - } + next(null, { flag: result.owner && result.edit, message: '[[error:no-privileges]]' }); + }, ], callback); } @@ -266,7 +261,7 @@ module.exports = function (privileges) { }, function (next) { user.isAdministrator(uid, next); - } + }, ], callback); } -}; \ No newline at end of file +}; diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 2350299e72..f44383eed8 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -12,7 +12,6 @@ var categories = require('../categories'); var plugins = require('../plugins'); module.exports = function (privileges) { - privileges.topics = {}; privileges.topics.get = function (tid, uid, callback) { @@ -26,9 +25,9 @@ module.exports = function (privileges) { privileges: async.apply(helpers.isUserAllowedTo, privs, uid, topic.cid), isAdministrator: async.apply(user.isAdministrator, uid), isModerator: async.apply(user.isModerator, uid, topic.cid), - disabled: async.apply(categories.getCategoryField, topic.cid, 'disabled') + disabled: async.apply(categories.getCategoryField, topic.cid, 'disabled'), }, next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -57,7 +56,7 @@ module.exports = function (privileges) { isAdminOrMod: isAdminOrMod, disabled: disabled, tid: tid, - uid: uid + uid: uid, }, callback); }); }; @@ -69,7 +68,7 @@ module.exports = function (privileges) { }, function (cid, next) { privileges.categories.can(privilege, cid, uid, next); - } + }, ], callback); }; @@ -94,7 +93,6 @@ module.exports = function (privileges) { privileges.categories.getBase(privilege, cids, uid, next); }, function (results, next) { - var isModOf = {}; cids = cids.filter(function (cid, index) { isModOf[cid] = results.isModerators[index]; @@ -112,11 +110,11 @@ module.exports = function (privileges) { plugins.fireHook('filter:privileges.topics.filter', { privilege: privilege, uid: uid, - tids: tids + tids: tids, }, function (err, data) { next(err, data ? data.tids : null); }); - } + }, ], callback); }; @@ -146,7 +144,7 @@ module.exports = function (privileges) { }, isAdmins: function (next) { user.isAdministrator(uids, next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -159,7 +157,7 @@ module.exports = function (privileges) { next(null, uids); }); - } + }, ], callback); }; @@ -172,12 +170,12 @@ module.exports = function (privileges) { async.parallel({ purge: async.apply(privileges.categories.isUserAllowedTo, 'purge', cid, uid), owner: async.apply(topics.isOwner, tid, uid), - isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid) + isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid), }, next); }, function (results, next) { next(null, results.isAdminOrMod || (results.purge && results.owner)); - } + }, ], callback); }; @@ -193,9 +191,9 @@ module.exports = function (privileges) { isModerator: async.apply(user.isModerator, uid, topicData.cid), isAdministrator: async.apply(user.isAdministrator, uid), isOwner: async.apply(topics.isOwner, tid, uid), - 'topics:delete': async.apply(helpers.isUserAllowedTo, 'topics:delete', uid, [topicData.cid]) + 'topics:delete': async.apply(helpers.isUserAllowedTo, 'topics:delete', uid, [topicData.cid]), }, next); - } + }, ], function (err, results) { if (err) { return callback(err); @@ -232,7 +230,7 @@ module.exports = function (privileges) { }, function (next) { privileges.topics.isAdminOrMod(tid, uid, next); - } + }, ], callback); }; @@ -249,7 +247,7 @@ module.exports = function (privileges) { }, function (next) { user.isAdministrator(uid, next); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/privileges/users.js b/src/privileges/users.js index 82553647a4..ed72efb147 100644 --- a/src/privileges/users.js +++ b/src/privileges/users.js @@ -7,7 +7,6 @@ var groups = require('../groups'); var plugins = require('../plugins'); module.exports = function (privileges) { - privileges.users = {}; privileges.users.isAdministrator = function (uid, callback) { @@ -29,18 +28,16 @@ module.exports = function (privileges) { privileges.users.isModerator = function (uid, cid, callback) { if (Array.isArray(cid)) { isModeratorOfCategories(cid, uid, callback); + } else if (Array.isArray(uid)) { + isModeratorsOfCategory(cid, uid, callback); } else { - if (Array.isArray(uid)) { - isModeratorsOfCategory(cid, uid, callback); - } else { - isModeratorOfCategory(cid, uid, callback); - } + isModeratorOfCategory(cid, uid, callback); } }; function isModeratorOfCategories(cids, uid, callback) { if (!parseInt(uid, 10)) { - return filterIsModerator(cids, uid, cids.map(function () {return false;}), callback); + return filterIsModerator(cids, uid, cids.map(function () { return false; }), callback); } privileges.users.isGlobalModerator(uid, function (err, isGlobalModerator) { @@ -48,7 +45,7 @@ module.exports = function (privileges) { return callback(err); } if (isGlobalModerator) { - return filterIsModerator(cids, uid, cids.map(function () {return true;}), callback); + return filterIsModerator(cids, uid, cids.map(function () { return true; }), callback); } @@ -66,16 +63,16 @@ module.exports = function (privileges) { async.parallel({ user: async.apply(groups.isMemberOfGroups, uid, groupNames), - group: async.apply(groups.isMemberOfGroupsList, uid, groupListNames) + group: async.apply(groups.isMemberOfGroupsList, uid, groupListNames), }, function (err, checks) { if (err) { return callback(err); } var isMembers = checks.user.map(function (isMember, idx) { - return isMember || checks.group[idx]; - }), - map = {}; + return isMember || checks.group[idx]; + }); + var map = {}; uniqueCids.forEach(function (cid, index) { map[cid] = isMembers[index]; @@ -94,7 +91,7 @@ module.exports = function (privileges) { async.parallel([ async.apply(privileges.users.isGlobalModerator, uids), async.apply(groups.isMembers, uids, 'cid:' + cid + ':privileges:mods'), - async.apply(groups.isMembersOfGroupList, uids, 'cid:' + cid + ':privileges:groups:moderate') + async.apply(groups.isMembersOfGroupList, uids, 'cid:' + cid + ':privileges:groups:moderate'), ], function (err, checks) { if (err) { return callback(err); @@ -112,7 +109,7 @@ module.exports = function (privileges) { async.parallel([ async.apply(privileges.users.isGlobalModerator, uid), async.apply(groups.isMember, uid, 'cid:' + cid + ':privileges:mods'), - async.apply(groups.isMemberOfGroupList, uid, 'cid:' + cid + ':privileges:groups:moderate') + async.apply(groups.isMemberOfGroupList, uid, 'cid:' + cid + ':privileges:groups:moderate'), ], function (err, checks) { if (err) { return callback(err); @@ -124,11 +121,11 @@ module.exports = function (privileges) { } function filterIsModerator(cid, uid, isModerator, callback) { - plugins.fireHook('filter:user.isModerator', {uid: uid, cid: cid, isModerator: isModerator}, function (err, data) { + plugins.fireHook('filter:user.isModerator', { uid: uid, cid: cid, isModerator: isModerator }, function (err, data) { if (err) { return callback(err); } - if (Array.isArray(uid) && !Array.isArray(data.isModerator) || Array.isArray(cid) && !Array.isArray(data.isModerator)) { + if ((Array.isArray(uid) || Array.isArray(cid)) && !Array.isArray(data.isModerator)) { return callback(new Error('filter:user.isModerator - i/o mismatch')); } @@ -150,7 +147,7 @@ module.exports = function (privileges) { }, isTargetAdmin: function (next) { privileges.users.isAdministrator(uid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -160,5 +157,4 @@ module.exports = function (privileges) { callback(null, canEdit); }); }; - -}; \ No newline at end of file +}; diff --git a/src/pubsub.js b/src/pubsub.js index f5c6c2f0ed..b33a03b6bf 100644 --- a/src/pubsub.js +++ b/src/pubsub.js @@ -26,7 +26,7 @@ var PubSub = function () { try { var msg = JSON.parse(message); self.emit(msg.event, msg.data); - } catch(err) { + } catch (err) { winston.error(err.stack); } }); @@ -37,7 +37,7 @@ util.inherits(PubSub, EventEmitter); PubSub.prototype.publish = function (event, data) { if (this.pubClient) { - this.pubClient.publish(channelName, JSON.stringify({event: event, data: data})); + this.pubClient.publish(channelName, JSON.stringify({ event: event, data: data })); } else { this.emit(event, data); } @@ -45,4 +45,4 @@ PubSub.prototype.publish = function (event, data) { var pubsub = new PubSub(); -module.exports = pubsub; \ No newline at end of file +module.exports = pubsub; diff --git a/src/reset.js b/src/reset.js index d237059f8e..f709c4188b 100644 --- a/src/reset.js +++ b/src/reset.js @@ -82,15 +82,15 @@ function resetSettings(callback) { function resetTheme(themeId, callback) { var meta = require('./meta'); var fs = require('fs'); - - fs.access('node_modules/' + themeId + '/package.json', function (err, fd) { + + fs.access('node_modules/' + themeId + '/package.json', function (err) { if (err) { winston.warn('[reset] Theme `%s` is not installed on this forum', themeId); callback(new Error('theme-not-found')); } else { meta.themes.set({ type: 'local', - id: themeId + id: themeId, }, function (err) { if (err) { winston.warn('[reset] Failed to reset theme to ' + themeId); @@ -99,7 +99,7 @@ function resetTheme(themeId, callback) { } callback(); - }); + }); } }); } @@ -109,7 +109,7 @@ function resetThemes(callback) { meta.themes.set({ type: 'local', - id: 'nodebb-theme-persona' + id: 'nodebb-theme-persona', }, function (err) { winston.info('[reset] Theme reset to Persona'); callback(err); @@ -129,18 +129,16 @@ function resetPlugin(pluginId, callback) { } else { next(); } - } + }, ], function (err) { if (err) { winston.error('[reset] Could not disable plugin: %s encountered error %s', pluginId, err.message); + } else if (active) { + winston.info('[reset] Plugin `%s` disabled', pluginId); } else { - if (active) { - winston.info('[reset] Plugin `%s` disabled', pluginId); - } else { - winston.warn('[reset] Plugin `%s` was not active on this forum', pluginId); - winston.info('[reset] No action taken.'); - err = new Error('plugin-not-active'); - } + winston.warn('[reset] Plugin `%s` was not active on this forum', pluginId); + winston.info('[reset] No action taken.'); + err = new Error('plugin-not-active'); } callback(err); @@ -161,4 +159,4 @@ function resetWidgets(callback) { }); } -module.exports = Reset; \ No newline at end of file +module.exports = Reset; diff --git a/src/rewards/admin.js b/src/rewards/admin.js index ec5a26d5aa..60f335ef86 100644 --- a/src/rewards/admin.js +++ b/src/rewards/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var plugins = require('../plugins'); @@ -7,9 +7,7 @@ var db = require('../database'); var rewards = module.exports; rewards.save = function (data, callback) { - async.each(data, function save(data, next) { - if (!Object.keys(data.rewards).length) { return next(); } @@ -26,7 +24,6 @@ rewards.save = function (data, callback) { } }, function (rid, next) { - data.id = rid; async.series([ @@ -41,11 +38,10 @@ rewards.save = function (data, callback) { }, function (next) { db.setObject('rewards:id:' + data.id + ':rewards', rewardsData, next); - } + }, ], next); - } + }, ], next); - }, function (err) { if (err) { return callback(err); @@ -65,7 +61,7 @@ rewards.delete = function (data, callback) { }, function (next) { db.delete('rewards:id:' + data.id + ':rewards', next); - } + }, ], callback); }; @@ -80,7 +76,7 @@ rewards.get = function (callback) { }, rewards: function (next) { plugins.fireHook('filter:rewards.rewards', [], next); - } + }, }, callback); }; @@ -105,7 +101,7 @@ function saveConditions(data, callback) { async.each(Object.keys(rewardsPerCondition), function (condition, next) { db.setAdd('condition:' + condition + ':rewards', rewardsPerCondition[condition], next); }, next); - } + }, ], function (err) { callback(err); }); @@ -121,7 +117,7 @@ function getActiveRewards(callback) { }, rewards: function (next) { db.getObject('rewards:id:' + id + ':rewards', next); - } + }, }, function (err, data) { if (data.main) { data.main.disabled = data.main.disabled === 'true'; diff --git a/src/rewards/index.js b/src/rewards/index.js index e2bc024f13..38105dd5ff 100644 --- a/src/rewards/index.js +++ b/src/rewards/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var db = require('../database'); @@ -44,7 +44,7 @@ rewards.checkConditionAndRewardUser = function (uid, condition, method, callback giveRewards(uid, eligible, next); }); - } + }, ], callback); }; @@ -100,7 +100,7 @@ function checkCondition(reward, method, callback) { return callback(err); } - plugins.fireHook('filter:rewards.checkConditional:' + reward.conditional, {left: value, right: reward.value}, function (err, bool) { + plugins.fireHook('filter:rewards.checkConditional:' + reward.conditional, { left: value, right: reward.value }, function (err, bool) { callback(err || bool); }); }); @@ -113,7 +113,7 @@ function giveRewards(uid, rewards, callback) { } async.each(rewards, function (reward, next) { - plugins.fireHook('action:rewards.award:' + reward.rid, {uid: uid, reward: rewardData[rewards.indexOf(reward)]}); + plugins.fireHook('action:rewards.award:' + reward.rid, { uid: uid, reward: rewardData[rewards.indexOf(reward)] }); db.sortedSetIncrBy('uid:' + uid + ':rewards', 1, reward.id, next); }, callback); }); diff --git a/src/routes/accounts.js b/src/routes/accounts.js index ae80b8aa4a..a462399b40 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var helpers = require('./helpers'); var setupPageRoute = helpers.setupPageRoute; diff --git a/src/routes/admin.js b/src/routes/admin.js index 0611eede70..35ad84203d 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var express = require('express'); diff --git a/src/routes/api.js b/src/routes/api.js index 98c884c237..9b5a7f77c7 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -1,28 +1,27 @@ -"use strict"; +'use strict'; var express = require('express'); var uploadsController = require('../controllers/uploads'); -module.exports = function (app, middleware, controllers) { - +module.exports = function (app, middleware, controllers) { var router = express.Router(); app.use('/api', router); router.get('/config', middleware.applyCSRF, controllers.api.getConfig); router.get('/widgets/render', controllers.api.renderWidgets); - router.get('/me', middleware.checkGlobalPrivacySettings, controllers.api.getCurrentUser); - router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.api.getUserByUID); - router.get('/user/username/:username', middleware.checkGlobalPrivacySettings, controllers.api.getUserByUsername); - router.get('/user/email/:email', middleware.checkGlobalPrivacySettings, controllers.api.getUserByEmail); + router.get('/me', middleware.checkGlobalPrivacySettings, controllers.user.getCurrentUser); + router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUID); + router.get('/user/username/:username', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUsername); + router.get('/user/email/:email', middleware.checkGlobalPrivacySettings, controllers.user.getUserByEmail); router.get('/:type/pid/:id', controllers.api.getObject); router.get('/:type/tid/:id', controllers.api.getObject); router.get('/:type/cid/:id', controllers.api.getObject); router.get('/categories/:cid/moderators', controllers.api.getModerators); - router.get('/recent/posts/:term?', controllers.api.getRecentPosts); + router.get('/recent/posts/:term?', controllers.posts.getRecentPosts); router.get('/unread/:filter?/total', middleware.authenticate, controllers.unread.unreadTotal); router.get('/topic/teaser/:topic_id', controllers.topics.teaser); router.get('/topic/pagination/:topic_id', controllers.topics.pagination); @@ -36,6 +35,5 @@ module.exports = function (app, middleware, controllers) { router.post('/user/:userslug/uploadcover', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadCoverPicture); router.post('/groups/uploadpicture', middlewares.concat([middleware.authenticate]), controllers.groups.uploadCover); - }; diff --git a/src/routes/authentication.js b/src/routes/authentication.js index c6f1359fc2..0e1d2aa6e2 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -1,17 +1,17 @@ +'use strict'; + (function (Auth) { - "use strict"; + var passport = require('passport'); + var passportLocal = require('passport-local').Strategy; + var nconf = require('nconf'); + var winston = require('winston'); + var express = require('express'); - var passport = require('passport'), - passportLocal = require('passport-local').Strategy, - nconf = require('nconf'), - winston = require('winston'), - express = require('express'), + var controllers = require('../controllers'); + var plugins = require('../plugins'); + var hotswap = require('../hotswap'); - controllers = require('../controllers'), - plugins = require('../plugins'), - hotswap = require('../hotswap'), - - loginStrategies = []; + var loginStrategies = []; Auth.initialize = function (app, middleware) { app.use(passport.initialize()); @@ -40,7 +40,7 @@ winston.warn('[authentication] Login override detected, skipping local login strategy.'); plugins.fireHook('action:auth.overrideLogin'); } else { - passport.use(new passportLocal({passReqToCallback: true}, controllers.authentication.localLogin)); + passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin)); } plugins.fireHook('filter:auth.init', loginStrategies, function (err) { @@ -53,13 +53,13 @@ if (strategy.url) { router.get(strategy.url, passport.authenticate(strategy.name, { scope: strategy.scope, - prompt: strategy.prompt || undefined + prompt: strategy.prompt || undefined, })); } router.get(strategy.callbackURL, passport.authenticate(strategy.name, { successReturnToOrRedirect: nconf.get('relative_path') + (strategy.successUrl !== undefined ? strategy.successUrl : '/'), - failureRedirect: nconf.get('relative_path') + (strategy.failureUrl !== undefined ? strategy.failureUrl : '/login') + failureRedirect: nconf.get('relative_path') + (strategy.failureUrl !== undefined ? strategy.failureUrl : '/login'), })); }); @@ -82,8 +82,7 @@ passport.deserializeUser(function (uid, done) { done(null, { - uid: uid + uid: uid, }); }); - }(exports)); diff --git a/src/routes/debug.js b/src/routes/debug.js index 9c5efe6c93..2ec3f23934 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var express = require('express'); var nconf = require('nconf'); @@ -7,9 +7,8 @@ var user = require('../user'); var categories = require('../categories'); var topics = require('../topics'); var posts = require('../posts'); -var db = require('../database'); -module.exports = function (app, middleware, controllers) { +module.exports = function (app) { var router = express.Router(); router.get('/uid/:uid', function (req, res) { @@ -26,7 +25,7 @@ module.exports = function (app, middleware, controllers) { res.send(data); } else { res.status(404).json({ - error: "User doesn't exist!" + error: "User doesn't exist!", }); } }); diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 9521e65ce8..5e3d75c34d 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var rss = require('rss'); @@ -13,7 +13,7 @@ var meta = require('../meta'); var helpers = require('../controllers/helpers'); var privileges = require('../privileges'); -module.exports = function (app, middleware, controllers) { +module.exports = function (app, middleware) { app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic); app.get('/category/:category_id.rss', middleware.maintenanceMode, generateForCategory); app.get('/recent.rss', middleware.maintenanceMode, generateForRecent); @@ -41,7 +41,7 @@ function generateForTopic(req, res, callback) { }, topic: function (next) { topics.getTopicData(tid, next); - } + }, }, next); }, function (results, next) { @@ -56,7 +56,7 @@ function generateForTopic(req, res, callback) { } userPrivileges = results.privileges; topics.getTopicWithPosts(results.topic, 'tid:' + tid + ':posts', req.uid, 0, 25, false, next); - } + }, ], function (err, topicData) { if (err) { return callback(err); @@ -75,7 +75,7 @@ function generateForTopic(req, res, callback) { site_url: nconf.get('url') + '/topic/' + topicData.slug, image_url: image_url, author: author, - ttl: 60 + ttl: 60, }); var dateStamp; @@ -92,7 +92,7 @@ function generateForTopic(req, res, callback) { description: postData.content, url: nconf.get('url') + '/post/' + postData.pid, author: postData.user ? postData.user.username : '', - date: dateStamp + date: dateStamp, }); } }); @@ -117,7 +117,7 @@ function generateForUserTopics(req, res, callback) { return callback(); } user.getUserFields(uid, ['uid', 'username'], next); - } + }, ], function (err, userData) { if (err) { return callback(err); @@ -128,7 +128,7 @@ function generateForUserTopics(req, res, callback) { title: 'Topics by ' + userData.username, description: 'A list of topics that are posted by ' + userData.username, feed_url: '/user/' + userslug + '/topics.rss', - site_url: '/user/' + userslug + '/topics' + site_url: '/user/' + userslug + '/topics', }, 'uid:' + userData.uid + ':topics', req, res, callback); }); } @@ -152,9 +152,9 @@ function generateForCategory(req, res, next) { reverse: true, start: 0, stop: 25, - uid: req.uid + uid: req.uid, }, next); - } + }, }, next); }, function (results, next) { @@ -168,7 +168,7 @@ function generateForCategory(req, res, next) { feed_url: '/category/' + cid + '.rss', site_url: '/category/' + results.category.cid, }, results.category.topics, next); - } + }, ], function (err, feed) { if (err) { return next(err); @@ -186,7 +186,7 @@ function generateForRecent(req, res, next) { title: 'Recently Active Topics', description: 'A list of topics that have been active within the past 24 hours', feed_url: '/recent.rss', - site_url: '/recent' + site_url: '/recent', }, 'topics:recent', req, res, next); } @@ -198,7 +198,7 @@ function generateForPopular(req, res, next) { daily: 'day', weekly: 'week', monthly: 'month', - alltime: 'alltime' + alltime: 'alltime', }; var term = terms[req.params.term] || 'day'; @@ -212,9 +212,9 @@ function generateForPopular(req, res, next) { title: 'Popular Topics', description: 'A list of topics that are sorted by post count', feed_url: '/popular/' + (req.params.term || 'daily') + '.rss', - site_url: '/popular/' + (req.params.term || 'daily') + site_url: '/popular/' + (req.params.term || 'daily'), }, topics, next); - } + }, ], function (err, feed) { if (err) { return next(err); @@ -232,7 +232,7 @@ function generateForTopics(options, set, req, res, next) { }, function (data, next) { generateTopicsFeed(options, data.topics, next); - } + }, ], function (err, feed) { if (err) { return next(err); @@ -242,7 +242,6 @@ function generateForTopics(options, set, req, res, next) { } function generateTopicsFeed(feedOptions, feedTopics, callback) { - feedOptions.ttl = 60; feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; feedOptions.site_url = nconf.get('url') + feedOptions.site_url; @@ -259,7 +258,7 @@ function generateTopicsFeed(feedOptions, feedTopics, callback) { var feedItem = { title: topicData.title, url: nconf.get('url') + '/topic/' + topicData.slug, - date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() + date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString(), }; if (topicData.teaser && topicData.teaser.user) { @@ -306,7 +305,7 @@ function generateForRecentPosts(req, res, next) { title: 'Recent Posts', description: 'A list of recent posts', feed_url: '/recentposts.rss', - site_url: '/recentposts' + site_url: '/recentposts', }, posts); sendFeed(feed, res); @@ -328,7 +327,7 @@ function generateForCategoryRecentPosts(req, res, next) { }, posts: function (next) { categories.getRecentReplies(cid, req.uid, 20, next); - } + }, }, function (err, results) { if (err) { return next(err); @@ -345,7 +344,7 @@ function generateForCategoryRecentPosts(req, res, next) { title: results.category.name + ' Recent Posts', description: 'A list of recent posts from ' + results.category.name, feed_url: '/category/' + cid + '/recentposts.rss', - site_url: '/category/' + cid + '/recentposts' + site_url: '/category/' + cid + '/recentposts', }, results.posts); sendFeed(feed, res); @@ -369,7 +368,7 @@ function generateForPostsFeed(feedOptions, posts) { description: postData.content, url: nconf.get('url') + '/post/' + postData.pid, author: postData.user ? postData.user.username : '', - date: new Date(parseInt(postData.timestamp, 10)).toUTCString() + date: new Date(parseInt(postData.timestamp, 10)).toUTCString(), }); }); @@ -392,7 +391,7 @@ function generateForTag(req, res, next) { feed_url: '/tags/' + tag + '.rss', site_url: '/tags/' + tag, start: start, - stop: stop + stop: stop, }, 'tag:' + tag + ':topics', req, res, next); } @@ -401,4 +400,3 @@ function sendFeed(feed, res) { res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml); } - diff --git a/src/routes/helpers.js b/src/routes/helpers.js index 2379c7ebf1..8452b7f6d9 100644 --- a/src/routes/helpers.js +++ b/src/routes/helpers.js @@ -9,4 +9,4 @@ helpers.setupPageRoute = function (router, name, middleware, middlewares, contro router.get('/api' + name, middlewares, controller); }; -module.exports = helpers; \ No newline at end of file +module.exports = helpers; diff --git a/src/routes/index.js b/src/routes/index.js index b49a429420..57b1d5c942 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var nconf = require('nconf'); var winston = require('winston'); @@ -85,11 +85,11 @@ function groupRoutes(app, middleware, controllers) { setupPageRoute(app, '/groups/:slug/members', middleware, middlewares, controllers.groups.members); } -module.exports = function (app, middleware, hotswapIds) { +module.exports = function (app, middleware, hotswapIds, callback) { var routers = [ express.Router(), // plugin router express.Router(), // main app router - express.Router() // auth router + express.Router(), // auth router ]; var router = routers[1]; var pluginRouter = routers[0]; @@ -97,8 +97,11 @@ module.exports = function (app, middleware, hotswapIds) { var relativePath = nconf.get('relative_path'); var ensureLoggedIn = require('connect-ensure-login'); + var idx; + var x; + if (Array.isArray(hotswapIds) && hotswapIds.length) { - for(var idx,x = 0; x < hotswapIds.length; x++) { + for (x = 0; x < hotswapIds.length; x += 1) { idx = routers.push(express.Router()) - 1; routers[idx].hotswapId = hotswapIds[x]; } @@ -132,7 +135,7 @@ module.exports = function (app, middleware, hotswapIds) { userRoutes(router, middleware, controllers); groupRoutes(router, middleware, controllers); - for(var x = 0; x < routers.length; x++) { + for (x = 0; x < routers.length; x += 1) { app.use(relativePath, routers[x]); } @@ -154,7 +157,7 @@ module.exports = function (app, middleware, hotswapIds) { if (path.resolve(__dirname, '../../public/uploads') !== nconf.get('upload_path')) { statics.unshift({ route: '/assets/uploads', path: nconf.get('upload_path') }); } - + statics.forEach(function (obj) { app.use(relativePath + obj.route, express.static(obj.path, staticOptions)); }); @@ -180,7 +183,7 @@ module.exports = function (app, middleware, hotswapIds) { ]; app.use(relativePath, function (req, res, next) { if (deprecatedPaths.some(function (path) { return req.path.startsWith(path); })) { - winston.warn('[deprecated] Accessing `' + req.path.slice(1) + '` from `/` is deprecated. ' + + winston.warn('[deprecated] Accessing `' + req.path.slice(1) + '` from `/` is deprecated. ' + 'Use `/assets' + req.path + '` to access this file.'); res.redirect(relativePath + '/assets' + req.path + '?' + meta.config['cache-buster']); } else { @@ -195,19 +198,20 @@ module.exports = function (app, middleware, hotswapIds) { }); app.use(relativePath + '/assets/vendor/jquery/timeago/locales', middleware.processTimeagoLocales); - app.use(controllers.handle404); - app.use(controllers.handleURIErrors); - app.use(controllers.handleErrors); + app.use(controllers['404'].handle404); + app.use(controllers.errors.handleURIErrors); + app.use(controllers.errors.handleErrors); // Add plugin routes async.series([ async.apply(plugins.reloadRoutes), async.apply(authRoutes.reloadRoutes), - async.apply(user.addInterstitials) + async.apply(user.addInterstitials), ], function (err) { if (err) { - return winston.error(err); + return callback(err); } winston.info('Routes added'); + callback(); }); }; diff --git a/src/routes/meta.js b/src/routes/meta.js index cb089f1200..de0bb52406 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; module.exports = function (app, middleware, controllers) { app.get('/sitemap.xml', controllers.sitemap.render); @@ -8,4 +8,5 @@ module.exports = function (app, middleware, controllers) { app.get('/robots.txt', controllers.robots); app.get('/manifest.json', controllers.manifest); app.get('/css/previews/:theme', controllers.admin.themes.get); + app.get('/osd.xml', controllers.osd.handle); }; diff --git a/src/search.js b/src/search.js index d77b1f58f0..ffe33c8ef5 100644 --- a/src/search.js +++ b/src/search.js @@ -17,7 +17,6 @@ var search = {}; module.exports = search; search.search = function (data, callback) { - var start = process.hrtime(); var searchIn = data.searchIn || 'titlesposts'; @@ -37,7 +36,7 @@ search.search = function (data, callback) { result.search_query = validator.escape(String(data.query || '')); result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2); next(null, result); - } + }, ], callback); }; @@ -49,7 +48,7 @@ function searchInContent(data, callback) { }, searchUids: function (next) { getSearchUids(data, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -69,7 +68,7 @@ function searchInContent(data, callback) { } else { next(null, []); } - } + }, }, function (err, results) { if (err) { return callback(err); @@ -77,7 +76,7 @@ function searchInContent(data, callback) { var matchCount = 0; if (!results || (!results.pids.length && !results.tids.length)) { - return callback(null, {posts: [], matchCount: matchCount, pageCount: 1}); + return callback(null, { posts: [], matchCount: matchCount, pageCount: 1 }); } async.waterfall([ @@ -106,8 +105,8 @@ function searchInContent(data, callback) { posts.getPostSummaryByPids(pids, data.uid, {}, next); }, function (posts, next) { - next(null, {posts: posts, matchCount: matchCount, pageCount: Math.max(1, Math.ceil(parseInt(matchCount, 10) / 10))}); - } + next(null, { posts: posts, matchCount: matchCount, pageCount: Math.max(1, Math.ceil(parseInt(matchCount, 10) / 10)) }); + }, ], callback); }); }); @@ -227,9 +226,9 @@ function getMatchedPosts(pids, data, callback) { } else { setImmediate(next); } - } + }, }, next); - } + }, ], function (err, results) { if (err) { return next(err); @@ -249,11 +248,10 @@ function getMatchedPosts(pids, data, callback) { next(null, topicsData); }); - } + }, }, next); }, function (results, next) { - posts.forEach(function (post, index) { if (results.topics && results.topics[index]) { post.topic = results.topics[index]; @@ -275,7 +273,7 @@ function getMatchedPosts(pids, data, callback) { }); next(null, posts); - } + }, ], callback); } @@ -296,7 +294,7 @@ function filterByPostcount(posts, postCount, repliesFilter) { } function filterByTimerange(posts, timeRange, timeFilter) { - timeRange = parseInt(timeRange) * 1000; + timeRange = parseInt(timeRange, 10) * 1000; if (timeRange) { var time = Date.now() - timeRange; if (timeFilter === 'newer') { @@ -380,7 +378,7 @@ function getSearchCids(data, callback) { }, function (cids, next) { privileges.categories.filterCids('read', cids, data.uid, next); - } + }, ], callback); return; } @@ -399,7 +397,7 @@ function getSearchCids(data, callback) { } else { next(null, []); } - } + }, }, function (err, results) { if (err) { return callback(err); @@ -424,10 +422,10 @@ function getChildrenCids(cids, uid, callback) { childrenCategories.forEach(function (childrens) { categories.flattenCategories(allCategories, childrens); - childrenCids = childrenCids.concat(allCategories.map(function (category) { - return category && category.cid; - })); - }); + childrenCids = childrenCids.concat(allCategories.map(function (category) { + return category && category.cid; + })); + }); callback(null, childrenCids); }); @@ -446,7 +444,7 @@ search.searchQuery = function (index, content, cids, uids, callback) { index: index, content: content, cid: cids, - uid: uids + uid: uids, }, callback); }; diff --git a/src/settings.js b/src/settings.js index 6f6cad2854..b9642c0dce 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1,9 +1,13 @@ -"use strict"; +'use strict'; var meta = require('./meta'); function expandObjBy(obj1, obj2) { - var key, val1, val2, xorValIsArray, changed = false; + var key; + var val1; + var val2; + var xorValIsArray; + var changed = false; for (key in obj2) { if (obj2.hasOwnProperty(key)) { val2 = obj2[key]; @@ -23,7 +27,8 @@ function expandObjBy(obj1, obj2) { } function trim(obj1, obj2) { - var key, val1; + var key; + var val1; for (key in obj1) { if (obj1.hasOwnProperty(key)) { val1 = obj1[key]; @@ -106,8 +111,8 @@ Settings.prototype.sync = function (callback) { @param callback Gets called when done. */ Settings.prototype.persist = function (callback) { - var conf = this.cfg._, - _this = this; + var conf = this.cfg._; + var _this = this; if (typeof conf === 'object') { conf = JSON.stringify(conf); } @@ -126,19 +131,19 @@ Settings.prototype.persist = function (callback) { @returns Object The setting to be used. */ Settings.prototype.get = function (key, def) { - var obj = this.cfg._, - parts = (key || '').split('.'), - part; - for (var i = 0; i < parts.length; i++) { + var obj = this.cfg._; + var parts = (key || '').split('.'); + var part; + for (var i = 0; i < parts.length; i += 1) { part = parts[i]; if (part && obj != null) { obj = obj[part]; } } - if (obj === void 0) { - if (def === void 0) { + if (obj === undefined) { + if (def === undefined) { def = this.defCfg; - for (var j = 0; j < parts.length; j++) { + for (var j = 0; j < parts.length; j += 1) { part = parts[j]; if (part && def != null) { def = def[part]; @@ -165,7 +170,7 @@ Settings.prototype.getWrapper = function () { Settings.prototype.createWrapper = function (version, settings) { return { v: version, - _: settings + _: settings, }; }; @@ -183,15 +188,18 @@ Settings.prototype.createDefaultWrapper = function () { @param val The value to set. */ Settings.prototype.set = function (key, val) { - var part, obj, parts; + var part; + var obj; + var parts; this.cfg.v = this.version; if (val == null || !key) { this.cfg._ = val || key; } else { obj = this.cfg._; parts = key.split('.'); - for (var i = 0, _len = parts.length - 1; i < _len; i++) { - if (part = parts[i]) { + for (var i = 0, _len = parts.length - 1; i < _len; i += 1) { + part = parts[i]; + if (part) { if (!obj.hasOwnProperty(part)) { obj[part] = {}; } diff --git a/src/sitemap.js b/src/sitemap.js index ec068d71d3..d6f6fa39fe 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -14,23 +14,23 @@ var utils = require('../public/src/utils'); var sitemap = { maps: { - topics: [] - } + topics: [], + }, }; sitemap.render = function (callback) { var numTopics = parseInt(meta.config.sitemapTopics, 10) || 500; var returnData = { - url: nconf.get('url'), - topics: [] - }; + url: nconf.get('url'), + topics: [], + }; var numPages; async.waterfall([ async.apply(db.getSortedSetRange, 'topics:recent', 0, -1), function (tids, next) { privileges.topics.filterTids('read', tids, 0, next); - } + }, ], function (err, tids) { if (err) { numPages = 1; @@ -38,7 +38,7 @@ sitemap.render = function (callback) { numPages = Math.ceil(tids.length / numTopics); } - for(var x = 1; x <= numPages; x++) { + for (var x = 1; x <= numPages; x += 1) { returnData.topics.push(x); } @@ -55,31 +55,31 @@ sitemap.getPages = function (callback) { } var urls = [{ - url: '', - changefreq: 'weekly', - priority: 0.6 - }, { - url: '/recent', - changefreq: 'daily', - priority: 0.4 - }, { - url: '/users', - changefreq: 'daily', - priority: 0.4 - }, { - url: '/groups', - changefreq: 'daily', - priority: 0.4 - }]; + url: '', + changefreq: 'weekly', + priority: 0.6, + }, { + url: '/recent', + changefreq: 'daily', + priority: 0.4, + }, { + url: '/users', + changefreq: 'daily', + priority: 0.4, + }, { + url: '/groups', + changefreq: 'daily', + priority: 0.4, + }]; - plugins.fireHook('filter:sitemap.getPages', {urls: urls}, function (err, data) { + plugins.fireHook('filter:sitemap.getPages', { urls: urls }, function (err, data) { if (err) { return callback(err); } sitemap.maps.pages = sm.createSitemap({ hostname: nconf.get('url'), cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours - urls: data.urls + urls: data.urls, }); sitemap.maps.pages.toXML(callback); @@ -105,7 +105,7 @@ sitemap.getCategories = function (callback) { categoryUrls.push({ url: '/category/' + category.slug, changefreq: 'weekly', - priority: 0.4 + priority: 0.4, }); } }); @@ -113,7 +113,7 @@ sitemap.getCategories = function (callback) { sitemap.maps.categories = sm.createSitemap({ hostname: nconf.get('url'), cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours - urls: categoryUrls + urls: categoryUrls, }); sitemap.maps.categories.toXML(callback); @@ -147,7 +147,7 @@ sitemap.getTopicPage = function (page, callback) { }, function (tids, next) { topics.getTopicsFields(tids, ['tid', 'title', 'slug', 'lastposttime'], next); - } + }, ], function (err, topics) { if (err) { return callback(err); @@ -159,7 +159,7 @@ sitemap.getTopicPage = function (page, callback) { url: '/topic/' + topic.slug, lastmodISO: utils.toISOString(topic.lastposttime), changefreq: 'daily', - priority: 0.6 + priority: 0.6, }); } }); @@ -167,7 +167,7 @@ sitemap.getTopicPage = function (page, callback) { sitemap.maps.topics[page - 1] = sm.createSitemap({ hostname: nconf.get('url'), cacheTime: 1000 * 60 * 60, // Cached for 1 hour - urls: topicUrls + urls: topicUrls, }); sitemap.maps.topics[page - 1].toXML(callback); diff --git a/src/social.js b/src/social.js index 0c71daadba..71780b5b81 100644 --- a/src/social.js +++ b/src/social.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var plugins = require('./plugins'); var db = require('./database'); @@ -15,20 +15,20 @@ social.getPostSharing = function (callback) { var networks = [ { - id: "facebook", - name: "Facebook", - class: "fa-facebook" + id: 'facebook', + name: 'Facebook', + class: 'fa-facebook', }, { - id: "twitter", - name: "Twitter", - class: "fa-twitter" + id: 'twitter', + name: 'Twitter', + class: 'fa-twitter', }, { - id: "google", - name: "Google+", - class: "fa-google-plus" - } + id: 'google', + name: 'Google+', + class: 'fa-google-plus', + }, ]; async.waterfall([ @@ -48,7 +48,7 @@ social.getPostSharing = function (callback) { social.postSharing = networks; next(null, networks); }); - } + }, ], callback); }; @@ -78,8 +78,8 @@ social.setActivePostSharingNetworks = function (networkIDs, callback) { function (next) { social.postSharing = null; next(); - } + }, ], callback); }; -module.exports = social; \ No newline at end of file +module.exports = social; diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 987f607ec9..9eba77f39b 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -33,7 +33,7 @@ var SocketAdmin = { email: {}, analytics: {}, logs: {}, - errors: {} + errors: {}, }; SocketAdmin.before = function (socket, method, data, next) { @@ -50,7 +50,7 @@ SocketAdmin.reload = function (socket, data, callback) { events.log({ type: 'restart', uid: socket.uid, - ip: socket.ip + ip: socket.ip, }); meta.restart(); callback(); @@ -65,13 +65,13 @@ SocketAdmin.restart = function (socket, data, callback) { events.log({ type: 'build', uid: socket.uid, - ip: socket.ip + ip: socket.ip, }); events.log({ type: 'restart', uid: socket.uid, - ip: socket.ip + ip: socket.ip, }); meta.restart(); @@ -93,17 +93,18 @@ SocketAdmin.themes.set = function (socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - var wrappedCallback = function (err) { - if (err) { - return callback(err); - } - meta.themes.set(data, callback); - }; - if (data.type === 'bootswatch') { - wrappedCallback(); - } else { - widgets.reset(wrappedCallback); - } + async.waterfall([ + function (next) { + if (data.type === 'bootswatch') { + setImmediate(next); + } else { + widgets.reset(next); + } + }, + function (next) { + meta.themes.set(data, next); + }, + ], callback); }; SocketAdmin.plugins.toggleActive = function (socket, plugin_id, callback) { @@ -125,7 +126,7 @@ SocketAdmin.plugins.orderActivePlugins = function (socket, data, callback) { if (plugin && plugin.name) { db.sortedSetAdd('plugins:active', plugin.order || 0, plugin.name, next); } else { - next(); + setImmediate(next); } }, callback); }; @@ -148,7 +149,7 @@ SocketAdmin.config.set = function (socket, data, callback) { } var _data = {}; _data[data.key] = data.value; - SocketAdmin.config.setMultiple(socket, data, callback); + SocketAdmin.config.setMultiple(socket, _data, callback); }; SocketAdmin.config.setMultiple = function (socket, data, callback) { @@ -166,14 +167,14 @@ SocketAdmin.config.setMultiple = function (socket, data, callback) { if (data.hasOwnProperty(field)) { setting = { key: field, - value: data[field] + value: data[field], }; plugins.fireHook('action:config.set', setting); - logger.monitorConfig({io: index.server}, setting); + logger.monitorConfig({ io: index.server }, setting); } } setImmediate(next); - } + }, ], callback); }; @@ -199,11 +200,15 @@ SocketAdmin.email.test = function (socket, data, callback) { emailer.send(data.template, socket.uid, { subject: '[' + site_title + '] Test Email', site_title: site_title, - url: nconf.get('url') + url: nconf.get('url'), }, callback); }; SocketAdmin.analytics.get = function (socket, data, callback) { + if (!data || !data.graph || !data.units) { + return callback(new Error('[[error:invalid-data]]')); + } + // Default returns views from past 24 hours, by hour if (data.units === 'days') { data.amount = 30; @@ -211,34 +216,30 @@ SocketAdmin.analytics.get = function (socket, data, callback) { data.amount = 24; } - if (data && data.graph && data.units && data.amount) { - if (data.graph === 'traffic') { - async.parallel({ - uniqueVisitors: function (next) { - if (data.units === 'days') { - analytics.getDailyStatsForSet('analytics:uniquevisitors', data.until || Date.now(), data.amount, next); - } else { - analytics.getHourlyStatsForSet('analytics:uniquevisitors', data.until || Date.now(), data.amount, next); - } - }, - pageviews: function (next) { - if (data.units === 'days') { - analytics.getDailyStatsForSet('analytics:pageviews', data.until || Date.now(), data.amount, next); - } else { - analytics.getHourlyStatsForSet('analytics:pageviews', data.until || Date.now(), data.amount, next); - } - }, - monthlyPageViews: function (next) { - analytics.getMonthlyPageViews(next); + if (data.graph === 'traffic') { + async.parallel({ + uniqueVisitors: function (next) { + if (data.units === 'days') { + analytics.getDailyStatsForSet('analytics:uniquevisitors', data.until || Date.now(), data.amount, next); + } else { + analytics.getHourlyStatsForSet('analytics:uniquevisitors', data.until || Date.now(), data.amount, next); } - }, function (err, data) { - data.pastDay = data.pageviews.reduce(function (a, b) {return parseInt(a, 10) + parseInt(b, 10);}); - data.pageviews[data.pageviews.length - 1] = parseInt(data.pageviews[data.pageviews.length - 1], 10) + analytics.getUnwrittenPageviews(); - callback(err, data); - }); - } - } else { - callback(new Error('Invalid analytics call')); + }, + pageviews: function (next) { + if (data.units === 'days') { + analytics.getDailyStatsForSet('analytics:pageviews', data.until || Date.now(), data.amount, next); + } else { + analytics.getHourlyStatsForSet('analytics:pageviews', data.until || Date.now(), data.amount, next); + } + }, + monthlyPageViews: function (next) { + analytics.getMonthlyPageViews(next); + }, + }, function (err, data) { + data.pastDay = data.pageviews.reduce(function (a, b) { return parseInt(a, 10) + parseInt(b, 10); }); + data.pageviews[data.pageviews.length - 1] = parseInt(data.pageviews[data.pageviews.length - 1], 10) + analytics.getUnwrittenPageviews(); + callback(err, data); + }); } }; @@ -259,13 +260,15 @@ SocketAdmin.deleteAllEvents = function (socket, data, callback) { }; SocketAdmin.getSearchDict = function (socket, data, callback) { - user.getSettings(socket.uid, function (err, settings) { - if (err) { - return callback(err); - } - var lang = settings.userLang || meta.config.defaultLang || 'en-GB'; - getAdminSearchDict(lang, callback); - }); + async.waterfall([ + function (next) { + user.getSettings(socket.uid, next); + }, + function (settings, next) { + var lang = settings.userLang || meta.config.defaultLang || 'en-GB'; + getAdminSearchDict(lang, next); + }, + ], callback); }; SocketAdmin.deleteAllSessions = function (socket, data, callback) { diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index e05f6db36e..50c2061038 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -22,12 +22,12 @@ Categories.getAll = function (socket, data, callback) { async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), async.apply(categories.getCategoriesData), function (categories, next) { - //Hook changes, there is no req, and res - plugins.fireHook('filter:admin.categories.get', {categories: categories}, next); + // Hook changes, there is no req, and res + plugins.fireHook('filter:admin.categories.get', { categories: categories }, next); }, function (result, next) { next(null, categories.getTree(result.categories, 0)); - } + }, ], function (err, categoriesTree) { if (err) { return callback(err); @@ -103,4 +103,4 @@ Categories.copyPrivilegesFrom = function (socket, data, callback) { categories.copyPrivilegesFrom(data.fromCid, data.toCid, callback); }; -module.exports = Categories; \ No newline at end of file +module.exports = Categories; diff --git a/src/socket.io/admin/groups.js b/src/socket.io/admin/groups.js index 6b9e404ae1..fdb50e0561 100644 --- a/src/socket.io/admin/groups.js +++ b/src/socket.io/admin/groups.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var groups = require('../../groups'); @@ -15,7 +15,7 @@ Groups.create = function (socket, data, callback) { groups.create({ name: data.name, description: data.description, - ownerUid: socket.uid + ownerUid: socket.uid, }, callback); }; @@ -33,7 +33,7 @@ Groups.join = function (socket, data, callback) { return next(new Error('[[error:group-already-member]]')); } groups.join(data.groupName, data.uid, next); - } + }, ], callback); }; @@ -55,7 +55,7 @@ Groups.leave = function (socket, data, callback) { return next(new Error('[[error:group-not-member]]')); } groups.leave(data.groupName, data.uid, next); - } + }, ], callback); }; @@ -67,4 +67,4 @@ Groups.update = function (socket, data, callback) { groups.update(data.groupName, data.values, callback); }; -module.exports = Groups; \ No newline at end of file +module.exports = Groups; diff --git a/src/socket.io/admin/navigation.js b/src/socket.io/admin/navigation.js index 2f4d9817b4..807b10ae85 100644 --- a/src/socket.io/admin/navigation.js +++ b/src/socket.io/admin/navigation.js @@ -1,10 +1,10 @@ -"use strict"; +'use strict'; -var navigationAdmin = require('../../navigation/admin'), - SocketNavigation = {}; +var navigationAdmin = require('../../navigation/admin'); +var SocketNavigation = {}; SocketNavigation.save = function (socket, data, callback) { navigationAdmin.save(data, callback); }; -module.exports = SocketNavigation; \ No newline at end of file +module.exports = SocketNavigation; diff --git a/src/socket.io/admin/rewards.js b/src/socket.io/admin/rewards.js index 3d895a5281..8b845a33c1 100644 --- a/src/socket.io/admin/rewards.js +++ b/src/socket.io/admin/rewards.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var rewardsAdmin = require('../../rewards/admin'); var SocketRewards = module.exports; diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index 2f6ab50698..544bdc04da 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -13,7 +13,7 @@ var stats = {}; var totals = {}; var SocketRooms = { stats: stats, - totals: totals + totals: totals, }; @@ -22,7 +22,7 @@ pubsub.on('sync:stats:start', function () { if (err) { return winston.error(err); } - pubsub.publish('sync:stats:end', {stats: stats, id: os.hostname() + ':' + nconf.get('port')}); + pubsub.publish('sync:stats:end', { stats: stats, id: os.hostname() + ':' + nconf.get('port') }); }); }); @@ -66,7 +66,7 @@ SocketRooms.getAll = function (socket, data, callback) { recent: 0, unread: 0, topics: 0, - category: 0 + category: 0, }; for (var instance in stats) { @@ -81,7 +81,7 @@ SocketRooms.getAll = function (socket, data, callback) { totals.users.category += stats[instance].users.category; stats[instance].topics.forEach(function (topic) { - totals.topics[topic.tid] = totals.topics[topic.tid] || {count: 0, tid: topic.tid}; + totals.topics[topic.tid] = totals.topics[topic.tid] || { count: 0, tid: topic.tid }; totals.topics[topic.tid].count += topic.count; }); } @@ -89,7 +89,7 @@ SocketRooms.getAll = function (socket, data, callback) { var topTenTopics = []; Object.keys(totals.topics).forEach(function (tid) { - topTenTopics.push({tid: tid, count: totals.topics[tid].count}); + topTenTopics.push({ tid: tid, count: totals.topics[tid].count }); }); topTenTopics = topTenTopics.sort(function (a, b) { @@ -109,11 +109,11 @@ SocketRooms.getAll = function (socket, data, callback) { topTenTopics.forEach(function (topic, index) { totals.topics[topic.tid] = { value: topic.count || 0, - title: validator.escape(String(titles[index].title)) + title: validator.escape(String(titles[index].title)), }; }); next(null, totals); - } + }, ], callback); }; @@ -123,7 +123,7 @@ SocketRooms.getOnlineUserCount = function (io) { if (io) { for (var key in io.sockets.adapter.rooms) { if (io.sockets.adapter.rooms.hasOwnProperty(key) && key.startsWith('uid_')) { - ++ count; + count += 1; } } } @@ -143,9 +143,9 @@ SocketRooms.getLocalStats = function (callback) { recent: 0, unread: 0, topics: 0, - category: 0 + category: 0, }, - topics: {} + topics: {}, }; if (io) { @@ -165,7 +165,7 @@ SocketRooms.getLocalStats = function (callback) { tid = room.match(/^topic_(\d+)/); if (tid) { socketData.users.topics += roomClients[room].length; - topTenTopics.push({tid: tid[1], count: roomClients[room].length}); + topTenTopics.push({ tid: tid[1], count: roomClients[room].length }); } else if (room.match(/^category/)) { socketData.users.category += roomClients[room].length; } @@ -183,4 +183,4 @@ SocketRooms.getLocalStats = function (callback) { }; -module.exports = SocketRooms; \ No newline at end of file +module.exports = SocketRooms; diff --git a/src/socket.io/admin/social.js b/src/socket.io/admin/social.js index 77227ea760..5f422eff6b 100644 --- a/src/socket.io/admin/social.js +++ b/src/socket.io/admin/social.js @@ -1,10 +1,10 @@ -"use strict"; +'use strict'; -var social = require('../../social'), - SocketSocial = {}; +var social = require('../../social'); +var SocketSocial = {}; SocketSocial.savePostSharingNetworks = function (socket, data, callback) { social.setActivePostSharingNetworks(data, callback); }; -module.exports = SocketSocial; \ No newline at end of file +module.exports = SocketSocial; diff --git a/src/socket.io/admin/tags.js b/src/socket.io/admin/tags.js index 4362159502..8fe50790eb 100644 --- a/src/socket.io/admin/tags.js +++ b/src/socket.io/admin/tags.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var topics = require('../../topics'); diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 87a4c2d2ae..8770381aae 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var validator = require('validator'); @@ -13,7 +13,7 @@ var plugins = require('../../plugins'); var User = {}; User.makeAdmins = function (socket, uids, callback) { - if(!Array.isArray(uids)) { + if (!Array.isArray(uids)) { return callback(new Error('[[error:invalid-data]]')); } @@ -22,7 +22,7 @@ User.makeAdmins = function (socket, uids, callback) { return callback(err); } - for(var i = 0; i < userData.length; i++) { + for (var i = 0; i < userData.length; i += 1) { if (userData[i] && parseInt(userData[i].banned, 10) === 1) { return callback(new Error('[[error:cant-make-banned-users-admin]]')); } @@ -35,7 +35,7 @@ User.makeAdmins = function (socket, uids, callback) { }; User.removeAdmins = function (socket, uids, callback) { - if(!Array.isArray(uids)) { + if (!Array.isArray(uids)) { return callback(new Error('[[error:invalid-data]]')); } @@ -117,7 +117,7 @@ User.sendValidationEmail = function (socket, uids, callback) { next(); } }, next); - } + }, ], callback); }; @@ -177,17 +177,17 @@ function deleteUsers(socket, uids, method, callback) { type: 'user-delete', uid: socket.uid, targetUid: uid, - ip: socket.ip + ip: socket.ip, }, next); }, function (next) { plugins.fireHook('action:user.delete', { callerUid: socket.uid, uid: uid, - ip: socket.ip + ip: socket.ip, }); next(); - } + }, ], next); }, callback); } @@ -196,7 +196,7 @@ User.search = function (socket, data, callback) { var searchData; async.waterfall([ function (next) { - user.search({query: data.query, searchBy: data.searchBy, uid: socket.uid}, next); + user.search({ query: data.query, searchBy: data.searchBy, uid: socket.uid }, next); }, function (_searchData, next) { searchData = _searchData; @@ -220,7 +220,7 @@ User.search = function (socket, data, callback) { } }); next(null, searchData); - } + }, ], callback); }; @@ -238,10 +238,10 @@ User.acceptRegistration = function (socket, data, callback) { type: 'registration-approved', uid: socket.uid, ip: socket.ip, - targetUid: uid + targetUid: uid, }); next(null, uid); - } + }, ], callback); }; @@ -258,7 +258,7 @@ User.rejectRegistration = function (socket, data, callback) { username: data.username, }); next(); - } + }, ], callback); }; diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 885af43516..1678b553bf 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -22,7 +22,7 @@ SocketCategories.get = function (socket, data, callback) { async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), async.apply(categories.getCategoriesData), ], next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -39,12 +39,12 @@ SocketCategories.get = function (socket, data, callback) { SocketCategories.getWatchedCategories = function (socket, data, callback) { async.parallel({ categories: async.apply(categories.getCategoriesByPrivilege, 'cid:0:children', socket.uid, 'find'), - ignoredCids: async.apply(user.getIgnoredCategories, socket.uid) + ignoredCids: async.apply(user.getIgnoredCategories, socket.uid), }, function (err, results) { if (err) { return callback(err); } - var watchedCategories = results.categories.filter(function (category) { + var watchedCategories = results.categories.filter(function (category) { return category && results.ignoredCids.indexOf(category.cid.toString()) === -1; }); @@ -70,7 +70,7 @@ SocketCategories.loadMore = function (socket, data, callback) { } else { next(); } - } + }, }, function (err, results) { if (err) { return callback(err); @@ -94,7 +94,7 @@ SocketCategories.loadMore = function (socket, data, callback) { var start = Math.max(0, parseInt(data.after, 10)); if (data.direction === -1) { - start = start - (reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage); + start -= reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage; } var stop = start + infScrollTopicsPerPage - 1; @@ -118,7 +118,7 @@ SocketCategories.loadMore = function (socket, data, callback) { stop: stop, uid: socket.uid, targetUid: results.targetUid, - settings: results.settings + settings: results.settings, }, function (err, data) { if (err) { return callback(err); @@ -129,7 +129,7 @@ SocketCategories.loadMore = function (socket, data, callback) { data.privileges = results.privileges; data.template = { category: true, - name: 'category' + name: 'category', }; callback(null, data); @@ -162,9 +162,9 @@ SocketCategories.getMoveCategories = function (socket, data, callback) { }, function (cids, next) { categories.getCategories(cids, socket.uid, next); - } + }, ], next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -204,16 +204,15 @@ function ignoreOrWatch(fn, socket, cid, callback) { // filter to subcategories of cid - var any = true; - while (any) { - any = false; - categoryData.forEach(function (c) { - if (cids.indexOf(c.cid) === -1 && cids.indexOf(c.parentCid) !== -1) { - cids.push(c.cid); - any = true; - } + var cat; + do { + cat = categoryData.find(function (c) { + return cids.indexOf(c.cid) === -1 && cids.indexOf(c.parentCid) !== -1; }); - } + if (cat) { + cids.push(cat.cid); + } + } while (cat); async.each(cids, function (cid, next) { fn(socket.uid, cid, next); @@ -221,7 +220,7 @@ function ignoreOrWatch(fn, socket, cid, callback) { }, function (next) { topics.pushUnreadCount(socket.uid, next); - } + }, ], callback); } diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 47453b6e0a..ed6cb00180 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -42,7 +42,7 @@ SocketGroups.join = function (socket, data, callback) { async.parallel({ isAdmin: async.apply(user.isAdministrator, socket.uid), - groupData: async.apply(groups.getGroupData, data.groupName) + groupData: async.apply(groups.getGroupData, data.groupName), }, next); }, function (results, next) { @@ -55,7 +55,7 @@ SocketGroups.join = function (socket, data, callback) { } else { groups.requestMembership(data.groupName, socket.uid, next); } - } + }, ], callback); }; @@ -75,7 +75,7 @@ function isOwner(next) { return function (socket, data, callback) { async.parallel({ isAdmin: async.apply(user.isAdministrator, socket.uid), - isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName) + isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName), }, function (err, results) { if (err || (!results.isOwner && !results.isAdmin)) { return callback(err || new Error('[[error:no-privileges]]')); @@ -129,7 +129,7 @@ function acceptRejectAll(method, socket, data, callback) { async.each(uids, function (uid, next) { method(data.groupName, uid, next); }, next); - } + }, ], callback); } @@ -158,7 +158,7 @@ SocketGroups.issueMassInvite = isOwner(function (socket, data, callback) { async.eachSeries(uids, function (uid, next) { groups.invite(data.groupName, uid, next); }, next); - } + }, ], callback); }); @@ -190,7 +190,7 @@ SocketGroups.kick = isOwner(function (socket, data, callback) { }, function (isOwner, next) { groups.kick(data.uid, data.groupName, isOwner, next); - } + }, ], callback); }); @@ -232,7 +232,7 @@ SocketGroups.search = function (socket, data, callback) { }; SocketGroups.loadMore = function (socket, data, callback) { - if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { + if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { return callback(new Error('[[error:invalid-data]]')); } @@ -259,9 +259,9 @@ SocketGroups.loadMoreMembers = function (socket, data, callback) { function (users, next) { next(null, { users: users, - nextStart: data.after + 10 + nextStart: data.after + 10, }); - } + }, ], callback); }; @@ -282,7 +282,7 @@ SocketGroups.cover.update = function (socket, data, callback) { } groups.updateCover(socket.uid, data, next); - } + }, ], callback); }; @@ -301,7 +301,7 @@ SocketGroups.cover.remove = function (socket, data, callback) { } groups.removeCover(data, next); - } + }, ], callback); }; diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 54c8152199..ce2ee7b30c 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -32,8 +32,8 @@ SocketHelpers.notifyNew = function (uid, type, result) { filterTidCidIgnorers(uids, result.posts[0].topic.tid, result.posts[0].topic.cid, next); }, function (uids, next) { - plugins.fireHook('filter:sockets.sendNewPostToUids', {uidsTo: uids, uidFrom: uid, type: type}, next); - } + plugins.fireHook('filter:sockets.sendNewPostToUids', { uidsTo: uids, uidFrom: uid, type: type }, next); + }, ], function (err, data) { if (err) { return winston.error(err.stack); @@ -64,7 +64,7 @@ function filterTidCidIgnorers(uids, tid, cid, callback) { }, categoryIgnored: function (next) { db.sortedSetScores('cid:' + cid + ':ignorers', uids, next); - } + }, }, next); }, function (results, next) { @@ -73,7 +73,7 @@ function filterTidCidIgnorers(uids, tid, cid, callback) { (!results.topicFollowed[index] && !results.topicIgnored[index] && !results.categoryIgnored[index]); }); next(null, uids); - } + }, ], callback); } @@ -98,7 +98,7 @@ SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, not async.parallel({ username: async.apply(user.getUserField, fromuid, 'username'), topicTitle: async.apply(topics.getTopicField, postData.tid, 'title'), - postObj: async.apply(posts.parsePost, postData) + postObj: async.apply(posts.parsePost, postData), }, next); }, function (results, next) { @@ -113,9 +113,9 @@ SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, not nid: command + ':post:' + pid + ':uid:' + fromuid, from: fromuid, mergeId: notification + '|' + pid, - topicTitle: results.topicTitle + topicTitle: results.topicTitle, }, next); - } + }, ], function (err, notification) { if (err) { return winston.error(err); @@ -154,9 +154,9 @@ SocketHelpers.sendNotificationToTopicOwner = function (tid, fromuid, command, no bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]', path: '/topic/' + results.topicData.slug, nid: command + ':tid:' + tid + ':uid:' + fromuid, - from: fromuid + from: fromuid, }, next); - } + }, ], function (err, notification) { if (err) { return winston.error(err); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 01a520585d..ccabf242fa 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var nconf = require('nconf'); @@ -23,7 +23,7 @@ Sockets.init = function (server) { var SocketIO = require('socket.io'); var socketioWildcard = require('socketio-wildcard')(); io = new SocketIO({ - path: nconf.get('relative_path') + '/socket.io' + path: nconf.get('relative_path') + '/socket.io', }); addRedisAdapter(io); @@ -56,7 +56,7 @@ Sockets.init = function (server) { } io.listen(server, { - transports: nconf.get('socket.io:transports') + transports: nconf.get('socket.io:transports'), }); Sockets.server = io; @@ -105,16 +105,15 @@ function onMessage(socket, payload) { var methodToCall = parts.reduce(function (prev, cur) { if (prev !== null && prev[cur]) { return prev[cur]; - } else { - return null; } + return null; }, Namespaces); if (!methodToCall) { if (process.env.NODE_ENV === 'development') { winston.warn('[socket.io] Unrecognized message: ' + eventName); } - return callback({message: '[[error:invalid-event]]'}); + return callback({ message: '[[error:invalid-event]]' }); } socket.previousEvents = socket.previousEvents || []; @@ -144,15 +143,15 @@ function onMessage(socket, payload) { }, function (next) { methodToCall(socket, params, next); - } + }, ], function (err, result) { - callback(err ? {message: err.message} : null, result); + callback(err ? { message: err.message } : null, result); }); } function requireModules() { var modules = ['admin', 'categories', 'groups', 'meta', 'modules', - 'notifications', 'plugins', 'posts', 'topics', 'user', 'blacklist' + 'notifications', 'plugins', 'posts', 'topics', 'user', 'blacklist', ]; modules.forEach(function (module) { @@ -175,7 +174,7 @@ function checkMaintenance(socket, callback) { function validateSession(socket, callback) { var req = socket.request; if (!req.signedCookies || !req.signedCookies[nconf.get('sessionKey')]) { - return callback(new Error('[[error:invalid-session]]')); + return callback(); } db.sessionStore.get(req.signedCookies[nconf.get('sessionKey')], function (err, sessionData) { if (err || !sessionData) { @@ -210,7 +209,7 @@ function authorize(socket, callback) { } next(); }); - } + }, ], callback); } @@ -220,7 +219,7 @@ function addRedisAdapter(io) { var redis = require('../database/redis'); var pub = redis.connect(); var sub = redis.connect(); - io.adapter(redisAdapter({pubClient: pub, subClient: sub})); + io.adapter(redisAdapter({ pubClient: pub, subClient: sub })); } else if (nconf.get('isCluster') === 'true') { winston.warn('[socket.io] Clustering detected, you are advised to configure Redis as a websocket store.'); } @@ -262,8 +261,7 @@ Sockets.reqFromSocket = function (socket, payload, event) { secure: encrypted, url: referer, path: referer.substr(referer.indexOf(host) + host.length), - headers: headers + headers: headers, }; }; - diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index baa0abc0aa..398bf249f5 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -5,7 +5,7 @@ var user = require('../user'); var topics = require('../topics'); var SocketMeta = { - rooms: {} + rooms: {}, }; SocketMeta.reconnected = function (socket, data, callback) { diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 473a32e5d9..f0309e8d30 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -1,4 +1,5 @@ -"use strict"; +'use strict'; + var async = require('async'); var validator = require('validator'); @@ -13,7 +14,7 @@ var user = require('../user'); var SocketModules = { chats: {}, sounds: {}, - settings: {} + settings: {}, }; /* Chat */ @@ -31,7 +32,7 @@ SocketModules.chats.getRaw = function (socket, data, callback) { return next(new Error('[[error:not-allowed]]')); } Messaging.getMessageField(data.mid, 'content', next); - } + }, ], callback); }; @@ -66,7 +67,7 @@ SocketModules.chats.send = function (socket, data, callback) { function (next) { plugins.fireHook('filter:messaging.send', { data: data, - uid: socket.uid + uid: socket.uid, }, function (err, results) { data = results.data; next(err); @@ -82,7 +83,7 @@ SocketModules.chats.send = function (socket, data, callback) { Messaging.notifyUsersInRoom(socket.uid, data.roomId, message); user.updateOnlineUsers(socket.uid); next(null, message); - } + }, ], callback); }; @@ -92,9 +93,9 @@ function rateLimitExceeded(socket) { var delay = meta.config.hasOwnProperty('chatMessageDelay') ? parseInt(meta.config.chatMessageDelay, 10) : 200; if (now - socket.lastChatMessageTime < delay) { return true; - } else { - socket.lastChatMessageTime = now; } + socket.lastChatMessageTime = now; + return false; } @@ -120,7 +121,7 @@ SocketModules.chats.loadRoom = function (socket, data, callback) { callerUid: socket.uid, uid: data.uid || socket.uid, roomId: data.roomId, - isNew: false + isNew: false, }), }, next); }, @@ -134,7 +135,7 @@ SocketModules.chats.loadRoom = function (socket, data, callback) { results.roomData.maximumUsersInChatRoom = parseInt(meta.config.maximumUsersInChatRoom, 10) || 0; results.roomData.showUserInput = !results.roomData.maximumUsersInChatRoom || results.roomData.maximumUsersInChatRoom > 2; next(null, results.roomData); - } + }, ], callback); }; @@ -168,7 +169,7 @@ SocketModules.chats.addUserToRoom = function (socket, data, callback) { async.parallel({ settings: async.apply(user.getSettings, uid), isAdminOrGlobalMod: async.apply(user.isAdminOrGlobalMod, socket.uid), - isFollowing: async.apply(user.isFollowing, uid, socket.uid) + isFollowing: async.apply(user.isFollowing, uid, socket.uid), }, next); }, function (results, next) { @@ -177,7 +178,7 @@ SocketModules.chats.addUserToRoom = function (socket, data, callback) { } Messaging.addUsersToRoom(socket.uid, [uid], data.roomId, next); - } + }, ], callback); }; @@ -195,7 +196,7 @@ SocketModules.chats.removeUserFromRoom = function (socket, data, callback) { } Messaging.removeUsersFromRoom(socket.uid, [uid], data.roomId, next); - } + }, ], callback); }; @@ -246,14 +247,14 @@ SocketModules.chats.markRead = function (socket, roomId, callback) { } async.parallel({ uidsInRoom: async.apply(Messaging.getUidsInRoom, roomId, 0, -1), - markRead: async.apply(Messaging.markRead, socket.uid, roomId) + markRead: async.apply(Messaging.markRead, socket.uid, roomId), }, function (err, results) { if (err) { return callback(err); } Messaging.pushUnreadCount(socket.uid); - server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', {roomId: roomId}); + server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', { roomId: roomId }); if (results.uidsInRoom.indexOf(socket.uid.toString()) === -1) { return callback(); @@ -282,7 +283,7 @@ SocketModules.chats.markAllRead = function (socket, data, callback) { function (next) { Messaging.pushUnreadCount(socket.uid); next(); - } + }, ], callback); }; @@ -299,12 +300,12 @@ SocketModules.chats.renameRoom = function (socket, data, callback) { Messaging.getUidsInRoom(data.roomId, 0, -1, next); }, function (uids, next) { - var eventData = {roomId: data.roomId, newName: validator.escape(String(data.newName))}; + var eventData = { roomId: data.roomId, newName: validator.escape(String(data.newName)) }; uids.forEach(function (uid) { server.in('uid_' + uid).emit('event:chats.roomRename', eventData); }); next(); - } + }, ], callback); }; @@ -334,7 +335,7 @@ SocketModules.chats.getMessages = function (socket, data, callback) { uid: data.uid, roomId: data.roomId, start: parseInt(data.start, 10) || 0, - count: 50 + count: 50, }; Messaging.getMessages(params, callback); diff --git a/src/socket.io/notifications.js b/src/socket.io/notifications.js index cc83b0b80b..66e5135ed6 100644 --- a/src/socket.io/notifications.js +++ b/src/socket.io/notifications.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var user = require('../user'); @@ -29,8 +29,8 @@ SocketNotifs.loadMore = function (socket, data, callback) { user.notifications.getAll(socket.uid, start, stop, next); }, function (notifications, next) { - next(null, {notifications: notifications, nextStart: stop}); - } + next(null, { notifications: notifications, nextStart: stop }); + }, ], callback); }; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 8ded335780..b4b5ac40cd 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); @@ -49,7 +49,7 @@ SocketPosts.reply = function (socket, data, callback) { user.updateOnlineUsers(socket.uid); socketHelpers.notifyNew(socket.uid, 'newPost', result); - } + }, ], callback); }; @@ -69,7 +69,7 @@ SocketPosts.getRawPost = function (socket, pid, callback) { return next(new Error('[[error:no-post]]')); } next(null, postData.content); - } + }, ], callback); }; @@ -135,7 +135,7 @@ SocketPosts.getReplies = function (socket, pid, callback) { }, privileges: function (next) { privileges.posts.get(pids, socket.uid, next); - } + }, }, next); }, function (results, next) { @@ -150,7 +150,7 @@ SocketPosts.getReplies = function (socket, pid, callback) { posts.modifyPostByPrivilege(postData, postPrivileges.isAdminOrMod); }); next(null, postData); - } + }, ], callback); }; diff --git a/src/socket.io/posts/bookmarks.js b/src/socket.io/posts/bookmarks.js index d0bb84256c..b77ce526a1 100644 --- a/src/socket.io/posts/bookmarks.js +++ b/src/socket.io/posts/bookmarks.js @@ -4,7 +4,6 @@ var helpers = require('./helpers'); module.exports = function (SocketPosts) { - SocketPosts.bookmark = function (socket, data, callback) { helpers.postCommand(socket, 'bookmark', 'bookmarked', '', data, callback); }; @@ -12,5 +11,4 @@ module.exports = function (SocketPosts) { SocketPosts.unbookmark = function (socket, data, callback) { helpers.postCommand(socket, 'unbookmark', 'bookmarked', '', data, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js index 54650961f9..5ab6973ce1 100644 --- a/src/socket.io/posts/edit.js +++ b/src/socket.io/posts/edit.js @@ -3,6 +3,7 @@ var async = require('async'); var validator = require('validator'); var _ = require('underscore'); +var S = require('string'); var posts = require('../../posts'); var groups = require('../../groups'); @@ -11,13 +12,17 @@ var meta = require('../../meta'); var websockets = require('../index'); module.exports = function (SocketPosts) { - SocketPosts.edit = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); } else if (!data || !data.pid || !data.content) { return callback(new Error('[[error:invalid-data]]')); - } else if (data.title && data.title.length < parseInt(meta.config.minimumTitleLength, 10)) { + } + + // Trim and remove HTML (latter for composers that send in HTML, like redactor) + var contentLen = S(data.content).stripTags().s.trim().length; + + if (data.title && data.title.length < parseInt(meta.config.minimumTitleLength, 10)) { return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]')); } else if (data.title && data.title.length > parseInt(meta.config.maximumTitleLength, 10)) { return callback(new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]')); @@ -25,9 +30,9 @@ module.exports = function (SocketPosts) { return callback(new Error('[[error:not-enough-tags, ' + meta.config.minimumTagsPerTopic + ']]')); } else if (data.tags && data.tags.length > parseInt(meta.config.maximumTagsPerTopic, 10)) { return callback(new Error('[[error:too-many-tags, ' + meta.config.maximumTagsPerTopic + ']]')); - } else if (!data.content || data.content.length < parseInt(meta.config.minimumPostLength, 10)) { + } else if (contentLen < parseInt(meta.config.minimumPostLength, 10)) { return callback(new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]')); - } else if (data.content.length > parseInt(meta.config.maximumPostLength, 10)) { + } else if (contentLen > parseInt(meta.config.maximumPostLength, 10)) { return callback(new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]')); } @@ -47,11 +52,11 @@ module.exports = function (SocketPosts) { uid: socket.uid, ip: socket.ip, oldTitle: validator.escape(String(result.topic.oldTitle)), - newTitle: validator.escape(String(result.topic.title)) + newTitle: validator.escape(String(result.topic.title)), }); } - if (parseInt(result.post.deleted) !== 1) { + if (parseInt(result.post.deleted, 10) !== 1) { websockets.in('topic_' + result.topic.tid).emit('event:post_edited', result); return callback(null, result.post); } @@ -60,7 +65,7 @@ module.exports = function (SocketPosts) { 'administrators', 'Global Moderators', 'cid:' + result.topic.cid + ':privileges:mods', - 'cid:' + result.topic.cid + ':privileges:groups:moderate' + 'cid:' + result.topic.cid + ':privileges:groups:moderate', ], next); }, function (results, next) { @@ -69,7 +74,7 @@ module.exports = function (SocketPosts) { websockets.in('uid_' + uid).emit('event:post_edited', editResult); }); next(null, editResult.post); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/socket.io/posts/flag.js b/src/socket.io/posts/flag.js index 077b88bfc9..dccf302c43 100644 --- a/src/socket.io/posts/flag.js +++ b/src/socket.io/posts/flag.js @@ -14,7 +14,6 @@ var meta = require('../../meta'); var utils = require('../../../public/src/utils'); module.exports = function (SocketPosts) { - SocketPosts.flag = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); @@ -48,7 +47,7 @@ module.exports = function (SocketPosts) { }, userData: function (next) { user.getUserFields(socket.uid, ['username', 'reputation', 'banned'], next); - } + }, }, next); }, function (user, next) { @@ -79,7 +78,7 @@ module.exports = function (SocketPosts) { }, moderators: function (next) { groups.getMembers('cid:' + post.topic.cid + ':privileges:mods', 0, -1, next); - } + }, }, next); }, function (results, next) { @@ -94,16 +93,16 @@ module.exports = function (SocketPosts) { nid: 'post_flag:' + data.pid + ':uid:' + socket.uid, from: socket.uid, mergeId: 'notifications:user_flagged_post_in|' + data.pid, - topicTitle: post.topic.title + topicTitle: post.topic.title, }, function (err, notification) { if (err || !notification) { return next(err); } - plugins.fireHook('action:post.flag', {post: post, reason: data.reason, flaggingUser: flaggingUser}); + plugins.fireHook('action:post.flag', { post: post, reason: data.reason, flaggingUser: flaggingUser }); notifications.push(notification, results.admins.concat(results.moderators).concat(results.globalMods), next); }); - } + }, ], callback); }; @@ -120,7 +119,7 @@ module.exports = function (SocketPosts) { return next(new Error('[[no-privileges]]')); } posts.dismissFlag(pid, next); - } + }, ], callback); }; @@ -134,7 +133,7 @@ module.exports = function (SocketPosts) { return next(new Error('[[no-privileges]]')); } posts.dismissAllFlags(next); - } + }, ], callback); }; @@ -149,7 +148,7 @@ module.exports = function (SocketPosts) { function (next) { async.parallel([ async.apply(user.isAdminOrGlobalMod, socket.uid), - async.apply(user.isModeratorOfAnyCategory, socket.uid) + async.apply(user.isModeratorOfAnyCategory, socket.uid), ], function (err, results) { next(err, results[0] || results[1]); }); @@ -166,7 +165,7 @@ module.exports = function (SocketPosts) { }, payload); posts.updateFlagData(socket.uid, data.pid, payload, next); - } + }, ], callback); }; }; diff --git a/src/socket.io/posts/helpers.js b/src/socket.io/posts/helpers.js index 4c04f82afc..c7b92488d5 100644 --- a/src/socket.io/posts/helpers.js +++ b/src/socket.io/posts/helpers.js @@ -26,7 +26,7 @@ helpers.postCommand = function (socket, command, eventName, notification, data, }, deleted: function (next) { posts.getPostField(data.pid, 'deleted', next); - } + }, }, next); }, function (results, next) { @@ -46,11 +46,11 @@ helpers.postCommand = function (socket, command, eventName, notification, data, filter:post.bookmark filter:post.unbookmark */ - plugins.fireHook('filter:post.' + command, {data: data, uid: socket.uid}, next); + plugins.fireHook('filter:post.' + command, { data: data, uid: socket.uid }, next); }, function (filteredData, next) { executeCommand(socket, command, eventName, notification, filteredData.data, next); - } + }, ], callback); }; @@ -71,6 +71,6 @@ function executeCommand(socket, command, eventName, notification, data, callback socketHelpers.rescindUpvoteNotification(data.pid, socket.uid); } next(null, result); - } + }, ], callback); -} \ No newline at end of file +} diff --git a/src/socket.io/posts/move.js b/src/socket.io/posts/move.js index 207db2aef5..6ef596c1c2 100644 --- a/src/socket.io/posts/move.js +++ b/src/socket.io/posts/move.js @@ -6,7 +6,6 @@ var topics = require('../../topics'); var socketHelpers = require('../helpers'); module.exports = function (SocketPosts) { - SocketPosts.movePost = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); @@ -30,8 +29,7 @@ module.exports = function (SocketPosts) { function (next) { socketHelpers.sendNotificationToPostOwner(data.pid, socket.uid, 'move', 'notifications:moved_your_post'); next(); - } + }, ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js index 571d84175b..ee393a42b9 100644 --- a/src/socket.io/posts/tools.js +++ b/src/socket.io/posts/tools.js @@ -13,7 +13,6 @@ var plugins = require('../../plugins'); var social = require('../../social'); module.exports = function (SocketPosts) { - SocketPosts.loadPostTools = function (socket, data, callback) { if (!data || !data.pid || !data.cid) { return callback(new Error('[[error:invalid-data]]')); @@ -37,11 +36,11 @@ module.exports = function (SocketPosts) { posts.hasBookmarked(data.pid, socket.uid, next); }, tools: function (next) { - plugins.fireHook('filter:post.tools', {pid: data.pid, uid: socket.uid, tools: []}, next); + plugins.fireHook('filter:post.tools', { pid: data.pid, uid: socket.uid, tools: [] }, next); }, postSharing: function (next) { social.getActivePostSharing(next); - } + }, }, next); }, function (results, next) { @@ -54,7 +53,7 @@ module.exports = function (SocketPosts) { results.posts.display_moderator_tools = results.posts.display_edit_tools || results.posts.display_delete_tools; results.posts.display_move_tools = results.isAdminOrMod; next(null, results); - } + }, ], callback); }; @@ -85,11 +84,11 @@ module.exports = function (SocketPosts) { type: 'post-delete', uid: socket.uid, pid: data.pid, - ip: socket.ip + ip: socket.ip, }); next(); - } + }, ], callback); }; @@ -103,18 +102,17 @@ module.exports = function (SocketPosts) { posts.tools.restore(socket.uid, data.pid, next); }, function (postData, next) { - websockets.in('topic_' + data.tid).emit('event:post_restored', postData); events.log({ type: 'post-restore', uid: socket.uid, pid: data.pid, - ip: socket.ip + ip: socket.ip, }); setImmediate(next); - } + }, ], callback); }; @@ -123,7 +121,7 @@ module.exports = function (SocketPosts) { return callback(new Error('[[error:invalid-data]]')); } async.eachSeries(data.pids, function (pid, next) { - SocketPosts.delete(socket, {pid: pid, tid: data.tid}, next); + SocketPosts.delete(socket, { pid: pid, tid: data.tid }, next); }, callback); }; @@ -132,7 +130,7 @@ module.exports = function (SocketPosts) { return callback(new Error('[[error:invalid-data]]')); } async.eachSeries(data.pids, function (pid, next) { - SocketPosts.purge(socket, {pid: pid, tid: data.tid}, next); + SocketPosts.purge(socket, { pid: pid, tid: data.tid }, next); }, callback); }; @@ -158,7 +156,7 @@ module.exports = function (SocketPosts) { posts.getPostField(data.pid, 'toPid', next); }, function (toPid, next) { - postData = {pid: data.pid, toPid: toPid}; + postData = { pid: data.pid, toPid: toPid }; posts.tools.purge(socket.uid, data.pid, next); }, function (next) { @@ -171,9 +169,9 @@ module.exports = function (SocketPosts) { uid: socket.uid, pid: data.pid, ip: socket.ip, - title: validator.escape(String(title)) + title: validator.escape(String(title)), }, next); - } + }, ], callback); }; @@ -183,8 +181,8 @@ module.exports = function (SocketPosts) { posts.getTopicFields(pid, ['tid', 'cid'], next); }, function (topic, next) { - socketTopics.doTopicAction('delete', 'event:topic_deleted', socket, {tids: [topic.tid], cid: topic.cid}, next); - } + socketTopics.doTopicAction('delete', 'event:topic_deleted', socket, { tids: [topic.tid], cid: topic.cid }, next); + }, ], callback); } @@ -197,8 +195,7 @@ module.exports = function (SocketPosts) { posts.getTopicFields(pid, ['postcount'], function (err, topic) { next(err, topic ? parseInt(topic.postcount, 10) === 1 : false); }); - } + }, }, callback); } - }; diff --git a/src/socket.io/posts/votes.js b/src/socket.io/posts/votes.js index e3a9510aaa..0c12fe262d 100644 --- a/src/socket.io/posts/votes.js +++ b/src/socket.io/posts/votes.js @@ -9,7 +9,6 @@ var privileges = require('../../privileges'); var helpers = require('./helpers'); module.exports = function (SocketPosts) { - SocketPosts.getVoters = function (socket, data, callback) { if (!data || !data.pid || !data.cid) { return callback(new Error('[[error:invalid-data]]')); @@ -30,7 +29,7 @@ module.exports = function (SocketPosts) { }, downvoteUids: function (next) { db.getSetMembers('pid:' + data.pid + ':downvote', next); - } + }, }, next); }, function (results, next) { @@ -46,9 +45,9 @@ module.exports = function (SocketPosts) { }, downvoteCount: function (next) { next(null, results.downvoteUids.length); - } + }, }, next); - } + }, ], callback); }; @@ -62,7 +61,7 @@ module.exports = function (SocketPosts) { return callback(err, []); } - async.map(data, function (uids, next) { + async.map(data, function (uids, next) { var otherCount = 0; if (uids.length > 6) { otherCount = uids.length - 5; @@ -71,7 +70,7 @@ module.exports = function (SocketPosts) { user.getUsernamesByUids(uids, function (err, usernames) { next(err, { otherCount: otherCount, - usernames: usernames + usernames: usernames, }); }); }, callback); @@ -89,4 +88,4 @@ module.exports = function (SocketPosts) { SocketPosts.unvote = function (socket, data, callback) { helpers.postCommand(socket, 'unvote', 'voted', '', data, callback); }; -}; \ No newline at end of file +}; diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 2fdecf550f..3b8a69d0f4 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -1,4 +1,3 @@ - 'use strict'; var async = require('async'); @@ -9,7 +8,7 @@ var user = require('../user'); var apiController = require('../controllers/api'); var socketHelpers = require('./helpers'); -var SocketTopics = {}; +var SocketTopics = module.exports; require('./topics/unread')(SocketTopics); require('./topics/move')(SocketTopics); @@ -26,18 +25,19 @@ SocketTopics.post = function (socket, data, callback) { data.req = websockets.reqFromSocket(socket); data.timestamp = Date.now(); - topics.post(data, function (err, result) { - if (err) { - return callback(err); - } + async.waterfall([ + function (next) { + topics.post(data, next); + }, + function (result, next) { + next(null, result.topicData); - callback(null, result.topicData); + socket.emit('event:new_post', { posts: [result.postData] }); + socket.emit('event:new_topic', result.topicData); - socket.emit('event:new_post', {posts: [result.postData]}); - socket.emit('event:new_topic', result.topicData); - - socketHelpers.notifyNew(socket.uid, 'newTopic', {posts: [result.postData], topic: result.topicData}); - }); + socketHelpers.notifyNew(socket.uid, 'newTopic', { posts: [result.postData], topic: result.topicData }); + }, + ], callback); }; SocketTopics.postcount = function (socket, tid, callback) { @@ -64,7 +64,7 @@ SocketTopics.createTopicFromPosts = function (socket, data, callback) { }; SocketTopics.changeWatching = function (socket, data, callback) { - if (!data.tid || !data.type) { + if (!data || !data.tid || !data.type) { return callback(new Error('[[error:invalid-data]]')); } var commands = ['follow', 'unfollow', 'ignore']; @@ -93,20 +93,23 @@ SocketTopics.isFollowed = function (socket, tid, callback) { }; SocketTopics.search = function (socket, data, callback) { + if (!data) { + return callback(new Error('[[error:invalid-data]]')); + } topics.search(data.tid, data.term, callback); }; SocketTopics.isModerator = function (socket, tid, callback) { - topics.getTopicField(tid, 'cid', function (err, cid) { - if (err) { - return callback(err); - } - user.isModerator(socket.uid, cid, callback); - }); + async.waterfall([ + function (next) { + topics.getTopicField(tid, 'cid', next); + }, + function (cid, next) { + user.isModerator(socket.uid, cid, next); + }, + ], callback); }; SocketTopics.getTopic = function (socket, tid, callback) { apiController.getTopicData(tid, socket.uid, callback); }; - -module.exports = SocketTopics; diff --git a/src/socket.io/topics/infinitescroll.js b/src/socket.io/topics/infinitescroll.js index a68d220609..b0d7407a0a 100644 --- a/src/socket.io/topics/infinitescroll.js +++ b/src/socket.io/topics/infinitescroll.js @@ -9,9 +9,8 @@ var utils = require('../../../public/src/utils'); var social = require('../../social'); module.exports = function (SocketTopics) { - SocketTopics.loadMore = function (socket, data, callback) { - if (!data || !data.tid || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { + if (!data || !data.tid || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { return callback(new Error('[[error:invalid-data]]')); } var userPrivileges; @@ -24,7 +23,7 @@ module.exports = function (SocketTopics) { }, topic: function (next) { topics.getTopicFields(data.tid, ['postcount', 'deleted'], next); - } + }, }, next); }, function (results, next) { @@ -47,12 +46,10 @@ module.exports = function (SocketTopics) { if (reverse) { start = results.topic.postcount - start; } + } else if (reverse) { + start = results.topic.postcount - start - infScrollPostsPerPage - 1; } else { - if (reverse) { - start = results.topic.postcount - start - infScrollPostsPerPage - 1; - } else { - start = start - infScrollPostsPerPage - 1; - } + start = start - infScrollPostsPerPage - 1; } var stop = start + (infScrollPostsPerPage - 1); @@ -72,7 +69,7 @@ module.exports = function (SocketTopics) { }, postSharing: function (next) { social.getActivePostSharing(next); - } + }, }, next); }, function (topicData, next) { @@ -86,7 +83,7 @@ module.exports = function (SocketTopics) { topics.modifyPostsByPrivilege(topicData, userPrivileges); next(null, topicData); - } + }, ], callback); }; @@ -122,5 +119,4 @@ module.exports = function (SocketTopics) { topics.getTopicsFromSet(data.set, socket.uid, start, stop, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/socket.io/topics/move.js b/src/socket.io/topics/move.js index 938fe22792..9faffa910b 100644 --- a/src/socket.io/topics/move.js +++ b/src/socket.io/topics/move.js @@ -7,7 +7,6 @@ var privileges = require('../../privileges'); var socketHelpers = require('../helpers'); module.exports = function (SocketTopics) { - SocketTopics.move = function (socket, data, callback) { if (!data || !Array.isArray(data.tids) || !data.cid) { return callback(new Error('[[error:invalid-data]]')); @@ -30,7 +29,7 @@ module.exports = function (SocketTopics) { topicData = _topicData; topicData.tid = tid; topics.tools.move(tid, data.cid, socket.uid, next); - } + }, ], function (err) { if (err) { return next(err); @@ -66,7 +65,7 @@ module.exports = function (SocketTopics) { async.eachLimit(tids, 50, function (tid, next) { topics.tools.move(tid, data.cid, socket.uid, next); }, next); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/socket.io/topics/tags.js b/src/socket.io/topics/tags.js index 8829229ca8..0b7076fa20 100644 --- a/src/socket.io/topics/tags.js +++ b/src/socket.io/topics/tags.js @@ -6,7 +6,6 @@ var topics = require('../../topics'); var utils = require('../../../public/src/utils'); module.exports = function (SocketTopics) { - SocketTopics.isTagAllowed = function (socket, data, callback) { if (!data || !data.cid || !data.tag) { return callback(new Error('[[error:invalid-data]]')); @@ -20,7 +19,7 @@ module.exports = function (SocketTopics) { return next(null, true); } next(null, tagWhitelist.indexOf(data.tag) !== -1); - } + }, ], callback); }; @@ -49,8 +48,8 @@ module.exports = function (SocketTopics) { }, function (tags, next) { tags = tags.filter(Boolean); - next(null, {tags: tags, nextStart: stop + 1}); - } + next(null, { tags: tags, nextStart: stop + 1 }); + }, ], callback); }; }; diff --git a/src/socket.io/topics/tools.js b/src/socket.io/topics/tools.js index ede87d2599..74cdb68e7e 100644 --- a/src/socket.io/topics/tools.js +++ b/src/socket.io/topics/tools.js @@ -10,7 +10,6 @@ var plugins = require('../../plugins'); var socketHelpers = require('../helpers'); module.exports = function (SocketTopics) { - SocketTopics.loadTopicTools = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:no-privileges]]')); @@ -27,13 +26,13 @@ module.exports = function (SocketTopics) { }, privileges: function (next) { privileges.topics.get(data.tid, socket.uid, next); - } + }, }, next); }, function (results, next) { topic = results.topic; topic.privileges = results.privileges; - plugins.fireHook('filter:topic.thread_tools', {topic: results.topic, uid: socket.uid, tools: []}, next); + plugins.fireHook('filter:topic.thread_tools', { topic: results.topic, uid: socket.uid, tools: [] }, next); }, function (data, next) { topic.deleted = parseInt(topic.deleted, 10) === 1; @@ -41,7 +40,7 @@ module.exports = function (SocketTopics) { topic.pinned = parseInt(topic.pinned, 10) === 1; topic.thread_tools = data.tools; next(null, topic); - } + }, ], callback); }; @@ -95,7 +94,7 @@ module.exports = function (SocketTopics) { function (data, next) { socketHelpers.emitToTopicAndCategory(event, data); logTopicAction(action, socket, tid, next); - } + }, ], next); }, callback); }; @@ -115,9 +114,9 @@ module.exports = function (SocketTopics) { uid: socket.uid, ip: socket.ip, tid: tid, - title: validator.escape(String(title)) + title: validator.escape(String(title)), }, next); - } + }, ], callback); } @@ -128,5 +127,4 @@ module.exports = function (SocketTopics) { topics.tools.orderPinnedTopics(socket.uid, data, callback); }; - -}; \ No newline at end of file +}; diff --git a/src/socket.io/topics/unread.js b/src/socket.io/topics/unread.js index 39c6485a26..8fa5651e32 100644 --- a/src/socket.io/topics/unread.js +++ b/src/socket.io/topics/unread.js @@ -6,7 +6,6 @@ var user = require('../../user'); var topics = require('../../topics'); module.exports = function (SocketTopics) { - SocketTopics.markAsRead = function (socket, tids, callback) { if (!Array.isArray(tids) || !socket.uid) { return callback(new Error('[[error:invalid-data]]')); @@ -22,7 +21,7 @@ module.exports = function (SocketTopics) { topics.markTopicNotificationsRead(tids, socket.uid); } next(); - } + }, ], callback); }; @@ -44,7 +43,7 @@ module.exports = function (SocketTopics) { function (next) { topics.pushUnreadCount(socket.uid); next(); - } + }, ], callback); }; @@ -55,7 +54,7 @@ module.exports = function (SocketTopics) { }, function (tids, next) { SocketTopics.markAsRead(socket, tids, next); - } + }, ], callback); }; @@ -70,7 +69,7 @@ module.exports = function (SocketTopics) { function (next) { topics.pushUnreadCount(socket.uid); next(); - } + }, ], callback); }; @@ -110,14 +109,14 @@ module.exports = function (SocketTopics) { }, function (next) { topics.updateRecent(tid, Date.now(), next); - } + }, ], next); }, next); }, function (next) { topics.pushUnreadCount(socket.uid); next(); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 060c9e7b2e..78f696a19b 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -12,7 +12,7 @@ var meta = require('../meta'); var events = require('../events'); var emailer = require('../emailer'); var db = require('../database'); -var apiController = require('../controllers/api'); +var userController = require('../controllers/user'); var privileges = require('../privileges'); var SocketUser = {}; @@ -46,16 +46,16 @@ SocketUser.deleteAccount = function (socket, data, callback) { user.deleteAccount(socket.uid, next); }, function (next) { - require('./index').server.sockets.emit('event:user_status_change', {uid: socket.uid, status: 'offline'}); + require('./index').server.sockets.emit('event:user_status_change', { uid: socket.uid, status: 'offline' }); events.log({ type: 'user-delete', uid: socket.uid, targetUid: socket.uid, - ip: socket.ip + ip: socket.ip, }); next(); - } + }, ], callback); }; @@ -85,7 +85,7 @@ SocketUser.emailConfirm = function (socket, data, callback) { } user.email.sendValidationEmail(socket.uid, email, next); - } + }, ], callback); }; @@ -120,7 +120,7 @@ SocketUser.reset.commit = function (socket, data, callback) { function (next) { async.parallel({ uid: async.apply(db.getObjectField, 'reset:uid', data.code), - reset: async.apply(user.reset.commit, data.code, data.password) + reset: async.apply(user.reset.commit, data.code, data.password), }, next); }, function (results, next) { @@ -128,7 +128,7 @@ SocketUser.reset.commit = function (socket, data, callback) { events.log({ type: 'password-reset', uid: uid, - ip: socket.ip + ip: socket.ip, }); user.getUserField(uid, 'username', next); @@ -140,11 +140,11 @@ SocketUser.reset.commit = function (socket, data, callback) { username: username, date: parsedDate, site_title: meta.config.title || 'NodeBB', - subject: '[[email:reset.notify.subject]]' + subject: '[[email:reset.notify.subject]]', }); next(); - } + }, ], callback); }; @@ -175,7 +175,7 @@ SocketUser.follow = function (socket, data, callback) { nid: 'follow:' + data.uid + ':uid:' + socket.uid, from: socket.uid, path: '/uid/' + data.uid + '/followers', - mergeId: 'notifications:user_started_following_you' + mergeId: 'notifications:user_started_following_you', }, next); }, function (notification, next) { @@ -184,7 +184,7 @@ SocketUser.follow = function (socket, data, callback) { } notification.user = userData; notifications.push(notification, [data.uid], next); - } + }, ], callback); }; @@ -203,7 +203,7 @@ function toggleFollow(method, uid, theiruid, callback) { plugins.fireHook('action:user.' + method, { fromUid: uid, - toUid: theiruid + toUid: theiruid, }); callback(); }); @@ -223,7 +223,7 @@ SocketUser.saveSettings = function (socket, data, callback) { return next(new Error('[[error:no-privileges]]')); } user.saveSettings(data.uid, data.settings, next); - } + }, ], callback); }; @@ -257,7 +257,7 @@ SocketUser.getUnreadCounts = function (socket, data, callback) { unreadTopicCount: async.apply(topics.getTotalUnread, socket.uid), unreadNewTopicCount: async.apply(topics.getTotalUnread, socket.uid, 'new'), unreadChatCount: async.apply(messaging.getUnreadCount, socket.uid), - unreadNotificationCount: async.apply(user.notifications.getUnreadCount, socket.uid) + unreadNotificationCount: async.apply(user.notifications.getUnreadCount, socket.uid), }, callback); }; @@ -296,22 +296,22 @@ SocketUser.invite = function (socket, email, callback) { } user.sendInvitationEmail(socket.uid, email, next); - } + }, ], next); - } + }, ], callback); }; SocketUser.getUserByUID = function (socket, uid, callback) { - apiController.getUserDataByField(socket.uid, 'uid', uid, callback); + userController.getUserDataByField(socket.uid, 'uid', uid, callback); }; SocketUser.getUserByUsername = function (socket, username, callback) { - apiController.getUserDataByField(socket.uid, 'username', username, callback); + userController.getUserDataByField(socket.uid, 'username', username, callback); }; SocketUser.getUserByEmail = function (socket, email, callback) { - apiController.getUserDataByField(socket.uid, 'email', email, callback); + userController.getUserDataByField(socket.uid, 'email', email, callback); }; SocketUser.setModerationNote = function (socket, data, callback) { @@ -339,7 +339,7 @@ SocketUser.setModerationNote = function (socket, data, callback) { } else { db.deleteObjectField('user:' + data.uid, 'moderationNote', next); } - } + }, ], callback); }; diff --git a/src/socket.io/user/ban.js b/src/socket.io/user/ban.js index 089720c59e..54ce94fd24 100644 --- a/src/socket.io/user/ban.js +++ b/src/socket.io/user/ban.js @@ -8,7 +8,6 @@ var events = require('../../events'); var plugins = require('../../plugins'); module.exports = function (SocketUser) { - SocketUser.banUsers = function (socket, data, callback) { if (!data || !Array.isArray(data.uids)) { return callback(new Error('[[error:invalid-data]]')); @@ -24,7 +23,7 @@ module.exports = function (SocketUser) { type: 'user-ban', uid: socket.uid, targetUid: uid, - ip: socket.ip + ip: socket.ip, }, next); }, function (next) { @@ -32,10 +31,10 @@ module.exports = function (SocketUser) { callerUid: socket.uid, ip: socket.ip, uid: uid, - until: data.until > 0 ? data.until : undefined + until: data.until > 0 ? data.until : undefined, }); next(); - } + }, ], next); }, callback); }; @@ -51,17 +50,17 @@ module.exports = function (SocketUser) { type: 'user-unban', uid: socket.uid, targetUid: uid, - ip: socket.ip + ip: socket.ip, }, next); }, function (next) { plugins.fireHook('action:user.unbanned', { callerUid: socket.uid, ip: socket.ip, - uid: uid + uid: uid, }); next(); - } + }, ], next); }, callback); }; @@ -80,7 +79,7 @@ module.exports = function (SocketUser) { return next(new Error('[[error:no-privileges]]')); } async.each(uids, method, next); - } + }, ], callback); } @@ -98,7 +97,7 @@ module.exports = function (SocketUser) { function (next) { websockets.in('uid_' + uid).emit('event:banned'); next(); - } + }, ], callback); } }; diff --git a/src/socket.io/user/picture.js b/src/socket.io/user/picture.js index deceb70f8a..109b2635e1 100644 --- a/src/socket.io/user/picture.js +++ b/src/socket.io/user/picture.js @@ -9,7 +9,6 @@ var user = require('../../user'); var plugins = require('../../plugins'); module.exports = function (SocketUser) { - SocketUser.changePicture = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:invalid-uid]]')); @@ -26,31 +25,31 @@ module.exports = function (SocketUser) { user.isAdminOrGlobalModOrSelf(socket.uid, data.uid, next); }, function (next) { - switch(type) { - case 'default': - next(null, ''); - break; - case 'uploaded': - user.getUserField(data.uid, 'uploadedpicture', next); - break; - default: - plugins.fireHook('filter:user.getPicture', { - uid: socket.uid, - type: type, - picture: undefined - }, function (err, returnData) { - if (err) { - return next(err); - } + switch (type) { + case 'default': + next(null, ''); + break; + case 'uploaded': + user.getUserField(data.uid, 'uploadedpicture', next); + break; + default: + plugins.fireHook('filter:user.getPicture', { + uid: socket.uid, + type: type, + picture: undefined, + }, function (err, returnData) { + if (err) { + return next(err); + } - next(null, returnData.picture || ''); - }); - break; + next(null, returnData.picture || ''); + }); + break; } }, function (picture, next) { user.setUserField(data.uid, 'picture', picture, next); - } + }, ], callback); }; @@ -67,7 +66,7 @@ module.exports = function (SocketUser) { }, function (uploadedImage, next) { next(null, uploadedImage ? uploadedImage.url : null); - } + }, ], callback); }; @@ -97,9 +96,9 @@ module.exports = function (SocketUser) { user.setUserFields(data.uid, { uploadedpicture: '', - picture: userData.uploadedpicture === userData.picture ? '' : userData.picture // if current picture is uploaded picture, reset to user icon + picture: userData.uploadedpicture === userData.picture ? '' : userData.picture, // if current picture is uploaded picture, reset to user icon }, next); - } + }, ], callback); }; @@ -111,9 +110,9 @@ module.exports = function (SocketUser) { async.parallel({ list: async.apply(plugins.fireHook, 'filter:user.listPictures', { uid: data.uid, - pictures: [] + pictures: [], }), - uploaded: async.apply(user.getUserField, data.uid, 'uploadedpicture') + uploaded: async.apply(user.getUserField, data.uid, 'uploadedpicture'), }, function (err, data) { if (err) { return callback(err); @@ -123,11 +122,11 @@ module.exports = function (SocketUser) { data.list.pictures.push({ type: 'uploaded', url: data.uploaded, - text: '[[user:uploaded_picture]]' + text: '[[user:uploaded_picture]]', }); } callback(null, data.list.pictures); }); }; -}; \ No newline at end of file +}; diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 392c7559b7..8e88edb1e5 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -8,7 +8,6 @@ var events = require('../../events'); var privileges = require('../../privileges'); module.exports = function (SocketUser) { - SocketUser.changeUsernameEmail = function (socket, data, callback) { if (!data || !data.uid || !socket.uid) { return callback(new Error('[[error:invalid-data]]')); @@ -20,7 +19,7 @@ module.exports = function (SocketUser) { }, function (next) { SocketUser.updateProfile(socket, data, next); - } + }, ], callback); }; @@ -34,10 +33,10 @@ module.exports = function (SocketUser) { }, function (next) { user.updateCoverPicture(data, next); - } + }, ], callback); }; - + SocketUser.uploadCroppedPicture = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:no-privileges]]')); @@ -48,7 +47,7 @@ module.exports = function (SocketUser) { }, function (next) { user.uploadCroppedPicture(data, next); - } + }, ], callback); }; @@ -63,7 +62,7 @@ module.exports = function (SocketUser) { }, function (next) { user.removeCoverPicture(data, next); - } + }, ], callback); }; @@ -77,7 +76,7 @@ module.exports = function (SocketUser) { } else { next(null, false); } - } + }, }, function (err, results) { if (err) { return callback(err); @@ -114,7 +113,7 @@ module.exports = function (SocketUser) { type: 'password-change', uid: socket.uid, targetUid: data.uid, - ip: socket.ip + ip: socket.ip, }); callback(); }); @@ -146,7 +145,7 @@ module.exports = function (SocketUser) { }, canEdit: function (next) { privileges.users.canEdit(socket.uid, data.uid, next); - } + }, }, next); }, function (results, next) { @@ -175,17 +174,15 @@ module.exports = function (SocketUser) { } if (userData.email !== oldUserData.email) { - log('email-change', {oldEmail: oldUserData.email, newEmail: userData.email}); + log('email-change', { oldEmail: oldUserData.email, newEmail: userData.email }); } if (userData.username !== oldUserData.username) { - log('username-change', {oldUsername: oldUserData.username, newUsername: userData.username}); + log('username-change', { oldUsername: oldUserData.username, newUsername: userData.username }); } next(null, userData); - } + }, ], callback); }; - - -}; \ No newline at end of file +}; diff --git a/src/socket.io/user/search.js b/src/socket.io/user/search.js index 9c3774089d..7d51ead4cf 100644 --- a/src/socket.io/user/search.js +++ b/src/socket.io/user/search.js @@ -5,7 +5,6 @@ var meta = require('../../meta'); var pagination = require('../../pagination'); module.exports = function (SocketUser) { - SocketUser.search = function (socket, data, callback) { if (!data) { return callback(new Error('[[error:invalid-data]]')); @@ -21,7 +20,7 @@ module.exports = function (SocketUser) { onlineOnly: data.onlineOnly, bannedOnly: data.bannedOnly, flaggedOnly: data.flaggedOnly, - uid: socket.uid + uid: socket.uid, }, function (err, result) { if (err) { return callback(err); @@ -31,5 +30,4 @@ module.exports = function (SocketUser) { callback(null, result); }); }; - -}; \ No newline at end of file +}; diff --git a/src/socket.io/user/status.js b/src/socket.io/user/status.js index b3530ffc7d..8849f0210e 100644 --- a/src/socket.io/user/status.js +++ b/src/socket.io/user/status.js @@ -6,7 +6,6 @@ var user = require('../../user'); var websockets = require('../index'); module.exports = function (SocketUser) { - SocketUser.checkStatus = function (socket, uid, callback) { if (!socket.uid) { return callback(new Error('[[error:invalid-uid]]')); @@ -17,7 +16,7 @@ module.exports = function (SocketUser) { }, function (userData, next) { next(null, user.getStatus(userData)); - } + }, ], callback); }; @@ -31,7 +30,7 @@ module.exports = function (SocketUser) { return callback(new Error('[[error:invalid-user-status]]')); } - var data = {status: status}; + var data = { status: status }; if (status !== 'offline') { data.lastonline = Date.now(); } @@ -43,11 +42,11 @@ module.exports = function (SocketUser) { function (next) { var data = { uid: socket.uid, - status: status + status: status, }; websockets.server.emit('event:user_status_change', data); next(null, data); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/start.js b/src/start.js index 06ffc93589..87c0d2bf70 100644 --- a/src/start.js +++ b/src/start.js @@ -35,7 +35,7 @@ start.start = function () { }, function (next) { require('./upgrade').check(next); - } + }, ], function (err) { next(err); }); @@ -53,25 +53,25 @@ start.start = function () { } webserver.listen(next); - } + }, ], function (err) { if (err) { - switch(err.message) { - case 'schema-out-of-date': - winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); - winston.warn(' ./nodebb upgrade'); - break; - case 'dependencies-out-of-date': - winston.warn('One or more of NodeBB\'s dependent packages are out-of-date. Please run the following command to update them:'); - winston.warn(' ./nodebb upgrade'); - break; - case 'dependencies-missing': - winston.warn('One or more of NodeBB\'s dependent packages are missing. Please run the following command to update them:'); - winston.warn(' ./nodebb upgrade'); - break; - default: - winston.error(err); - break; + switch (err.message) { + case 'schema-out-of-date': + winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); + winston.warn(' ./nodebb upgrade'); + break; + case 'dependencies-out-of-date': + winston.warn('One or more of NodeBB\'s dependent packages are out-of-date. Please run the following command to update them:'); + winston.warn(' ./nodebb upgrade'); + break; + case 'dependencies-missing': + winston.warn('One or more of NodeBB\'s dependent packages are missing. Please run the following command to update them:'); + winston.warn(' ./nodebb upgrade'); + break; + default: + winston.error(err); + break; } // Either way, bad stuff happened. Abort start. @@ -80,7 +80,7 @@ start.start = function () { if (process.send) { process.send({ - action: 'listening' + action: 'listening', }); } }); @@ -126,8 +126,8 @@ function addProcessHandlers() { var meta = require('./meta'); switch (message.action) { - case 'reload': - meta.reload(); + case 'reload': + meta.reload(); break; } }); @@ -144,7 +144,7 @@ function restart() { if (process.send) { winston.info('[app] Restarting...'); process.send({ - action: 'restart' + action: 'restart', }); } else { winston.error('[app] Could not restart server. Shutting down.'); diff --git a/src/topics.js b/src/topics.js index 75aeb46564..164200016d 100644 --- a/src/topics.js +++ b/src/topics.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var _ = require('underscore'); @@ -13,7 +13,6 @@ var privileges = require('./privileges'); var social = require('./social'); (function (Topics) { - require('./topics/data')(Topics); require('./topics/create')(Topics); require('./topics/delete')(Topics); @@ -50,7 +49,7 @@ var social = require('./social'); }, function (settings, next) { next(null, Math.ceil((parseInt(postCount, 10) - 1) / settings.postsPerPage)); - } + }, ], callback); }; @@ -68,8 +67,8 @@ var social = require('./social'); Topics.getTopics(tids, uid, next); }, function (topics, next) { - next(null, {topics: topics, nextStart: stop + 1}); - } + next(null, { topics: topics, nextStart: stop + 1 }); + }, ], callback); }; @@ -80,7 +79,7 @@ var social = require('./social'); }, function (tids, next) { Topics.getTopicsByTids(tids, uid, next); - } + }, ], callback); }; @@ -89,7 +88,9 @@ var social = require('./social'); return callback(null, []); } - var uids, cids, topics; + var uids; + var cids; + var topics; async.waterfall([ function (next) { @@ -129,14 +130,14 @@ var social = require('./social'); }, tags: function (next) { Topics.getTopicsTagsObjects(tids, next); - } + }, }, next); }, function (results, next) { var users = _.object(uids, results.users); var categories = _.object(cids, results.categories); - for (var i = 0; i < topics.length; ++i) { + for (var i = 0; i < topics.length; i += 1) { if (topics[i]) { topics[i].category = categories[topics[i].cid]; topics[i].user = users[topics[i].uid]; @@ -160,11 +161,11 @@ var social = require('./social'); return topic && topic.category && !topic.category.disabled; }); - plugins.fireHook('filter:topics.get', {topics: topics, uid: uid}, next); + plugins.fireHook('filter:topics.get', { topics: topics, uid: uid }, next); }, function (data, next) { next(null, data.topics); - } + }, ], callback); }; @@ -174,11 +175,12 @@ var social = require('./social'); async.parallel({ posts: async.apply(getMainPostAndReplies, topicData, set, uid, start, stop, reverse), category: async.apply(Topics.getCategoryData, topicData.tid), - threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', {topic: topicData, uid: uid, tools: []}), + threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', { topic: topicData, uid: uid, tools: [] }), isFollowing: async.apply(Topics.isFollowing, [topicData.tid], uid), isIgnoring: async.apply(Topics.isIgnoring, [topicData.tid], uid), bookmark: async.apply(Topics.getUserBookmark, topicData.tid, uid), postSharing: async.apply(social.getActivePostSharing), + deleter: async.apply(getDeleter, topicData), related: function (next) { async.waterfall([ function (next) { @@ -187,9 +189,9 @@ var social = require('./social'); function (tags, next) { topicData.tags = tags; Topics.getRelatedTopics(topicData, uid, next); - } + }, ], next); - } + }, }, next); }, function (results, next) { @@ -201,6 +203,8 @@ var social = require('./social'); topicData.isIgnoring = results.isIgnoring[0]; topicData.bookmark = results.bookmark; topicData.postSharing = results.postSharing; + topicData.deleter = results.deleter; + topicData.deletedTimestampISO = utils.toISOString(topicData.deletedTimestamp); topicData.related = results.related || []; topicData.unreplied = parseInt(topicData.postcount, 10) === 1; @@ -210,11 +214,11 @@ var social = require('./social'); topicData.icons = []; - plugins.fireHook('filter:topic.get', {topic: topicData, uid: uid}, next); + plugins.fireHook('filter:topic.get', { topic: topicData, uid: uid }, next); }, function (data, next) { next(null, data.topic); - } + }, ], callback); }; @@ -222,9 +226,9 @@ var social = require('./social'); async.waterfall([ function (next) { if (stop > 0) { - stop--; + stop -= 1; if (start > 0) { - start --; + start -= 1; } } @@ -253,10 +257,17 @@ var social = require('./social'); Topics.calculatePostIndices(replies, start, stop, topic.postcount, reverse); Topics.addPostData(posts, uid, next); - } + }, ], callback); } + function getDeleter(topicData, callback) { + if (!topicData.deleterUid) { + return setImmediate(callback, null, null); + } + user.getUserFields(topicData.deleterUid, ['username', 'userslug', 'picture'], callback); + } + Topics.getMainPost = function (tid, uid, callback) { Topics.getMainPosts([tid], uid, function (err, mainPosts) { callback(err, Array.isArray(mainPosts) && mainPosts.length ? mainPosts[0] : null); @@ -313,11 +324,10 @@ var social = require('./social'); if (plugins.hasListeners('filter:topic.search')) { plugins.fireHook('filter:topic.search', { tid: tid, - term: term + term: term, }, callback); } else { - callback(new Error('no-plugins-available'), []); + callback(new Error('[[error:no-plugins-available]]'), []); } }; - }(exports)); diff --git a/src/topics/bookmarks.js b/src/topics/bookmarks.js index 8ec80cfdcb..b47d5f2278 100644 --- a/src/topics/bookmarks.js +++ b/src/topics/bookmarks.js @@ -7,7 +7,6 @@ var db = require('../database'); var posts = require('../posts'); module.exports = function (Topics) { - Topics.getUserBookmark = function (tid, uid, callback) { db.sortedSetScore('tid:' + tid + ':bookmarks', uid, callback); }; @@ -44,13 +43,13 @@ module.exports = function (Topics) { }, function (bookmarks, next) { var forkedPosts = pids.map(function (pid) { - return {pid: pid, tid: tid}; + return { pid: pid, tid: tid }; }); var uidData = bookmarks.map(function (bookmark) { return { uid: bookmark.value, - bookmark: bookmark.score + bookmark: bookmark.score, }; }); @@ -63,8 +62,8 @@ module.exports = function (Topics) { var bookmark = data.bookmark; bookmark = bookmark < maxIndex ? bookmark : maxIndex; - for (var i = 0; i < postIndices.length && postIndices[i] < data.bookmark; ++i) { - --bookmark; + for (var i = 0; i < postIndices.length && postIndices[i] < data.bookmark; i += 1) { + bookmark -= 1; } if (parseInt(bookmark, 10) !== parseInt(data.bookmark, 10)) { @@ -74,10 +73,9 @@ module.exports = function (Topics) { } }); }, next); - } + }, ], function (err) { callback(err); }); }; - }; diff --git a/src/topics/create.js b/src/topics/create.js index bf62266ecf..da16489f05 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -15,7 +15,6 @@ var privileges = require('../privileges'); var categories = require('../categories'); module.exports = function (Topics) { - Topics.create = function (data, callback) { // This is an internal method, consider using Topics.post instead var timestamp = data.timestamp || Date.now(); @@ -30,26 +29,26 @@ module.exports = function (Topics) { }, function (tid, next) { topicData = { - 'tid': tid, - 'uid': data.uid, - 'cid': data.cid, - 'mainPid': 0, - 'title': data.title, - 'slug': tid + '/' + (utils.slugify(data.title) || 'topic'), - 'timestamp': timestamp, - 'lastposttime': 0, - 'postcount': 0, - 'viewcount': 0, - 'locked': 0, - 'deleted': 0, - 'pinned': 0 + tid: tid, + uid: data.uid, + cid: data.cid, + mainPid: 0, + title: data.title, + slug: tid + '/' + (utils.slugify(data.title) || 'topic'), + timestamp: timestamp, + lastposttime: 0, + postcount: 0, + viewcount: 0, + locked: 0, + deleted: 0, + pinned: 0, }; if (data.thumb) { topicData.thumb = data.thumb; } - plugins.fireHook('filter:topic.create', {topic: topicData, data: data}, next); + plugins.fireHook('filter:topic.create', { topic: topicData, data: data }, next); }, function (data, next) { topicData = data.topic; @@ -61,7 +60,7 @@ module.exports = function (Topics) { db.sortedSetsAdd([ 'topics:tid', 'cid:' + topicData.cid + ':tids', - 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids' + 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', ], timestamp, topicData.tid, next); }, function (next) { @@ -78,13 +77,13 @@ module.exports = function (Topics) { }, function (next) { Topics.createTags(data.tags, topicData.tid, timestamp, next); - } + }, ], next); }, function (results, next) { plugins.fireHook('action:topic.save', topicData); next(null, topicData.tid); - } + }, ], callback); }; @@ -160,7 +159,7 @@ module.exports = function (Topics) { }, topicData: function (next) { Topics.getTopicsByTids([postData.tid], uid, next); - } + }, }, next); }, function (data, next) { @@ -182,9 +181,9 @@ module.exports = function (Topics) { next(null, { topicData: data.topicData, - postData: data.postData + postData: data.postData, }); - } + }, ], callback); }; @@ -248,7 +247,7 @@ module.exports = function (Topics) { content: content, toPid: data.toPid, timestamp: data.timestamp, - ip: data.req ? data.req.ip : null + ip: data.req ? data.req.ip : null, }, next); }, function (_postData, next) { @@ -272,7 +271,7 @@ module.exports = function (Topics) { plugins.fireHook('action:topic.reply', postData); next(null, postData); - } + }, ], callback); }; @@ -299,7 +298,7 @@ module.exports = function (Topics) { }, content: function (next) { posts.parsePost(postData, next); - } + }, }, next); }, function (results, next) { @@ -323,14 +322,14 @@ module.exports = function (Topics) { postData.topic.title = validator.escape(String(postData.topic.title)); next(null, postData); - } + }, ], callback); } function check(item, min, max, minError, maxError, callback) { // Trim and remove HTML (latter for composers that send in HTML, like redactor) if (typeof item === 'string') { - item = S(item.trim()).stripTags().s; + item = S(item).stripTags().s.trim(); } if (!item || item.length < parseInt(min, 10)) { @@ -356,5 +355,4 @@ module.exports = function (Topics) { } callback(); } - }; diff --git a/src/topics/data.js b/src/topics/data.js index a0196e1508..17e060f679 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -7,7 +7,6 @@ var categories = require('../categories'); var utils = require('../../public/src/utils'); module.exports = function (Topics) { - Topics.getTopicField = function (tid, field, callback) { db.getObjectField('topic:' + tid, field, callback); }; @@ -40,7 +39,7 @@ module.exports = function (Topics) { Topics.getTopicsData = function (tids, callback) { var keys = []; - for (var i = 0; i < tids.length; ++i) { + for (var i = 0; i < tids.length; i += 1) { keys.push('topic:' + tids[i]); } @@ -88,4 +87,7 @@ module.exports = function (Topics) { db.deleteObjectField('topic:' + tid, field, callback); }; -}; \ No newline at end of file + Topics.deleteTopicFields = function (tid, fields, callback) { + db.deleteObjectFields('topic:' + tid, fields, callback); + }; +}; diff --git a/src/topics/delete.js b/src/topics/delete.js index 91c1bf53e3..082244f96d 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -10,79 +10,91 @@ var batch = require('../batch'); module.exports = function (Topics) { - Topics.delete = function (tid, uid, callback) { - Topics.getTopicFields(tid, ['cid'], function (err, topicData) { - if (err) { - return callback(err); - } - - async.parallel([ - function (next) { - Topics.setTopicField(tid, 'deleted', 1, next); - }, - function (next) { - db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); - }, - function (next) { - Topics.getPids(tid, function (err, pids) { - if (err) { - return next(err); - } - db.sortedSetRemove('cid:' + topicData.cid + ':pids', pids, next); - }); - } - ], function (err) { - callback(err); - }); + async.parallel([ + function (next) { + Topics.setTopicFields(tid, { + deleted: 1, + deleterUid: uid, + deletedTimestamp: Date.now(), + }, next); + }, + function (next) { + db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); + }, + function (next) { + async.waterfall([ + function (next) { + async.parallel({ + cid: function (next) { + Topics.getTopicField(tid, 'cid', next); + }, + pids: function (next) { + Topics.getPids(tid, next); + }, + }, next); + }, + function (results, next) { + db.sortedSetRemove('cid:' + results.cid + ':pids', results.pids, next); + }, + ], next); + }, + ], function (err) { + callback(err); }); }; Topics.restore = function (tid, uid, callback) { - Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], function (err, topicData) { - if (err) { - return callback(err); - } - - async.parallel([ - function (next) { - Topics.setTopicField(tid, 'deleted', 0, next); - }, - function (next) { - Topics.updateRecent(tid, topicData.lastposttime, next); - }, - function (next) { - db.sortedSetAdd('topics:posts', topicData.postcount, tid, next); - }, - function (next) { - db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); - }, - function (next) { - Topics.getPids(tid, function (err, pids) { - if (err) { - return callback(err); - } - - posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], function (err, postData) { - if (err) { - return next(err); - } - postData = postData.filter(function (post) { - return post && parseInt(post.deleted, 10) !== 1; - }); - var pidsToAdd = [], scores = []; - postData.forEach(function (post) { - pidsToAdd.push(post.pid); - scores.push(post.timestamp); - }); - db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next); - }); - }); - } - ], function (err) { - callback(err); - }); - }); + var topicData; + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], next); + }, + function (_topicData, next) { + topicData = _topicData; + async.parallel([ + function (next) { + Topics.setTopicField(tid, 'deleted', 0, next); + }, + function (next) { + Topics.deleteTopicFields(tid, ['deleterUid', 'deletedTimestamp'], next); + }, + function (next) { + Topics.updateRecent(tid, topicData.lastposttime, next); + }, + function (next) { + db.sortedSetAdd('topics:posts', topicData.postcount, tid, next); + }, + function (next) { + db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); + }, + function (next) { + async.waterfall([ + function (next) { + Topics.getPids(tid, next); + }, + function (pids, next) { + posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], next); + }, + function (postData, next) { + postData = postData.filter(function (post) { + return post && parseInt(post.deleted, 10) !== 1; + }); + var pidsToAdd = []; + var scores = []; + postData.forEach(function (post) { + pidsToAdd.push(post.pid); + scores.push(post.timestamp); + }); + db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next); + }, + ], next); + }, + ], function (err) { + next(err); + }); + }, + ], callback); }; Topics.purgePostsAndTopic = function (tid, uid, callback) { @@ -97,14 +109,14 @@ module.exports = function (Topics) { async.eachLimit(pids, 10, function (pid, next) { posts.purge(pid, uid, next); }, next); - }, {alwaysStartAt: 0}, next); + }, { alwaysStartAt: 0 }, next); }, function (next) { posts.purge(mainPid, uid, next); }, function (next) { Topics.purge(tid, uid, next); - } + }, ], callback); }; @@ -122,7 +134,7 @@ module.exports = function (Topics) { 'tid:' + tid + ':posts', 'tid:' + tid + ':posts:votes', 'tid:' + tid + ':bookmarks', - 'tid:' + tid + ':posters' + 'tid:' + tid + ':posters', ], next); }, function (next) { @@ -136,16 +148,16 @@ module.exports = function (Topics) { }, function (next) { reduceCounters(tid, next); - } - ], next); - } - ], function (err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:topic.purge', tid); - db.delete('topic:' + tid, callback); - }); + }, + ], function (err) { + next(err); + }); + }, + function (next) { + plugins.fireHook('action:topic.purge', tid); + db.delete('topic:' + tid, next); + }, + ], callback); }; function deleteFromFollowersIgnorers(tid, callback) { @@ -153,7 +165,7 @@ module.exports = function (Topics) { function (next) { async.parallel({ followers: async.apply(db.getSetMembers, 'tid:' + tid + ':followers'), - ignorers: async.apply(db.getSetMembers, 'tid:' + tid + ':ignorers') + ignorers: async.apply(db.getSetMembers, 'tid:' + tid + ':ignorers'), }, next); }, function (results, next) { @@ -164,29 +176,33 @@ module.exports = function (Topics) { return 'uid:' + uid + 'ignored_tids'; }); db.sortedSetsRemove(followerKeys.concat(ignorerKeys), tid, next); - } + }, ], callback); } function deleteTopicFromCategoryAndUser(tid, callback) { - Topics.getTopicFields(tid, ['cid', 'uid'], function (err, topicData) { - if (err) { - return callback(err); - } - async.parallel([ - function (next) { - db.sortedSetsRemove([ - 'cid:' + topicData.cid + ':tids', - 'cid:' + topicData.cid + ':tids:pinned', - 'cid:' + topicData.cid + ':tids:posts', - 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', - 'uid:' + topicData.uid + ':topics' - ], tid, next); - }, - function (next) { - user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next); - } - ], callback); + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'uid'], next); + }, + function (topicData, next) { + async.parallel([ + function (next) { + db.sortedSetsRemove([ + 'cid:' + topicData.cid + ':tids', + 'cid:' + topicData.cid + ':tids:pinned', + 'cid:' + topicData.cid + ':tids:posts', + 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', + 'uid:' + topicData.uid + ':topics', + ], tid, next); + }, + function (next) { + user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next); + }, + ], next); + }, + ], function (err) { + callback(err); }); } @@ -197,27 +213,29 @@ module.exports = function (Topics) { db.incrObjectFieldBy('global', 'topicCount', incr, next); }, function (next) { - Topics.getTopicFields(tid, ['cid', 'postcount'], function (err, topicData) { - if (err) { - return next(err); - } - topicData.postcount = parseInt(topicData.postcount, 10); - topicData.postcount = topicData.postcount || 0; - var postCountChange = incr * topicData.postcount; + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'postcount'], next); + }, + function (topicData, next) { + topicData.postcount = parseInt(topicData.postcount, 10); + topicData.postcount = topicData.postcount || 0; + var postCountChange = incr * topicData.postcount; - async.parallel([ - function (next) { - db.incrObjectFieldBy('global', 'postCount', postCountChange, next); - }, - function (next) { - db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next); - }, - function (next) { - db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next); - } - ], next); - }); - } + async.parallel([ + function (next) { + db.incrObjectFieldBy('global', 'postCount', postCountChange, next); + }, + function (next) { + db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next); + }, + function (next) { + db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next); + }, + ], next); + }, + ], next); + }, ], callback); } }; diff --git a/src/topics/follow.js b/src/topics/follow.js index 4775cdb9bc..a3b1041b13 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -16,7 +16,6 @@ var emailer = require('../emailer'); var plugins = require('../plugins'); module.exports = function (Topics) { - Topics.toggleFollow = function (tid, uid, callback) { callback = callback || function () {}; var isFollowing; @@ -40,7 +39,7 @@ module.exports = function (Topics) { }, function (next) { next(null, !isFollowing); - } + }, ], callback); }; @@ -75,9 +74,9 @@ module.exports = function (Topics) { method2(tid, uid, next); }, function (next) { - plugins.fireHook(hook, {uid: uid, tid: tid}); + plugins.fireHook(hook, { uid: uid, tid: tid }); next(); - } + }, ], callback); } @@ -104,7 +103,7 @@ module.exports = function (Topics) { }, function (next) { db.sortedSetAdd(set2, Date.now(), tid, next); - } + }, ], callback); } @@ -115,7 +114,7 @@ module.exports = function (Topics) { }, function (next) { db.sortedSetRemove(set2, tid, next); - } + }, ], callback); } @@ -158,7 +157,7 @@ module.exports = function (Topics) { return uid && !isIgnoring[index]; }); next(null, readingUids); - } + }, ], callback); }; @@ -233,7 +232,7 @@ module.exports = function (Topics) { tid: postData.topic.tid, from: exceptUid, mergeId: 'notifications:user_posted_to|' + postData.topic.tid, - topicTitle: title + topicTitle: title, }, next); }, function (notification, next) { @@ -248,7 +247,7 @@ module.exports = function (Topics) { async.eachLimit(followers, 3, function (toUid, next) { async.parallel({ userData: async.apply(user.getUserFields, toUid, ['username', 'userslug']), - userSettings: async.apply(user.getSettings, toUid) + userSettings: async.apply(user.getSettings, toUid), }, function (err, data) { if (err) { return next(err); @@ -266,7 +265,7 @@ module.exports = function (Topics) { url: nconf.get('url') + '/topic/' + postData.topic.tid, topicSlug: postData.topic.slug, postCount: postData.topic.postcount, - base_url: nconf.get('url') + base_url: nconf.get('url'), }, next); } else { winston.debug('[topics.notifyFollowers] uid ' + toUid + ' does not have post notifications enabled, skipping.'); @@ -275,7 +274,7 @@ module.exports = function (Topics) { }); }); next(); - } + }, ], callback); }; }; diff --git a/src/topics/fork.js b/src/topics/fork.js index d882cddf00..396ae3d63b 100644 --- a/src/topics/fork.js +++ b/src/topics/fork.js @@ -2,9 +2,8 @@ 'use strict'; var async = require('async'); -var winston = require('winston'); + var db = require('../database'); -var user = require('../user'); var posts = require('../posts'); var privileges = require('../privileges'); var plugins = require('../plugins'); @@ -12,7 +11,6 @@ var meta = require('../meta'); module.exports = function (Topics) { - Topics.createTopicFromPosts = function (uid, title, pids, fromTid, callback) { if (title) { title = title.trim(); @@ -46,17 +44,17 @@ module.exports = function (Topics) { }, isAdminOrMod: function (next) { privileges.categories.isAdminOrMod(cid, uid, next); - } + }, }, next); }, function (results, next) { if (!results.isAdminOrMod) { return next(new Error('[[error:no-privileges]]')); } - Topics.create({uid: results.postData.uid, title: title, cid: cid}, next); + Topics.create({ uid: results.postData.uid, title: title, cid: cid }, next); }, function (results, next) { - Topics.updateTopicBookmarks(fromTid, pids, function () { next( null, results );} ); + Topics.updateTopicBookmarks(fromTid, pids, function () { next(null, results); }); }, function (_tid, next) { function move(pid, next) { @@ -76,7 +74,7 @@ module.exports = function (Topics) { }, function (next) { Topics.getTopicData(tid, next); - } + }, ], callback); }; @@ -122,20 +120,20 @@ module.exports = function (Topics) { }, function (next) { Topics.addPostToTopic(tid, postData, next); - } + }, ], next); }, function (results, next) { async.parallel([ async.apply(updateRecentTopic, tid), - async.apply(updateRecentTopic, postData.tid) + async.apply(updateRecentTopic, postData.tid), ], next); - } + }, ], function (err) { if (err) { return callback(err); } - plugins.fireHook('action:post.move', {post: postData, tid: tid}); + plugins.fireHook('action:post.move', { post: postData, tid: tid }); callback(); }); }; @@ -153,7 +151,7 @@ module.exports = function (Topics) { } async.parallel([ async.apply(db.incrObjectFieldBy, 'category:' + topicData[0].cid, 'post_count', -1), - async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1) + async.apply(db.incrObjectFieldBy, 'category:' + topicData[1].cid, 'post_count', 1), ], callback); }); } @@ -171,9 +169,7 @@ module.exports = function (Topics) { }, function (timestamp, next) { Topics.updateTimestamp(tid, timestamp, next); - } + }, ], callback); } - - }; diff --git a/src/topics/popular.js b/src/topics/popular.js index 452f897581..e6d78ad4b4 100644 --- a/src/topics/popular.js +++ b/src/topics/popular.js @@ -5,7 +5,6 @@ var async = require('async'); var privileges = require('../privileges'); module.exports = function (Topics) { - Topics.getPopular = function (term, uid, count, callback) { count = parseInt(count, 10) || 20; @@ -19,7 +18,7 @@ module.exports = function (Topics) { }, function (tids, next) { getTopics(tids, uid, count, next); - } + }, ], callback); }; @@ -46,7 +45,7 @@ module.exports = function (Topics) { }, function (tids, next) { Topics.getTopicsByTids(tids, uid, next); - } + }, ], callback); } }; diff --git a/src/topics/posts.js b/src/topics/posts.js index 97b6f71162..909de0caa4 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -12,7 +12,6 @@ var meta = require('../meta'); var plugins = require('../plugins'); module.exports = function (Topics) { - Topics.onNewPostMade = function (postData, callback) { async.series([ function (next) { @@ -23,7 +22,7 @@ module.exports = function (Topics) { }, function (next) { Topics.addPostToTopic(postData.tid, postData, next); - } + }, ], callback); }; @@ -36,14 +35,14 @@ module.exports = function (Topics) { }, postCount: function (next) { Topics.getTopicField(tid, 'postcount', next); - } + }, }, next); }, function (results, next) { Topics.calculatePostIndices(results.posts, start, stop, results.postCount, reverse); Topics.addPostData(results.posts, uid, next); - } + }, ], callback); }; @@ -78,7 +77,7 @@ module.exports = function (Topics) { userData[uids[index]] = user; }); next(null, userData); - } + }, ], callback); } @@ -95,7 +94,6 @@ module.exports = function (Topics) { getPostUserData('uid', function (uids, next) { posts.getUserInfoForPosts(uids, uid, next); }, next); - }, editors: function (next) { getPostUserData('editor', function (uids, next) { @@ -104,7 +102,7 @@ module.exports = function (Topics) { }, parents: function (next) { Topics.addParentPosts(postData, next); - } + }, }, next); }, function (results, next) { @@ -128,12 +126,12 @@ module.exports = function (Topics) { }); plugins.fireHook('filter:topics.addPostData', { posts: postData, - uid: uid + uid: uid, }, next); }, function (data, next) { next(null, data.posts); - } + }, ], callback); }; @@ -167,8 +165,8 @@ module.exports = function (Topics) { async.apply(posts.getPostsFields, parentPids, ['uid']), function (_parentPosts, next) { parentPosts = _parentPosts; - var parentUids = parentPosts.map(function (postObj) { - return parseInt(postObj.uid, 10); + var parentUids = parentPosts.map(function (postObj) { + return parseInt(postObj.uid, 10); }).filter(function (uid, idx, users) { return users.indexOf(uid) === idx; }); @@ -182,14 +180,14 @@ module.exports = function (Topics) { }); var parents = {}; parentPosts.forEach(function (post, i) { - parents[parentPids[i]] = {username: usersMap[post.uid]}; + parents[parentPids[i]] = { username: usersMap[post.uid] }; }); postData.forEach(function (post) { post.parent = parents[post.toPid]; }); next(); - } + }, ], callback); }; @@ -219,7 +217,7 @@ module.exports = function (Topics) { }, function (mainPost, next) { next(null, parseInt(mainPost.pid, 10) && parseInt(mainPost.deleted, 10) !== 1 ? mainPost.pid.toString() : null); - } + }, ], callback); }; @@ -249,9 +247,9 @@ module.exports = function (Topics) { if (!isDeleted) { latestPid = pids[0]; } - ++index; + index += 1; _next(); - } + }, ], next); }, function () { @@ -281,7 +279,7 @@ module.exports = function (Topics) { var downvotes = parseInt(postData.downvotes, 10) || 0; var votes = upvotes - downvotes; db.sortedSetAdd('tid:' + tid + ':posts:votes', votes, postData.pid, next); - } + }, ], function (err) { next(err); }); @@ -292,7 +290,7 @@ module.exports = function (Topics) { }, function (count, next) { Topics.updateTeaser(tid, next); - } + }, ], callback); }; @@ -301,7 +299,7 @@ module.exports = function (Topics) { function (next) { db.sortedSetsRemove([ 'tid:' + tid + ':posts', - 'tid:' + tid + ':posts:votes' + 'tid:' + tid + ':posts:votes', ], postData.pid, next); }, function (next) { @@ -309,7 +307,7 @@ module.exports = function (Topics) { }, function (count, next) { Topics.updateTeaser(tid, next); - } + }, ], callback); }; @@ -322,7 +320,7 @@ module.exports = function (Topics) { }, pids: function (next) { db.getSortedSetRange('tid:' + tid + ':posts', 0, -1, next); - } + }, }, next); }, function (results, next) { @@ -330,7 +328,7 @@ module.exports = function (Topics) { results.pids = [results.mainPid].concat(results.pids); } next(null, results.pids); - } + }, ], callback); }; @@ -354,7 +352,7 @@ module.exports = function (Topics) { }, function (value, next) { db.sortedSetAdd(set, value, tid, next); - } + }, ], callback); } @@ -369,7 +367,7 @@ module.exports = function (Topics) { }, function (tid, next) { Topics.getTopicField(tid, field, next); - } + }, ], callback); }; @@ -380,12 +378,11 @@ module.exports = function (Topics) { }, function (tid, next) { Topics.getTopicData(tid, next); - } + }, ], callback); }; Topics.getPostCount = function (tid, callback) { db.getObjectField('topic:' + tid, 'postcount', callback); }; - }; diff --git a/src/topics/recent.js b/src/topics/recent.js index 23ca9ff5ba..dbecd035b4 100644 --- a/src/topics/recent.js +++ b/src/topics/recent.js @@ -7,20 +7,20 @@ var db = require('../database'); var plugins = require('../plugins'); var privileges = require('../privileges'); var user = require('../user'); -var categories = require('../categories'); +var categories = require('../categories'); module.exports = function (Topics) { var terms = { day: 86400000, week: 604800000, month: 2592000000, - year: 31104000000 + year: 31104000000, }; Topics.getRecentTopics = function (cid, uid, start, stop, filter, callback) { var recentTopics = { - nextStart : 0, - topics: [] + nextStart: 0, + topics: [], }; async.waterfall([ @@ -43,7 +43,7 @@ module.exports = function (Topics) { recentTopics.topics = topicData; recentTopics.nextStart = stop + 1; next(null, recentTopics); - } + }, ], callback); }; @@ -72,21 +72,20 @@ module.exports = function (Topics) { }, topicData: function (next) { Topics.getTopicsFields(tids, ['tid', 'cid'], next); - } + }, }, next); }, function (results, next) { tids = results.topicData.filter(function (topic) { if (topic) { return results.ignoredCids.indexOf(topic.cid.toString()) === -1; - } else { - return false; } + return false; }).map(function (topic) { return topic.tid; }); next(null, tids); - } + }, ], callback); } @@ -100,8 +99,8 @@ module.exports = function (Topics) { Topics.getTopics(tids, uid, next); }, function (topics, next) { - next(null, {topics: topics, nextStart: stop + 1}); - } + next(null, { topics: topics, nextStart: stop + 1 }); + }, ], callback); }; @@ -128,12 +127,12 @@ module.exports = function (Topics) { return next(); } Topics.updateRecent(tid, timestamp, next); - } + }, ], next); }, function (next) { Topics.setTopicField(tid, 'lastposttime', timestamp, next); - } + }, ], function (err) { callback(err); }); @@ -142,7 +141,7 @@ module.exports = function (Topics) { Topics.updateRecent = function (tid, timestamp, callback) { callback = callback || function () {}; if (plugins.hasListeners('filter:topics.updateRecent')) { - plugins.fireHook('filter:topics.updateRecent', {tid: tid, timestamp: timestamp}, function (err, data) { + plugins.fireHook('filter:topics.updateRecent', { tid: tid, timestamp: timestamp }, function (err, data) { if (err) { return callback(err); } diff --git a/src/topics/suggested.js b/src/topics/suggested.js index d51d51827b..d69471744f 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -8,7 +8,6 @@ var categories = require('../categories'); var search = require('../search'); module.exports = function (Topics) { - Topics.getSuggestedTopics = function (tid, uid, start, stop, callback) { async.parallel({ tagTids: function (next) { @@ -19,7 +18,7 @@ module.exports = function (Topics) { }, categoryTids: function (next) { getCategoryTids(tid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -51,7 +50,7 @@ module.exports = function (Topics) { }, function (data, next) { next(null, _.unique(_.flatten(data))); - } + }, ], callback); } @@ -62,7 +61,7 @@ module.exports = function (Topics) { }, function (title, next) { search.searchQuery('topic', title, [], [], next); - } + }, ], callback); } @@ -73,8 +72,7 @@ module.exports = function (Topics) { }, function (cid, next) { categories.getTopicIds(cid, 'cid:' + cid + ':tids', true, 0, 9, next); - } + }, ], callback); } - -}; \ No newline at end of file +}; diff --git a/src/topics/tags.js b/src/topics/tags.js index a360de290e..d10c127ac0 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -11,7 +11,6 @@ var utils = require('../../public/src/utils'); module.exports = function (Topics) { - Topics.createTags = function (tags, tid, timestamp, callback) { callback = callback || function () {}; @@ -21,7 +20,7 @@ module.exports = function (Topics) { async.waterfall([ function (next) { - plugins.fireHook('filter:tags.filter', {tags: tags, tid: tid}, next); + plugins.fireHook('filter:tags.filter', { tags: tags, tid: tid }, next); }, function (data, next) { tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5); @@ -41,14 +40,14 @@ module.exports = function (Topics) { async.parallel([ async.apply(db.setAdd, 'topic:' + tid + ':tags', tags), - async.apply(db.sortedSetsAdd, keys, timestamp, tid) + async.apply(db.sortedSetsAdd, keys, timestamp, tid), ], function (err) { next(err); }); }, function (next) { async.each(tags, updateTagCount, next); - } + }, ], callback); }; @@ -68,7 +67,7 @@ module.exports = function (Topics) { return tagWhitelist.indexOf(tag) !== -1; }); next(null, tags); - } + }, ], callback); } @@ -91,7 +90,7 @@ module.exports = function (Topics) { return next(); } db.sortedSetAdd('tags:topic:count', 0, tag, next); - } + }, ], callback); }; @@ -112,7 +111,7 @@ module.exports = function (Topics) { count = count || 0; db.sortedSetAdd('tags:topic:count', count, tag, next); - } + }, ], callback); } @@ -146,7 +145,7 @@ module.exports = function (Topics) { db.deleteAll(tags.map(function (tag) { return 'tag:' + tag; }), next); - } + }, ], callback); }; @@ -176,7 +175,7 @@ module.exports = function (Topics) { }, function (tags, next) { Topics.getTagData(tags, next); - } + }, ], callback); }; @@ -195,7 +194,7 @@ module.exports = function (Topics) { tag.bgColor = tagData[index] ? tagData[index].bgColor : ''; }); next(null, tags); - } + }, ], callback); }; @@ -231,7 +230,7 @@ module.exports = function (Topics) { uniqueTopicTags = _.uniq(_.flatten(topicTags)); var tags = uniqueTopicTags.map(function (tag) { - return {value: tag}; + return { value: tag }; }); async.parallel({ @@ -240,7 +239,7 @@ module.exports = function (Topics) { }, counts: function (next) { db.sortedSetScores('tags:topic:count', uniqueTopicTags, next); - } + }, }, next); }, function (results, next) { @@ -252,12 +251,12 @@ module.exports = function (Topics) { topicTags.forEach(function (tags, index) { if (Array.isArray(tags)) { - topicTags[index] = tags.map(function (tag) {return tagData[tag];}); + topicTags[index] = tags.map(function (tag) { return tagData[tag]; }); } }); next(null, topicTags); - } + }, ], callback); }; @@ -272,7 +271,7 @@ module.exports = function (Topics) { }, function (timestamp, next) { Topics.createTags(tags, tid, timestamp, next); - } + }, ], callback); }; @@ -297,9 +296,9 @@ module.exports = function (Topics) { async.each(tags, function (tag, next) { updateTagCount(tag, next); }, next); - } + }, ], next); - } + }, ], function (err) { callback(err); }); @@ -313,17 +312,17 @@ module.exports = function (Topics) { async.waterfall([ function (next) { if (plugins.hasListeners('filter:topics.searchTags')) { - plugins.fireHook('filter:topics.searchTags', {data: data}, next); + plugins.fireHook('filter:topics.searchTags', { data: data }, next); } else { findMatches(data.query, 0, next); } }, function (result, next) { - plugins.fireHook('filter:tags.search', {data: data, matches: result.matches}, next); + plugins.fireHook('filter:tags.search', { data: data, matches: result.matches }, next); }, function (result, next) { next(null, result.matches); - } + }, ], callback); }; @@ -335,14 +334,14 @@ module.exports = function (Topics) { async.waterfall([ function (next) { if (plugins.hasListeners('filter:topics.autocompleteTags')) { - plugins.fireHook('filter:topics.autocompleteTags', {data: data}, next); + plugins.fireHook('filter:topics.autocompleteTags', { data: data }, next); } else { findMatches(data.query, data.cid, next); } }, function (result, next) { next(null, result.matches); - } + }, ], callback); }; @@ -366,7 +365,7 @@ module.exports = function (Topics) { query = query.toLowerCase(); var matches = []; - for(var i = 0; i < tags.length; ++i) { + for (var i = 0; i < tags.length; i += 1) { if (tags[i].toLowerCase().startsWith(query)) { matches.push(tags[i]); if (matches.length > 19) { @@ -378,8 +377,8 @@ module.exports = function (Topics) { matches = matches.sort(function (a, b) { return a > b; }); - next(null, {matches: matches}); - } + next(null, { matches: matches }); + }, ], callback); } @@ -387,7 +386,7 @@ module.exports = function (Topics) { var searchResult = { tags: [], matchCount: 0, - pageCount: 1 + pageCount: 1, }; if (!data || !data.query || !data.query.length) { @@ -404,11 +403,11 @@ module.exports = function (Topics) { }, tagData: function (next) { tags = tags.map(function (tag) { - return {value: tag}; + return { value: tag }; }); Topics.getTagData(tags, next); - } + }, }, next); }, function (results, next) { @@ -422,13 +421,13 @@ module.exports = function (Topics) { searchResult.matchCount = results.tagData.length; searchResult.pageCount = 1; next(null, searchResult); - } + }, ], callback); }; Topics.getRelatedTopics = function (topicData, uid, callback) { if (plugins.hasListeners('filter:topic.getRelatedTopics')) { - return plugins.fireHook('filter:topic.getRelatedTopics', {topic: topicData, uid: uid}, callback); + return plugins.fireHook('filter:topic.getRelatedTopics', { topic: topicData, uid: uid }, callback); } var maximumTopics = parseInt(meta.config.maximumRelatedTopics, 10) || 0; @@ -453,7 +452,7 @@ module.exports = function (Topics) { return topic && !topic.deleted && parseInt(topic.uid, 10) !== parseInt(uid, 10); }); next(null, topics); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/topics/teaser.js b/src/topics/teaser.js index 1467dd194f..aa64d7780f 100644 --- a/src/topics/teaser.js +++ b/src/topics/teaser.js @@ -12,7 +12,6 @@ var plugins = require('../plugins'); var utils = require('../../public/src/utils'); module.exports = function (Topics) { - Topics.getTeasers = function (topics, callback) { if (!Array.isArray(topics) || !topics.length) { return callback(null, []); @@ -30,19 +29,19 @@ module.exports = function (Topics) { delete topic.teaserPid; } - switch(meta.config.teaserPost) { - case 'first': - teaserPids.push(topic.mainPid); - break; + switch (meta.config.teaserPost) { + case 'first': + teaserPids.push(topic.mainPid); + break; - case 'last-post': - teaserPids.push(topic.teaserPid || topic.mainPid); - break; + case 'last-post': + teaserPids.push(topic.teaserPid || topic.mainPid); + break; - case 'last-reply': // intentional fall-through - default: - teaserPids.push(topic.teaserPid); - break; + case 'last-reply': // intentional fall-through + default: + teaserPids.push(topic.teaserPid); + break; } } }); @@ -95,11 +94,11 @@ module.exports = function (Topics) { return tidToPost[topic.tid]; }); - plugins.fireHook('filter:teasers.get', {teasers: teasers}, next); + plugins.fireHook('filter:teasers.get', { teasers: teasers }, next); }, function (data, next) { next(null, data.teasers); - } + }, ], callback); }; @@ -113,7 +112,7 @@ module.exports = function (Topics) { }, function (topics, next) { Topics.getTeasers(topics, next); - } + }, ], callback); }; @@ -137,4 +136,4 @@ module.exports = function (Topics) { } }); }; -}; \ No newline at end of file +}; diff --git a/src/topics/thumb.js b/src/topics/thumb.js index a5ca38ed3e..574ca302ad 100644 --- a/src/topics/thumb.js +++ b/src/topics/thumb.js @@ -16,7 +16,6 @@ var file = require('../file'); var plugins = require('../plugins'); module.exports = function (Topics) { - Topics.resizeAndUploadThumb = function (data, callback) { if (!data.thumb || !validator.isURL(data.thumb)) { return callback(); @@ -30,7 +29,6 @@ module.exports = function (Topics) { request.head(data.thumb, next); }, function (res, body, next) { - var type = res.headers['content-type']; if (!type.match(/image./)) { return next(new Error('[[error:invalid-file]]')); @@ -54,7 +52,7 @@ module.exports = function (Topics) { path: pathToUpload, extension: path.extname(pathToUpload), width: size, - height: size + height: size, }, next); }, function (next) { @@ -63,13 +61,13 @@ module.exports = function (Topics) { return callback(); } - plugins.fireHook('filter:uploadImage', {image: {path: pathToUpload, name: ''}, uid: data.uid}, next); + plugins.fireHook('filter:uploadImage', { image: { path: pathToUpload, name: '' }, uid: data.uid }, next); }, function (uploadedFile, next) { deleteFile(pathToUpload); data.thumb = uploadedFile.url; next(); - } + }, ], function (err) { if (err) { deleteFile(pathToUpload); @@ -87,5 +85,4 @@ module.exports = function (Topics) { }); } } - }; diff --git a/src/topics/tools.js b/src/topics/tools.js index cccffa8c75..f83a5f91f0 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -10,7 +10,6 @@ var privileges = require('../privileges'); module.exports = function (Topics) { - var topicTools = {}; Topics.tools = topicTools; @@ -46,7 +45,7 @@ module.exports = function (Topics) { if (parseInt(topicData.deleted, 10) === 1 && isDelete) { return callback(new Error('[[error:topic-already-deleted]]')); - } else if(parseInt(topicData.deleted, 10) !== 1 && !isDelete) { + } else if (parseInt(topicData.deleted, 10) !== 1 && !isDelete) { return callback(new Error('[[error:topic-already-restored]]')); } @@ -65,11 +64,11 @@ module.exports = function (Topics) { tid: tid, cid: topicData.cid, isDelete: isDelete, - uid: uid + uid: uid, }; next(null, data); - } + }, ], callback); } @@ -98,8 +97,8 @@ module.exports = function (Topics) { Topics.purgePostsAndTopic(tid, uid, next); }, function (next) { - next(null, {tid: tid, cid: cid, uid: uid}); - } + next(null, { tid: tid, cid: cid, uid: uid }); + }, ], callback); }; @@ -139,13 +138,13 @@ module.exports = function (Topics) { tid: tid, isLocked: lock, uid: uid, - cid: cid + cid: cid, }; plugins.fireHook('action:topic.lock', data); next(null, data); - } + }, ], callback); } @@ -185,16 +184,16 @@ module.exports = function (Topics) { async.parallel([ async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:pinned', Date.now(), tid), async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids', tid), - async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', tid) + async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', tid), ], next); } else { async.parallel([ async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:pinned', tid), async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids', topicData.lastposttime, tid), - async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid) + async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid), ], next); } - } + }, ], next); }, function (results, next) { @@ -202,13 +201,13 @@ module.exports = function (Topics) { tid: tid, isPinned: pin, uid: uid, - cid: topicData.cid + cid: topicData.cid, }; plugins.fireHook('action:topic.pin', data); next(null, data); - } + }, ], callback); } @@ -225,7 +224,7 @@ module.exports = function (Topics) { var uniqueCids = _.unique(topicData.map(function (topicData) { return topicData && parseInt(topicData.cid, 10); })); - + if (uniqueCids.length > 1 || !uniqueCids.length || !uniqueCids[0]) { return next(new Error('[[error:invalid-data]]')); } @@ -248,10 +247,10 @@ module.exports = function (Topics) { } else { setImmediate(next); } - } - ], next); + }, + ], next); }, next); - } + }, ], callback); }; @@ -272,7 +271,7 @@ module.exports = function (Topics) { db.sortedSetsRemove([ 'cid:' + topicData.cid + ':tids', 'cid:' + topicData.cid + ':tids:pinned', - 'cid:' + topicData.cid + ':tids:posts' // post count + 'cid:' + topicData.cid + ':tids:posts', // post count ], tid, next); }, function (next) { @@ -286,10 +285,10 @@ module.exports = function (Topics) { function (next) { topic.postcount = topic.postcount || 0; db.sortedSetAdd('cid:' + cid + ':tids:posts', topic.postcount, tid, next); - } + }, ], next); } - } + }, ], function (err) { if (err) { return callback(err); @@ -307,9 +306,9 @@ module.exports = function (Topics) { function (next) { Topics.setTopicFields(tid, { cid: cid, - oldCid: oldCid + oldCid: oldCid, }, next); - } + }, ], function (err) { if (err) { return callback(err); @@ -318,12 +317,10 @@ module.exports = function (Topics) { tid: tid, fromCid: oldCid, toCid: cid, - uid: uid + uid: uid, }); callback(); }); }); }; - - }; diff --git a/src/topics/unread.js b/src/topics/unread.js index e61ca46d59..b2f5b199d1 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -12,7 +12,6 @@ var meta = require('../meta'); var utils = require('../../public/src/utils'); module.exports = function (Topics) { - Topics.getTotalUnread = function (uid, filter, callback) { if (!callback) { callback = filter; @@ -25,11 +24,10 @@ module.exports = function (Topics) { Topics.getUnreadTopics = function (cid, uid, start, stop, filter, callback) { - var unreadTopics = { showSelect: true, - nextStart : 0, - topics: [] + nextStart: 0, + topics: [], }; async.waterfall([ @@ -59,12 +57,13 @@ module.exports = function (Topics) { unreadTopics.topics = topicData; unreadTopics.nextStart = stop + 1; next(null, unreadTopics); - } + }, ], callback); }; Topics.unreadCutoff = function () { - return Date.now() - (parseInt(meta.config.unreadCutoff, 10) || 2) * 86400000; + var cutoff = parseInt(meta.config.unreadCutoff, 10) || 2; + return Date.now() - (cutoff * 86400000); }; Topics.getUnreadTids = function (cid, uid, filter, callback) { @@ -97,7 +96,7 @@ module.exports = function (Topics) { }, tids_unread: function (next) { db.getSortedSetRevRangeWithScores('uid:' + uid + ':tids_unread', 0, -1, next); - } + }, }, next); }, function (results, next) { @@ -122,10 +121,10 @@ module.exports = function (Topics) { return false; } switch (filter) { - case 'new': - return !userRead[recentTopic.value]; - default: - return !userRead[recentTopic.value] || recentTopic.score > userRead[recentTopic.value]; + case 'new': + return !userRead[recentTopic.value]; + default: + return !userRead[recentTopic.value] || recentTopic.score > userRead[recentTopic.value]; } }).map(function (topic) { return topic.value; @@ -140,11 +139,10 @@ module.exports = function (Topics) { } }, function (tids, next) { - tids = tids.slice(0, 200); filterTopics(uid, tids, cid, ignoredCids, filter, next); - } + }, ], callback); }; @@ -168,7 +166,7 @@ module.exports = function (Topics) { return next(null, []); } db.sortedSetScores('uid:' + uid + ':followed_tids', tids, next); - } + }, }, next); }, function (results, next) { @@ -181,7 +179,7 @@ module.exports = function (Topics) { return topic.tid; }); next(null, tids); - } + }, ], callback); } @@ -208,7 +206,7 @@ module.exports = function (Topics) { Topics.markAsRead = function (tids, uid, callback) { callback = callback || function () {}; if (!Array.isArray(tids) || !tids.length) { - return callback(); + return setImmediate(callback, null, false); } tids = tids.filter(function (tid, index, array) { @@ -216,14 +214,14 @@ module.exports = function (Topics) { }); if (!tids.length) { - return callback(null, false); + return setImmediate(callback, null, false); } async.waterfall([ function (next) { async.parallel({ topicScores: async.apply(db.sortedSetScores, 'topics:recent', tids), - userScores: async.apply(db.sortedSetScores, 'uid:' + uid + ':tids_read', tids) + userScores: async.apply(db.sortedSetScores, 'uid:' + uid + ':tids_read', tids), }, next); }, function (results, next) { @@ -243,7 +241,7 @@ module.exports = function (Topics) { async.parallel({ markRead: async.apply(db.sortedSetAdd, 'uid:' + uid + ':tids_read', scores, tids), markUnread: async.apply(db.sortedSetRemove, 'uid:' + uid + ':tids_unread', tids), - topicData: async.apply(Topics.getTopicsFields, tids, ['cid']) + topicData: async.apply(Topics.getTopicsFields, tids, ['cid']), }, next); }, function (results, next) { @@ -257,7 +255,7 @@ module.exports = function (Topics) { }, function (next) { next(null, true); - } + }, ], callback); }; @@ -272,7 +270,7 @@ module.exports = function (Topics) { }, function (markedRead, next) { db.delete('uid:' + uid + ':tids_unread', next); - } + }, ], callback); }; @@ -292,7 +290,7 @@ module.exports = function (Topics) { function (next) { user.notifications.pushCount(uid); next(); - } + }, ], callback); }; @@ -303,7 +301,7 @@ module.exports = function (Topics) { }, function (cid, next) { categories.markAsUnreadForAll(cid, next); - } + }, ], callback); }; @@ -323,7 +321,7 @@ module.exports = function (Topics) { }, tids_unread: function (next) { db.sortedSetScores('uid:' + uid + ':tids_unread', tids, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -359,7 +357,7 @@ module.exports = function (Topics) { }, function (next) { db.sortedSetAdd('uid:' + uid + ':tids_unread', Date.now(), tid, next); - } + }, ], callback); }; @@ -374,5 +372,4 @@ module.exports = function (Topics) { callback(null, tids); }); }; - }; diff --git a/src/topics/user.js b/src/topics/user.js index ab56a5f778..d0a8d21426 100644 --- a/src/topics/user.js +++ b/src/topics/user.js @@ -1,13 +1,8 @@ - - 'use strict'; -var async = require('async'); var db = require('../database'); -var posts = require('../posts'); module.exports = function (Topics) { - Topics.isOwner = function (tid, uid, callback) { uid = parseInt(uid, 10); if (!uid) { @@ -21,4 +16,4 @@ module.exports = function (Topics) { Topics.getUids = function (tid, callback) { db.getSortedSetRevRangeByScore('tid:' + tid + ':posters', 0, -1, '+inf', 1, callback); }; -}; \ No newline at end of file +}; diff --git a/src/upgrade.js b/src/upgrade.js index 4aca187a7a..0ab9984646 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -1,6 +1,5 @@ -"use strict"; +'use strict'; -/* globals console, require */ var db = require('./database'); var async = require('async'); @@ -13,7 +12,7 @@ var schemaDate; var thisSchemaDate; // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema -var latestSchema = Date.UTC(2016, 10, 22); +var latestSchema = Date.UTC(2017, 1, 28); Upgrade.check = function (callback) { db.get('schemaDate', function (err, value) { @@ -53,7 +52,7 @@ Upgrade.upgrade = function (callback) { return next(err); } - if(!value) { + if (!value) { db.set('schemaDate', latestSchema, function () { next(); }); @@ -131,7 +130,7 @@ Upgrade.upgrade = function (callback) { }, function (next) { db.deleteObjectField('post:' + id, 'reputation', next); - } + }, ], next); }, next); }, {}, next); @@ -187,7 +186,7 @@ Upgrade.upgrade = function (callback) { console.log('processing pid: ' + postData.pid + ' toPid: ' + postData.toPid); async.parallel([ async.apply(db.sortedSetAdd, 'pid:' + postData.toPid + ':replies', postData.timestamp, postData.pid), - async.apply(db.incrObjectField, 'post:' + postData.toPid, 'replies') + async.apply(db.incrObjectField, 'post:' + postData.toPid, 'replies'), ], next); }, next); }); @@ -242,23 +241,23 @@ Upgrade.upgrade = function (callback) { async.waterfall([ async.apply(db.getObjectField, 'user:' + uid + ':settings', 'userLang'), function (language, next) { - ++i; + i += 1; if (!language) { return setImmediate(next); } newLanguage = language.replace('_', '-').replace('@', '-x-'); if (newLanguage !== language) { - ++j; + j += 1; user.setSetting(uid, 'userLang', newLanguage, next); } else { setImmediate(next); } - } + }, ], next); }, next); }, next); - } + }, ], function (err) { if (err) { return next(err); @@ -297,7 +296,7 @@ Upgrade.upgrade = function (callback) { async.parallel([ async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:pinned', Date.now(), topicData.tid), async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids', topicData.tid), - async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', topicData.tid) + async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', topicData.tid), ], next); }, next); }); @@ -314,17 +313,129 @@ Upgrade.upgrade = function (callback) { next(); } }, + function (next) { + thisSchemaDate = Date.UTC(2017, 1, 25); + var schemaName = '[2017/2/25] Update global and user sound settings'; + + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.verbose(schemaName); + + var meta = require('./meta'); + var batch = require('./batch'); + + var map = { + 'notification.mp3': 'Default | Deedle-dum', + 'waterdrop-high.mp3': 'Default | Water drop (high)', + 'waterdrop-low.mp3': 'Default | Water drop (low)', + }; + + async.parallel([ + function (cb) { + var keys = ['chat-incoming', 'chat-outgoing', 'notification']; + + db.getObject('settings:sounds', function (err, settings) { + if (err || !settings) { + return cb(err); + } + + keys.forEach(function (key) { + if (settings[key] && settings[key].indexOf(' | ') === -1) { + settings[key] = map[settings[key]] || ''; + } + }); + + meta.configs.setMultiple(settings, cb); + }); + }, + function (cb) { + var keys = ['notificationSound', 'incomingChatSound', 'outgoingChatSound']; + + batch.processSortedSet('users:joindate', function (ids, next) { + async.each(ids, function (uid, next) { + db.getObject('user:' + uid + ':settings', function (err, settings) { + if (err || !settings) { + return next(err); + } + var newSettings = {}; + keys.forEach(function (key) { + if (settings[key] && settings[key].indexOf(' | ') === -1) { + newSettings[key] = map[settings[key]] || ''; + } + }); + + if (Object.keys(newSettings).length) { + db.setObject('user:' + uid + ':settings', newSettings, next); + } else { + setImmediate(next); + } + }); + }, next); + }, cb); + }, + ], function (err) { + if (err) { + return next(err); + } + winston.info(schemaName + ' - done'); + Upgrade.update(thisSchemaDate, next); + }); + } else { + winston.info(schemaName + ' - skipped!'); + next(); + } + }, + function (next) { + thisSchemaDate = Date.UTC(2017, 1, 28); + var schemaName = '[2017/2/28] Update urls in config to `/assets`'; + + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info(schemaName); + async.waterfall([ + function (cb) { + db.getObject('config', cb); + }, + function (config, cb) { + if (!config) { + return cb(); + } + + var keys = ['brand:favicon', 'brand:touchicon', 'og:image', 'brand:logo:url', 'defaultAvatar', 'profile:defaultCovers']; + + keys.forEach(function (key) { + var oldValue = config[key]; + + if (!oldValue || typeof oldValue !== 'string') { + return; + } + + config[key] = oldValue.replace(/(?:\/assets)?\/(images|uploads)\//g, '/assets/$1/'); + }); + + db.setObject('config', config, cb); + }, + function (next) { + winston.info(schemaName + ' - done'); + Upgrade.update(thisSchemaDate, next); + }, + ], next); + } else { + winston.info(schemaName + ' - skipped!'); + next(); + } + }, // Add new schema updates here // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 24!!! ], function (err) { if (!err) { - if(updatesMade) { + if (updatesMade) { winston.info('[upgrade] Schema update complete!'); } else { winston.info('[upgrade] Schema already up to date!'); } } else { - switch(err.message) { + switch (err.message) { case 'upgrade-not-possible': winston.error('[upgrade] NodeBB upgrade could not complete, as your database schema is too far out of date.'); winston.error('[upgrade] Please ensure that you did not skip any minor version upgrades.'); diff --git a/src/user.js b/src/user.js index 00e5824690..48098feadf 100644 --- a/src/user.js +++ b/src/user.js @@ -6,382 +6,324 @@ var _ = require('underscore'); var groups = require('./groups'); var plugins = require('./plugins'); var db = require('./database'); -var topics = require('./topics'); var privileges = require('./privileges'); var meta = require('./meta'); -(function (User) { +var User = module.exports; - User.email = require('./user/email'); - User.notifications = require('./user/notifications'); - User.reset = require('./user/reset'); - User.digest = require('./user/digest'); +User.email = require('./user/email'); +User.notifications = require('./user/notifications'); +User.reset = require('./user/reset'); +User.digest = require('./user/digest'); - require('./user/data')(User); - require('./user/auth')(User); - require('./user/bans')(User); - require('./user/create')(User); - require('./user/posts')(User); - require('./user/topics')(User); - require('./user/categories')(User); - require('./user/follow')(User); - require('./user/profile')(User); - require('./user/admin')(User); - require('./user/delete')(User); - require('./user/settings')(User); - require('./user/search')(User); - require('./user/jobs')(User); - require('./user/picture')(User); - require('./user/approval')(User); - require('./user/invite')(User); - require('./user/password')(User); - require('./user/info')(User); - - User.updateLastOnlineTime = function (uid, callback) { - callback = callback || function () {}; - db.getObjectFields('user:' + uid, ['status', 'lastonline'], function (err, userData) { - var now = Date.now(); - if (err || userData.status === 'offline' || now - parseInt(userData.lastonline, 10) < 300000) { - return callback(err); - } - User.setUserField(uid, 'lastonline', now, callback); - }); - }; - - User.updateOnlineUsers = function (uid, callback) { - callback = callback || function () {}; +require('./user/data')(User); +require('./user/auth')(User); +require('./user/bans')(User); +require('./user/create')(User); +require('./user/posts')(User); +require('./user/topics')(User); +require('./user/categories')(User); +require('./user/follow')(User); +require('./user/profile')(User); +require('./user/admin')(User); +require('./user/delete')(User); +require('./user/settings')(User); +require('./user/search')(User); +require('./user/jobs')(User); +require('./user/picture')(User); +require('./user/approval')(User); +require('./user/invite')(User); +require('./user/password')(User); +require('./user/info')(User); +require('./user/online')(User); +User.getUidsFromSet = function (set, start, stop, callback) { + if (set === 'users:online') { + var count = parseInt(stop, 10) === -1 ? stop : stop - start + 1; var now = Date.now(); - async.waterfall([ - function (next) { - db.sortedSetScore('users:online', uid, next); - }, - function (userOnlineTime, next) { - if (now - parseInt(userOnlineTime, 10) < 300000) { - return callback(); - } - db.sortedSetAdd('users:online', now, uid, next); - }, - function (next) { - topics.pushUnreadCount(uid); - plugins.fireHook('action:user.online', {uid: uid, timestamp: now}); - next(); - } - ], callback); - }; + db.getSortedSetRevRangeByScore(set, start, count, '+inf', now - 300000, callback); + } else { + db.getSortedSetRevRange(set, start, stop, callback); + } +}; - User.getUidsFromSet = function (set, start, stop, callback) { - if (set === 'users:online') { - var count = parseInt(stop, 10) === -1 ? stop : stop - start + 1; - var now = Date.now(); - db.getSortedSetRevRangeByScore(set, start, count, '+inf', now - 300000, callback); - } else { - db.getSortedSetRevRange(set, start, stop, callback); - } - }; +User.getUsersFromSet = function (set, uid, start, stop, callback) { + async.waterfall([ + function (next) { + User.getUidsFromSet(set, start, stop, next); + }, + function (uids, next) { + User.getUsers(uids, uid, next); + }, + ], callback); +}; - User.getUsersFromSet = function (set, uid, start, stop, callback) { - async.waterfall([ - function (next) { - User.getUidsFromSet(set, start, stop, next); - }, - function (uids, next) { - User.getUsers(uids, uid, next); - } - ], callback); - }; - - User.getUsersWithFields = function (uids, fields, uid, callback) { - async.waterfall([ - function (next) { - plugins.fireHook('filter:users.addFields', {fields: fields}, next); - }, - function (data, next) { - data.fields = data.fields.filter(function (field, index, array) { - return array.indexOf(field) === index; - }); - - async.parallel({ - userData: function (next) { - User.getUsersFields(uids, data.fields, next); - }, - isAdmin: function (next) { - User.isAdministrator(uids, next); - } - }, next); - }, - function (results, next) { - results.userData.forEach(function (user, index) { - if (user) { - user.status = User.getStatus(user); - user.administrator = results.isAdmin[index]; - user.banned = parseInt(user.banned, 10) === 1; - user.banned_until = parseInt(user['banned:expire'], 10) || 0; - user.banned_until_readable = user.banned_until ? new Date(user.banned_until).toString() : 'Not Banned'; - user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1; - } - }); - plugins.fireHook('filter:userlist.get', {users: results.userData, uid: uid}, next); - }, - function (data, next) { - next(null, data.users); - } - ], callback); - }; - - User.getUsers = function (uids, uid, callback) { - var fields = ['uid', 'username', 'userslug', 'picture', 'status', 'flags', - 'banned', 'banned:expire', 'joindate', 'postcount', 'reputation', 'email:confirmed', 'lastonline']; - - User.getUsersWithFields(uids, fields, uid, callback); - }; - - User.getStatus = function (userData) { - var isOnline = (Date.now() - parseInt(userData.lastonline, 10)) < 300000; - return isOnline ? (userData.status || 'online') : 'offline'; - }; - - User.isOnline = function (uid, callback) { - if (Array.isArray(uid)) { - db.sortedSetScores('users:online', uid, function (err, lastonline) { - if (err) { - return callback(err); - } - var now = Date.now(); - var isOnline = uid.map(function (uid, index) { - return now - lastonline[index] < 300000; - }); - callback(null, isOnline); +User.getUsersWithFields = function (uids, fields, uid, callback) { + async.waterfall([ + function (next) { + plugins.fireHook('filter:users.addFields', { fields: fields }, next); + }, + function (data, next) { + data.fields = data.fields.filter(function (field, index, array) { + return array.indexOf(field) === index; }); - } else { - db.sortedSetScore('users:online', uid, function (err, lastonline) { - if (err) { - return callback(err); + + async.parallel({ + userData: function (next) { + User.getUsersFields(uids, data.fields, next); + }, + isAdmin: function (next) { + User.isAdministrator(uids, next); + }, + }, next); + }, + function (results, next) { + results.userData.forEach(function (user, index) { + if (user) { + user.status = User.getStatus(user); + user.administrator = results.isAdmin[index]; + user.banned = parseInt(user.banned, 10) === 1; + user.banned_until = parseInt(user['banned:expire'], 10) || 0; + user.banned_until_readable = user.banned_until ? new Date(user.banned_until).toString() : 'Not Banned'; + user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1; } - var isOnline = Date.now() - parseInt(lastonline, 10) < 300000; - callback(null, isOnline); }); - } + plugins.fireHook('filter:userlist.get', { users: results.userData, uid: uid }, next); + }, + function (data, next) { + next(null, data.users); + }, + ], callback); +}; - }; +User.getUsers = function (uids, uid, callback) { + var fields = ['uid', 'username', 'userslug', 'picture', 'status', 'flags', + 'banned', 'banned:expire', 'joindate', 'postcount', 'reputation', 'email:confirmed', 'lastonline']; - User.exists = function (uid, callback) { - db.isSortedSetMember('users:joindate', uid, callback); - }; + User.getUsersWithFields(uids, fields, uid, callback); +}; - User.existsBySlug = function (userslug, callback) { - User.getUidByUserslug(userslug, function (err, exists) { - callback(err, !! exists); - }); - }; +User.getStatus = function (userData) { + var isOnline = (Date.now() - parseInt(userData.lastonline, 10)) < 300000; + return isOnline ? (userData.status || 'online') : 'offline'; +}; - User.getUidByUsername = function (username, callback) { - if (!username) { - return callback(null, 0); - } - db.sortedSetScore('username:uid', username, callback); - }; +User.exists = function (uid, callback) { + db.isSortedSetMember('users:joindate', uid, callback); +}; - User.getUidsByUsernames = function (usernames, callback) { - db.sortedSetScores('username:uid', usernames, callback); - }; +User.existsBySlug = function (userslug, callback) { + User.getUidByUserslug(userslug, function (err, exists) { + callback(err, !!exists); + }); +}; - User.getUidByUserslug = function (userslug, callback) { - if (!userslug) { - return callback(null, 0); - } - db.sortedSetScore('userslug:uid', userslug, callback); - }; +User.getUidByUsername = function (username, callback) { + if (!username) { + return callback(null, 0); + } + db.sortedSetScore('username:uid', username, callback); +}; - User.getUsernamesByUids = function (uids, callback) { - User.getUsersFields(uids, ['username'], function (err, users) { - if (err) { - return callback(err); - } +User.getUidsByUsernames = function (usernames, callback) { + db.sortedSetScores('username:uid', usernames, callback); +}; +User.getUidByUserslug = function (userslug, callback) { + if (!userslug) { + return callback(null, 0); + } + db.sortedSetScore('userslug:uid', userslug, callback); +}; + +User.getUsernamesByUids = function (uids, callback) { + async.waterfall([ + function (next) { + User.getUsersFields(uids, ['username'], next); + }, + function (users, next) { users = users.map(function (user) { return user.username; }); - callback(null, users); - }); - }; + next(null, users); + }, + ], callback); +}; - User.getUsernameByUserslug = function (slug, callback) { - async.waterfall([ - function (next) { - User.getUidByUserslug(slug, next); - }, - function (uid, next) { - User.getUserField(uid, 'username', next); +User.getUsernameByUserslug = function (slug, callback) { + async.waterfall([ + function (next) { + User.getUidByUserslug(slug, next); + }, + function (uid, next) { + User.getUserField(uid, 'username', next); + }, + ], callback); +}; + +User.getUidByEmail = function (email, callback) { + db.sortedSetScore('email:uid', email.toLowerCase(), callback); +}; + +User.getUidsByEmails = function (emails, callback) { + emails = emails.map(function (email) { + return email && email.toLowerCase(); + }); + db.sortedSetScores('email:uid', emails, callback); +}; + +User.getUsernameByEmail = function (email, callback) { + async.waterfall([ + function (next) { + db.sortedSetScore('email:uid', email.toLowerCase(), next); + }, + function (uid, next) { + User.getUserField(uid, 'username', next); + }, + ], callback); +}; + +User.isModerator = function (uid, cid, callback) { + privileges.users.isModerator(uid, cid, callback); +}; + +User.isModeratorOfAnyCategory = function (uid, callback) { + User.getModeratedCids(uid, function (err, cids) { + callback(err, Array.isArray(cids) ? !!cids.length : false); + }); +}; + +User.isAdministrator = function (uid, callback) { + privileges.users.isAdministrator(uid, callback); +}; + +User.isGlobalModerator = function (uid, callback) { + privileges.users.isGlobalModerator(uid, callback); +}; + +User.isAdminOrGlobalMod = function (uid, callback) { + async.parallel({ + isAdmin: async.apply(User.isAdministrator, uid), + isGlobalMod: async.apply(User.isGlobalModerator, uid), + }, function (err, results) { + callback(err, results ? (results.isAdmin || results.isGlobalMod) : false); + }); +}; + +User.isAdminOrSelf = function (callerUid, uid, callback) { + isSelfOrMethod(callerUid, uid, User.isAdministrator, callback); +}; + +User.isAdminOrGlobalModOrSelf = function (callerUid, uid, callback) { + isSelfOrMethod(callerUid, uid, User.isAdminOrGlobalMod, callback); +}; + +function isSelfOrMethod(callerUid, uid, method, callback) { + if (parseInt(callerUid, 10) === parseInt(uid, 10)) { + return callback(); + } + async.waterfall([ + function (next) { + method(callerUid, next); + }, + function (isPass, next) { + if (!isPass) { + return next(new Error('[[error:no-privileges]]')); } - ], callback); - }; + next(); + }, + ], callback); +} - User.getUidByEmail = function (email, callback) { - db.sortedSetScore('email:uid', email.toLowerCase(), callback); - }; +User.getAdminsandGlobalMods = function (callback) { + async.waterfall([ + function (next) { + async.parallel([ + async.apply(groups.getMembers, 'administrators', 0, -1), + async.apply(groups.getMembers, 'Global Moderators', 0, -1), + ], next); + }, + function (results, next) { + User.getUsersData(_.union(results), next); + }, + ], callback); +}; - User.getUidsByEmails = function (emails, callback) { - emails = emails.map(function (email) { - return email && email.toLowerCase(); - }); - db.sortedSetScores('email:uid', emails, callback); - }; +User.getAdminsandGlobalModsandModerators = function (callback) { + async.waterfall([ + function (next) { + async.parallel([ + async.apply(groups.getMembers, 'administrators', 0, -1), + async.apply(groups.getMembers, 'Global Moderators', 0, -1), + async.apply(User.getModeratorUids), + ], next); + }, + function (results, next) { + User.getUsersData(_.union.apply(_, results), next); + }, + ], callback); +}; - User.getUsernameByEmail = function (email, callback) { - db.sortedSetScore('email:uid', email.toLowerCase(), function (err, uid) { - if (err) { - return callback(err); - } - User.getUserField(uid, 'username', callback); - }); - }; - - User.isModerator = function (uid, cid, callback) { - privileges.users.isModerator(uid, cid, callback); - }; - - User.isModeratorOfAnyCategory = function (uid, callback) { - User.getModeratedCids(uid, function (err, cids) { - callback(err, Array.isArray(cids) ? !!cids.length : false); - }); - }; - - User.isAdministrator = function (uid, callback) { - privileges.users.isAdministrator(uid, callback); - }; - - User.isGlobalModerator = function (uid, callback) { - privileges.users.isGlobalModerator(uid, callback); - }; - - User.isAdminOrGlobalMod = function (uid, callback) { - async.parallel({ - isAdmin: async.apply(User.isAdministrator, uid), - isGlobalMod: async.apply(User.isGlobalModerator, uid) - }, function (err, results) { - callback(err, results ? (results.isAdmin || results.isGlobalMod) : false); - }); - }; - - User.isAdminOrSelf = function (callerUid, uid, callback) { - if (parseInt(callerUid, 10) === parseInt(uid, 10)) { - return callback(); - } - User.isAdministrator(callerUid, function (err, isAdmin) { - if (err || !isAdmin) { - return callback(err || new Error('[[error:no-privileges]]')); - } - callback(); - }); - }; - - User.isAdminOrGlobalModOrSelf = function (callerUid, uid, callback) { - if (parseInt(callerUid, 10) === parseInt(uid, 10)) { - return callback(); - } - User.isAdminOrGlobalMod(callerUid, function (err, isAdminOrGlobalMod) { - if (err || !isAdminOrGlobalMod) { - return callback(err || new Error('[[error:no-privileges]]')); - } - callback(); - }); - }; - - User.getAdminsandGlobalMods = function (callback) { - async.parallel({ - admins: async.apply(groups.getMembers, 'administrators', 0, -1), - mods: async.apply(groups.getMembers, 'Global Moderators', 0, -1) - }, function (err, results) { - if (err) { - return callback(err); - } - var uids = results.admins.concat(results.mods).filter(function (uid, index, array) { - return uid && array.indexOf(uid) === index; +User.getModeratorUids = function (callback) { + async.waterfall([ + async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), + function (cids, next) { + var groupNames = cids.map(function (cid) { + return 'cid:' + cid + ':privileges:mods'; }); - User.getUsersData(uids, callback); - }); - }; - User.getAdminsandGlobalModsandModerators = function (callback) { - async.parallel([ - async.apply(groups.getMembers, 'administrators', 0, -1), - async.apply(groups.getMembers, 'Global Moderators', 0, -1), - async.apply(User.getModeratorUids) - ], function (err, results) { - if (err) { - return callback(err); - } + groups.getMembersOfGroups(groupNames, next); + }, + function (memberSets, next) { + next(null, _.union.apply(_, memberSets)); + }, + ], callback); +}; - User.getUsersData(_.union.apply(_, results), callback); - }); - }; +User.getModeratedCids = function (uid, callback) { + var cids; + async.waterfall([ + function (next) { + db.getSortedSetRange('categories:cid', 0, -1, next); + }, + function (_cids, next) { + cids = _cids; + User.isModerator(uid, cids, next); + }, + function (isMods, next) { + cids = cids.filter(function (cid, index) { + return cid && isMods[index]; + }); + next(null, cids); + }, + ], callback); +}; - User.getModeratorUids = function (callback) { - async.waterfall([ - async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), - function (cids, next) { - var groupNames = cids.map(function (cid) { - return 'cid:' + cid + ':privileges:mods'; - }); - - groups.getMembersOfGroups(groupNames, function (err, memberSets) { - if (err) { - return next(err); - } - - next(null, _.union.apply(_, memberSets)); - }); - } - ], callback); - }; - - User.getModeratedCids = function (uid, callback) { - var cids; - async.waterfall([ - function (next) { - db.getSortedSetRange('categories:cid', 0, -1, next); - }, - function (_cids, next) { - cids = _cids; - User.isModerator(uid, cids, next); - }, - function (isMods, next) { - cids = cids.filter(function (cid, index) { - return cid && isMods[index]; - }); - next(null, cids); - } - ], callback); - }; - - User.addInterstitials = function (callback) { - plugins.registerHook('core', { - hook: 'filter:register.interstitial', - method: function (data, callback) { - if (meta.config.termsOfUse && !data.userData.acceptTos) { - data.interstitials.push({ - template: 'partials/acceptTos', - data: { - termsOfUse: meta.config.termsOfUse - }, - callback: function (userData, formData, next) { - if (formData['agree-terms'] === 'on') { - userData.acceptTos = true; - } - - next(userData.acceptTos ? null : new Error('[[register:terms_of_use_error]]')); +User.addInterstitials = function (callback) { + plugins.registerHook('core', { + hook: 'filter:register.interstitial', + method: function (data, callback) { + if (meta.config.termsOfUse && !data.userData.acceptTos) { + data.interstitials.push({ + template: 'partials/acceptTos', + data: { + termsOfUse: meta.config.termsOfUse, + }, + callback: function (userData, formData, next) { + if (formData['agree-terms'] === 'on') { + userData.acceptTos = true; } - }); - } - callback(null, data); + next(userData.acceptTos ? null : new Error('[[register:terms_of_use_error]]')); + }, + }); } - }); - callback(); - }; + callback(null, data); + }, + }); + callback(); +}; -}(exports)); diff --git a/src/user/admin.js b/src/user/admin.js index 8b5a6ebef4..1d6cd8c7ad 100644 --- a/src/user/admin.js +++ b/src/user/admin.js @@ -8,7 +8,6 @@ var plugins = require('../plugins'); var winston = require('winston'); module.exports = function (User) { - User.logIP = function (uid, ip) { var now = Date.now(); db.sortedSetAdd('uid:' + uid + ':ip', now, ip || 'Unknown'); @@ -18,13 +17,7 @@ module.exports = function (User) { }; User.getIPs = function (uid, stop, callback) { - db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, function (err, ips) { - if (err) { - return callback(err); - } - - callback(null, ips); - }); + db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, callback); }; User.getUsersCSV = function (callback) { @@ -39,7 +32,7 @@ module.exports = function (User) { uids = users.map(function (user) { return user.score; }); - plugins.fireHook('filter:user.csvFields', {fields: ['uid', 'email', 'username']}, next); + plugins.fireHook('filter:user.csvFields', { fields: ['uid', 'email', 'username'] }, next); }, function (data, next) { User.getUsersFields(uids, data.fields, next); @@ -52,7 +45,7 @@ module.exports = function (User) { }); next(null, csvContent); - } + }, ], callback); }; diff --git a/src/user/approval.js b/src/user/approval.js index 2f9d9f847a..cbb1ba08b4 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -14,7 +14,6 @@ var utils = require('../../public/src/utils'); var plugins = require('../plugins'); module.exports = function (User) { - User.addToApprovalQueue = function (userData, callback) { userData.userslug = utils.slugify(userData.username); async.waterfall([ @@ -29,9 +28,9 @@ module.exports = function (User) { username: userData.username, email: userData.email, ip: userData.ip, - hashedPassword: hashedPassword + hashedPassword: hashedPassword, }; - plugins.fireHook('filter:user.addToApprovalQueue', {data: data, userData: userData}, next); + plugins.fireHook('filter:user.addToApprovalQueue', { data: data, userData: userData }, next); }, function (results, next) { db.setObject('registration:queue:name:' + userData.username, results.data, next); @@ -41,7 +40,7 @@ module.exports = function (User) { }, function (next) { sendNotificationToAdmins(userData.username, next); - } + }, ], callback); }; @@ -52,12 +51,12 @@ module.exports = function (User) { bodyShort: '[[notifications:new_register, ' + username + ']]', nid: 'new_register:' + username, path: '/admin/manage/registration', - mergeId: 'new_register' + mergeId: 'new_register', }, next); }, function (notification, next) { notifications.pushGroup(notification, 'administrators', next); - } + }, ], callback); } @@ -93,7 +92,7 @@ module.exports = function (User) { username: username, subject: subject, template: 'registration_accepted', - uid: uid + uid: uid, }; emailer.send('registration_accepted', uid, data, next); @@ -101,7 +100,7 @@ module.exports = function (User) { }, function (next) { next(null, uid); - } + }, ], callback); }; @@ -115,7 +114,7 @@ module.exports = function (User) { async.each(uids, function (uid, next) { notifications.markRead(nid, uid, next); }, next); - } + }, ], callback); } @@ -126,14 +125,14 @@ module.exports = function (User) { }, function (next) { markNotificationRead(username, next); - } + }, ], callback); }; function removeFromQueue(username, callback) { async.parallel([ async.apply(db.sortedSetRemove, 'registration:queue', username), - async.apply(db.delete, 'registration:queue:name:' + username) + async.apply(db.delete, 'registration:queue:name:' + username), ], function (err) { callback(err); }); @@ -191,7 +190,7 @@ module.exports = function (User) { '&email=' + encodeURIComponent(user.email) + '&username=' + encodeURIComponent(user.username) + '&f=json', - json: true + json: true, }, function (err, response, body) { if (err) { return next(); @@ -205,20 +204,18 @@ module.exports = function (User) { next(); }); - } + }, ], function (err) { next(err, user); }); }, next); }, function (users, next) { - plugins.fireHook('filter:user.getRegistrationQueue', {users: users}, next); + plugins.fireHook('filter:user.getRegistrationQueue', { users: users }, next); }, function (results, next) { next(null, results.users); - } + }, ], callback); }; - - }; diff --git a/src/user/auth.js b/src/user/auth.js index 219c468304..29a79f39c4 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -37,10 +37,10 @@ module.exports = function (User) { events.log({ type: 'account-locked', uid: uid, - ip: ip + ip: ip, }); next(new Error('[[error:account-locked]]')); - } + }, ], callback); }; @@ -51,7 +51,7 @@ module.exports = function (User) { User.auth.resetLockout = function (uid, callback) { async.parallel([ async.apply(db.delete, 'loginAttempts:' + uid), - async.apply(db.delete, 'lockout:' + uid) + async.apply(db.delete, 'lockout:' + uid), ], callback); }; @@ -78,8 +78,8 @@ module.exports = function (User) { }); // Revoke any sessions that have expired, return filtered list - var expiredSids = [], - expired; + var expiredSids = []; + var expired; sessions = sessions.filter(function (sessionObj, idx) { expired = !sessionObj || !sessionObj.hasOwnProperty('passport') || @@ -98,7 +98,7 @@ module.exports = function (User) { }, function (err) { next(err, sessions); }); - } + }, ], function (err, sessions) { callback(err, sessions ? sessions.map(function (sessObj) { sessObj.meta.datetimeISO = new Date(sessObj.meta.datetime).toISOString(); @@ -128,7 +128,7 @@ module.exports = function (User) { } }, async.apply(db.sortedSetRemove, 'uid:' + uid + ':sessions', sessionId), - async.apply(db.sessionStore.destroy.bind(db.sessionStore), sessionId) + async.apply(db.sessionStore.destroy.bind(db.sessionStore), sessionId), ], callback); }); }; @@ -140,14 +140,13 @@ module.exports = function (User) { async.each(sids, function (sid, next) { User.auth.revokeSession(sid, uid, next); }, next); - } + }, ], callback); }; User.auth.deleteAllSessions = function (callback) { var _ = require('underscore'); batch.processSortedSet('users:joindate', function (uids, next) { - var sessionKeys = uids.map(function (uid) { return 'uid:' + uid + ':sessions'; }); @@ -169,10 +168,10 @@ module.exports = function (User) { async.each(sids, function (sid, next) { db.sessionStore.destroy(sid, next); }, next); - } + }, ], next); - } + }, ], next); - }, {batch: 1000}, callback); + }, { batch: 1000 }, callback); }; -}; \ No newline at end of file +}; diff --git a/src/user/bans.js b/src/user/bans.js index 8667641c46..dc70d012dd 100644 --- a/src/user/bans.js +++ b/src/user/bans.js @@ -1,8 +1,8 @@ 'use strict'; var async = require('async'); + var db = require('../database'); -var plugins = require('../plugins'); module.exports = function (User) { User.ban = function (uid, until, reason, callback) { @@ -27,7 +27,7 @@ module.exports = function (User) { var tasks = [ async.apply(User.setUserField, uid, 'banned', 1), async.apply(db.sortedSetAdd, 'users:banned', now, uid), - async.apply(db.sortedSetAdd, 'uid:' + uid + ':bans', now, until) + async.apply(db.sortedSetAdd, 'uid:' + uid + ':bans', now, until), ]; if (until > 0 && now < until) { @@ -49,11 +49,11 @@ module.exports = function (User) { User.unban = function (uid, callback) { async.waterfall([ function (next) { - User.setUserFields(uid, {banned: 0, 'banned:expire': 0}, next); + User.setUserFields(uid, { banned: 0, 'banned:expire': 0 }, next); }, function (next) { db.sortedSetsRemove(['users:banned', 'users:banned:expire'], uid, next); - } + }, ], callback); }; @@ -75,11 +75,11 @@ module.exports = function (User) { async.parallel([ async.apply(db.sortedSetRemove.bind(db), 'users:banned:expire', uid), async.apply(db.sortedSetRemove.bind(db), 'users:banned', uid), - async.apply(User.setUserFields, uid, {banned:0, 'banned:expire': 0}) + async.apply(User.setUserFields, uid, { banned: 0, 'banned:expire': 0 }), ], function (err) { next(err, false); }); - } + }, ], callback); }; diff --git a/src/user/categories.js b/src/user/categories.js index fee8fc8bb0..8a4b26199f 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -6,7 +6,6 @@ var db = require('../database'); var categories = require('../categories'); module.exports = function (User) { - User.getIgnoredCategories = function (uid, callback) { db.getSortedSetRange('uid:' + uid + ':ignored:cids', 0, -1, callback); }; @@ -18,7 +17,7 @@ module.exports = function (User) { }, all: function (next) { db.getSortedSetRange('categories:cid', 0, -1, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -48,7 +47,7 @@ module.exports = function (User) { }, function (next) { db.sortedSetAdd('cid:' + cid + ':ignorers', Date.now(), uid, next); - } + }, ], callback); }; @@ -69,7 +68,7 @@ module.exports = function (User) { }, function (next) { db.sortedSetRemove('cid:' + cid + ':ignorers', uid, next); - } + }, ], callback); }; -}; \ No newline at end of file +}; diff --git a/src/user/create.js b/src/user/create.js index 67d6baf3cd..2620cb67d3 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -9,7 +9,6 @@ var groups = require('../groups'); var meta = require('../meta'); module.exports = function (User) { - User.create = function (data, callback) { data.username = data.username.trim(); data.userslug = utils.slugify(data.username); @@ -18,31 +17,31 @@ module.exports = function (User) { } User.isDataValid(data, function (err) { - if (err) { + if (err) { return callback(err); } var timestamp = data.timestamp || Date.now(); var userData = { - 'username': data.username, - 'userslug': data.userslug, - 'email': data.email || '', - 'joindate': timestamp, - 'lastonline': timestamp, - 'picture': '', - 'fullname': data.fullname || '', - 'location': '', - 'birthday': '', - 'website': '', - 'signature': '', - 'uploadedpicture': '', - 'profileviews': 0, - 'reputation': 0, - 'postcount': 0, - 'topiccount': 0, - 'lastposttime': 0, - 'banned': 0, - 'status': 'online' + username: data.username, + userslug: data.userslug, + email: data.email || '', + joindate: timestamp, + lastonline: timestamp, + picture: '', + fullname: data.fullname || '', + location: '', + birthday: '', + website: '', + signature: '', + uploadedpicture: '', + profileviews: 0, + reputation: 0, + postcount: 0, + topiccount: 0, + lastposttime: 0, + banned: 0, + status: 'online', }; async.parallel({ @@ -50,8 +49,8 @@ module.exports = function (User) { renameUsername(userData, next); }, userData: function (next) { - plugins.fireHook('filter:user.create', {user: userData, data: data}, next); - } + plugins.fireHook('filter:user.create', { user: userData, data: data }, next); + }, }, function (err, results) { if (err) { return callback(err); @@ -106,7 +105,7 @@ module.exports = function (User) { if (userData.email) { async.parallel([ async.apply(db.sortedSetAdd, 'email:uid', userData.uid, userData.email.toLowerCase()), - async.apply(db.sortedSetAdd, 'email:sorted', 0, userData.email.toLowerCase() + ':' + userData.uid) + async.apply(db.sortedSetAdd, 'email:sorted', 0, userData.email.toLowerCase() + ':' + userData.uid), ], next); if (parseInt(userData.uid, 10) !== 1 && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { @@ -128,13 +127,13 @@ module.exports = function (User) { async.parallel([ async.apply(User.setUserField, userData.uid, 'password', hash), - async.apply(User.reset.updateExpiry, userData.uid) + async.apply(User.reset.updateExpiry, userData.uid), ], next); }); }, function (next) { User.updateDigestSetting(userData.uid, meta.config.dailyDigestFreq, next); - } + }, ], next); }, function (results, next) { @@ -143,7 +142,7 @@ module.exports = function (User) { } plugins.fireHook('action:user.create', userData); next(null, userData.uid); - } + }, ], callback); }); }); @@ -179,7 +178,7 @@ module.exports = function (User) { } else { next(); } - } + }, }, function (err) { callback(err); }); @@ -225,5 +224,4 @@ module.exports = function (User) { }); }); } - }; diff --git a/src/user/data.js b/src/user/data.js index cbaf066ded..120da7e3a2 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -1,5 +1,6 @@ 'use strict'; +var async = require('async'); var validator = require('validator'); var nconf = require('nconf'); var winston = require('winston'); @@ -9,7 +10,6 @@ var plugins = require('../plugins'); var utils = require('../../public/src/utils'); module.exports = function (User) { - var iconBackgrounds = ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#009688', '#1b5e20', '#33691e', '#827717', '#e65100', '#ff5722', '#795548', '#607d8b']; @@ -55,13 +55,14 @@ module.exports = function (User) { addField('lastonline'); } - db.getObjectsFields(keys, fields, function (err, users) { - if (err) { - return callback(err); - } - - modifyUserData(users, fieldsToRemove, callback); - }); + async.waterfall([ + function (next) { + db.getObjectsFields(keys, fields, next); + }, + function (users, next) { + modifyUserData(users, fieldsToRemove, next); + }, + ], callback); }; User.getMultipleUserFields = function (uids, fields, callback) { @@ -84,13 +85,14 @@ module.exports = function (User) { return 'user:' + uid; }); - db.getObjects(keys, function (err, users) { - if (err) { - return callback(err); - } - - modifyUserData(users, [], callback); - }); + async.waterfall([ + function (next) { + db.getObjects(keys, next); + }, + function (users, next) { + modifyUserData(users, [], next); + }, + ], callback); }; function modifyUserData(users, fieldsToRemove, callback) { @@ -117,7 +119,8 @@ module.exports = function (User) { } if (user.picture && user.picture === user.uploadedpicture) { - user.picture = user.uploadedpicture = user.picture.startsWith('http') ? user.picture : nconf.get('relative_path') + user.picture; + user.uploadedpicture = user.picture.startsWith('http') ? user.picture : nconf.get('relative_path') + user.picture; + user.picture = user.uploadedpicture; } else if (user.uploadedpicture) { user.uploadedpicture = user.uploadedpicture.startsWith('http') ? user.uploadedpicture : nconf.get('relative_path') + user.uploadedpicture; } @@ -126,7 +129,7 @@ module.exports = function (User) { user.status = User.getStatus(user); } - for(var i = 0; i < fieldsToRemove.length; ++i) { + for (var i = 0; i < fieldsToRemove.length; i += 1) { user[fieldsToRemove[i]] = undefined; } @@ -152,52 +155,53 @@ module.exports = function (User) { User.setUserField = function (uid, field, value, callback) { callback = callback || function () {}; - db.setObjectField('user:' + uid, field, value, function (err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', {uid: uid, field: field, value: value, type: 'set'}); - callback(); - }); + async.waterfall([ + function (next) { + db.setObjectField('user:' + uid, field, value, next); + }, + function (next) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: 'set' }); + next(); + }, + ], callback); }; User.setUserFields = function (uid, data, callback) { callback = callback || function () {}; - db.setObject('user:' + uid, data, function (err) { - if (err) { - return callback(err); - } - for (var field in data) { - if (data.hasOwnProperty(field)) { - plugins.fireHook('action:user.set', {uid: uid, field: field, value: data[field], type: 'set'}); + async.waterfall([ + function (next) { + db.setObject('user:' + uid, data, next); + }, + function (next) { + for (var field in data) { + if (data.hasOwnProperty(field)) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: data[field], type: 'set' }); + } } - } - callback(); - }); + next(); + }, + ], callback); }; User.incrementUserFieldBy = function (uid, field, value, callback) { - callback = callback || function () {}; - db.incrObjectFieldBy('user:' + uid, field, value, function (err, value) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', {uid: uid, field: field, value: value, type: 'increment'}); - - callback(null, value); - }); + incrDecrUserFieldBy(uid, field, value, 'increment', callback); }; User.decrementUserFieldBy = function (uid, field, value, callback) { - callback = callback || function () {}; - db.incrObjectFieldBy('user:' + uid, field, -value, function (err, value) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.set', {uid: uid, field: field, value: value, type: 'decrement'}); - - callback(null, value); - }); + incrDecrUserFieldBy(uid, field, -value, 'decrement', callback); }; + function incrDecrUserFieldBy(uid, field, value, type, callback) { + callback = callback || function () {}; + async.waterfall([ + function (next) { + db.incrObjectFieldBy('user:' + uid, field, value, next); + }, + function (value, next) { + plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: type }); + + next(null, value); + }, + ], callback); + } }; diff --git a/src/user/delete.js b/src/user/delete.js index e648c5dfb0..7392192c8b 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -10,7 +10,6 @@ var plugins = require('../plugins'); var batch = require('../batch'); module.exports = function (User) { - User.delete = function (callerUid, uid, callback) { if (!parseInt(uid, 10)) { return callback(new Error('[[error:invalid-uid]]')); @@ -25,7 +24,7 @@ module.exports = function (User) { }, function (next) { User.deleteAccount(uid, next); - } + }, ], callback); }; @@ -34,7 +33,7 @@ module.exports = function (User) { async.eachSeries(ids, function (pid, next) { posts.purge(pid, callerUid, next); }, next); - }, {alwaysStartAt: 0}, callback); + }, { alwaysStartAt: 0 }, callback); } function deleteTopics(callerUid, uid, callback) { @@ -42,7 +41,7 @@ module.exports = function (User) { async.eachSeries(ids, function (tid, next) { topics.purge(tid, callerUid, next); }, next); - }, {alwaysStartAt: 0}, callback); + }, { alwaysStartAt: 0 }, callback); } User.deleteAccount = function (uid, callback) { @@ -57,9 +56,9 @@ module.exports = function (User) { } User.getUserFields(uid, ['username', 'userslug', 'fullname', 'email'], next); }, - function (_userData, next) { + function (_userData, next) { userData = _userData; - plugins.fireHook('static:user.delete', {uid: uid}, next); + plugins.fireHook('static:user.delete', { uid: uid }, next); }, function (next) { deleteVotes(uid, next); @@ -88,7 +87,7 @@ module.exports = function (User) { if (userData.email) { async.parallel([ async.apply(db.sortedSetRemove, 'email:uid', userData.email.toLowerCase()), - async.apply(db.sortedSetRemove, 'email:sorted', userData.email.toLowerCase() + ':' + uid) + async.apply(db.sortedSetRemove, 'email:sorted', userData.email.toLowerCase() + ':' + uid), ], next); } else { next(); @@ -104,7 +103,7 @@ module.exports = function (User) { 'users:notvalidated', 'digest:day:uids', 'digest:week:uids', - 'digest:month:uids' + 'digest:month:uids', ], uid, next); }, function (next) { @@ -123,7 +122,7 @@ module.exports = function (User) { 'uid:' + uid + ':chat:rooms', 'uid:' + uid + ':chat:rooms:unread', 'uid:' + uid + ':upvote', 'uid:' + uid + ':downvote', 'uid:' + uid + ':ignored:cids', 'uid:' + uid + ':flag:pids', - 'uid:' + uid + ':sessions', 'uid:' + uid + ':sessionUUID:sessionId' + 'uid:' + uid + ':sessions', 'uid:' + uid + ':sessionUUID:sessionId', ]; db.deleteAll(keys, next); }, @@ -135,12 +134,12 @@ module.exports = function (User) { }, function (next) { groups.leaveAllGroups(uid, next); - } + }, ], next); }, function (results, next) { db.deleteAll(['followers:' + uid, 'following:' + uid, 'user:' + uid], next); - } + }, ], callback); }; @@ -149,7 +148,7 @@ module.exports = function (User) { function (next) { async.parallel({ upvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':upvote', 0, -1), - downvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':downvote', 0, -1) + downvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':downvote', 0, -1), }, next); }, function (pids, next) { @@ -160,7 +159,7 @@ module.exports = function (User) { async.eachSeries(pids, function (pid, next) { posts.unvote(pid, uid, next); }, next); - } + }, ], function (err) { callback(err); }); @@ -181,9 +180,9 @@ module.exports = function (User) { async.parallel([ async.apply(db.sortedSetsRemove, roomKeys, uid), - async.apply(db.deleteAll, userKeys) + async.apply(db.deleteAll, userKeys), ], next); - } + }, ], function (err) { callback(err); }); @@ -202,14 +201,14 @@ module.exports = function (User) { }, function (next) { db.delete('uid:' + uid + ':ip', next); - } + }, ], callback); } function deleteUserFromFollowers(uid, callback) { async.parallel({ followers: async.apply(db.getSortedSetRange, 'followers:' + uid, 0, -1), - following: async.apply(db.getSortedSetRange, 'following:' + uid, 0, -1) + following: async.apply(db.getSortedSetRange, 'following:' + uid, 0, -1), }, function (err, results) { function updateCount(uids, name, fieldName, next) { async.each(uids, function (uid, next) { @@ -238,7 +237,7 @@ module.exports = function (User) { async.parallel([ async.apply(db.sortedSetsRemove, followerSets.concat(followingSets), uid), async.apply(updateCount, results.following, 'followers:', 'followerCount'), - async.apply(updateCount, results.followers, 'following:', 'followingCount') + async.apply(updateCount, results.followers, 'following:', 'followingCount'), ], callback); }); } diff --git a/src/user/digest.js b/src/user/digest.js index 9c86aca26d..73cd773713 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -31,7 +31,7 @@ var utils = require('../../public/src/utils'); function (next) { async.parallel({ topics: async.apply(topics.getLatestTopics, 0, 0, 9, interval), - subscribers: async.apply(Digest.getSubscribers, interval) + subscribers: async.apply(Digest.getSubscribers, interval), }, next); }, function (data, next) { @@ -52,7 +52,7 @@ var utils = require('../../public/src/utils'); data.interval = interval; Digest.send(data, next); - } + }, ], function (err) { if (err) { winston.error('[user/jobs] Could not send digests (' + interval + '): ' + err.message); @@ -72,12 +72,12 @@ var utils = require('../../public/src/utils'); function (subscribers, next) { plugins.fireHook('filter:digest.subscribers', { interval: interval, - subscribers: subscribers + subscribers: subscribers, }, next); }, function (results, next) { next(null, results.subscribers); - } + }, ], callback); }; @@ -118,16 +118,15 @@ var utils = require('../../public/src/utils'); site_title: meta.config.title || meta.config.browserTitle || 'NodeBB', notifications: notifications, recent: data.topics.topics, - interval: data.interval + interval: data.interval, }); next(); - } + }, ], next); }, next); - } + }, ], function (err) { callback(err); }); }; - }(module.exports)); diff --git a/src/user/email.js b/src/user/email.js index 99d2d9693d..8b8919c73a 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -13,7 +13,6 @@ var meta = require('../meta'); var emailer = require('../emailer'); (function (UserEmail) { - UserEmail.exists = function (email, callback) { user.getUidByEmail(email.toLowerCase(), function (err, exists) { callback(err, !!exists); @@ -53,11 +52,11 @@ var emailer = require('../emailer'); confirm_code = _confirm_code; db.setObject('confirm:' + confirm_code, { email: email.toLowerCase(), - uid: uid + uid: uid, }, next); }, function (next) { - db.expireAt('confirm:' + confirm_code, Math.floor(Date.now() / 1000 + 60 * 60 * 24), next); + db.expireAt('confirm:' + confirm_code, Math.floor((Date.now() / 1000) + (60 * 60 * 24)), next); }, function (next) { user.getUserField(uid, 'username', next); @@ -73,27 +72,32 @@ var emailer = require('../emailer'); subject: subject, template: 'welcome', - uid: uid + uid: uid, }; if (plugins.hasListeners('action:user.verify')) { - plugins.fireHook('action:user.verify', {uid: uid, data: data}); + plugins.fireHook('action:user.verify', { uid: uid, data: data }); next(); } else { emailer.send('welcome', uid, data, next); } }); - } + }, + function (next) { + next(null, confirm_code); + }, ], callback); }; UserEmail.confirm = function (code, callback) { - db.getObject('confirm:' + code, function (err, confirmObj) { - if (err) { - return callback(new Error('[[error:parse-error]]')); - } - - if (confirmObj && confirmObj.uid && confirmObj.email) { + async.waterfall([ + function (next) { + db.getObject('confirm:' + code, next); + }, + function (confirmObj, next) { + if (!confirmObj || !confirmObj.uid || !confirmObj.email) { + return next(new Error('[[error:invalid-data]]')); + } async.series([ async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1), async.apply(db.delete, 'confirm:' + code), @@ -102,15 +106,12 @@ var emailer = require('../emailer'); db.sortedSetRemove('users:notvalidated', confirmObj.uid, next); }, function (next) { - plugins.fireHook('action:user.email.confirmed', {uid: confirmObj.uid, email: confirmObj.email}, next); - } - ], function (err) { - callback(err ? new Error('[[error:email-confirm-failed]]') : null); - }); - } else { - callback(new Error('[[error:invalid-data]]')); - } + plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next); + }, + ], next); + }, + ], function (err) { + callback(err); }); }; - }(exports)); diff --git a/src/user/follow.js b/src/user/follow.js index e6c9624018..fe3dc0931d 100644 --- a/src/user/follow.js +++ b/src/user/follow.js @@ -6,7 +6,6 @@ var plugins = require('../plugins'); var db = require('../database'); module.exports = function (User) { - User.follow = function (uid, followuid, callback) { toggleFollow('follow', uid, followuid, callback); }; @@ -44,7 +43,7 @@ module.exports = function (User) { async.apply(db.sortedSetAdd, 'following:' + uid, now, theiruid), async.apply(db.sortedSetAdd, 'followers:' + theiruid, now, uid), async.apply(User.incrementUserFieldBy, uid, 'followingCount', 1), - async.apply(User.incrementUserFieldBy, theiruid, 'followerCount', 1) + async.apply(User.incrementUserFieldBy, theiruid, 'followerCount', 1), ], next); } else { if (!isFollowing) { @@ -54,10 +53,10 @@ module.exports = function (User) { async.apply(db.sortedSetRemove, 'following:' + uid, theiruid), async.apply(db.sortedSetRemove, 'followers:' + theiruid, uid), async.apply(User.decrementUserFieldBy, uid, 'followingCount', 1), - async.apply(User.decrementUserFieldBy, theiruid, 'followerCount', 1) + async.apply(User.decrementUserFieldBy, theiruid, 'followerCount', 1), ], next); } - } + }, ], callback); } @@ -82,12 +81,12 @@ module.exports = function (User) { uids: uids, uid: uid, start: start, - stop: stop + stop: stop, }, next); }, function (data, next) { User.getUsers(data.uids, uid, next); - } + }, ], callback); } @@ -97,5 +96,4 @@ module.exports = function (User) { } db.isSortedSetMember('following:' + uid, theirid, callback); }; - }; diff --git a/src/user/info.js b/src/user/info.js index 296dd9a723..4af1b77f35 100644 --- a/src/user/info.js +++ b/src/user/info.js @@ -11,7 +11,9 @@ var topics = require('../topics'); module.exports = function (User) { User.getLatestBanInfo = function (uid, callback) { // Simply retrieves the last record of the user's ban, even if they've been unbanned since then. - var timestamp, expiry, reason; + var timestamp; + var expiry; + var reason; async.waterfall([ async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':bans', 0, 0), @@ -28,7 +30,7 @@ module.exports = function (User) { function (_reason, next) { reason = _reason && _reason.length ? _reason[0] : ''; next(); - } + }, ], function (err) { if (err) { return callback(err); @@ -39,7 +41,7 @@ module.exports = function (User) { timestamp: timestamp, expiry: parseInt(expiry, 10), expiry_readable: new Date(parseInt(expiry, 10)).toString().replace(/:/g, '%3A'), - reason: validator.escape(String(reason)) + reason: validator.escape(String(reason)), }); }); }; @@ -50,12 +52,12 @@ module.exports = function (User) { async.parallel({ flags: async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':flag:pids', 0, 19), bans: async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':bans', 0, 19), - reasons: async.apply(db.getSortedSetRevRangeWithScores, 'banned:' + uid + ':reasons', 0, 19) + reasons: async.apply(db.getSortedSetRevRangeWithScores, 'banned:' + uid + ':reasons', 0, 19), }, next); }, function (data, next) { getFlagMetadata(data, next); - } + }, ], function (err, data) { if (err) { return callback(err); @@ -117,9 +119,9 @@ module.exports = function (User) { function formatBanData(data) { var reasons = data.reasons.reduce(function (memo, cur) { - memo[cur.score] = cur.value; - return memo; - }, {}); + memo[cur.score] = cur.value; + return memo; + }, {}); data.bans = data.bans.map(function (banObj) { banObj.until = parseInt(banObj.value, 10); diff --git a/src/user/invite.js b/src/user/invite.js index 043bf62a7b..4e41b824a5 100644 --- a/src/user/invite.js +++ b/src/user/invite.js @@ -12,7 +12,6 @@ var utils = require('../../public/src/utils'); module.exports = function (User) { - User.getInvites = function (uid, callback) { db.getSetMembers('invitation:uid:' + uid, callback); }; @@ -37,11 +36,11 @@ module.exports = function (User) { invitations = invitations.map(function (invites, index) { return { uid: uids[index], - invitations: invites + invitations: invites, }; }); next(null, invitations); - } + }, ], callback); }; @@ -68,7 +67,7 @@ module.exports = function (User) { }, function (next) { db.setAdd('invitation:uids', uid, next); - } + }, ], function (err) { next(err); }); @@ -90,12 +89,12 @@ module.exports = function (User) { registerLink: registerLink, subject: subject, username: username, - template: 'invitation' + template: 'invitation', }; emailer.sendToEmail('invitation', email, meta.config.defaultLang, data, next); }); - } + }, ], callback); }; @@ -114,7 +113,7 @@ module.exports = function (User) { } next(); - } + }, ], callback); }; @@ -134,11 +133,11 @@ module.exports = function (User) { }, function (next) { db.delete('invitation:email:' + email, next); - } + }, ], function (err) { next(err); }); - } + }, ], callback); }; @@ -156,7 +155,7 @@ module.exports = function (User) { }, function (next) { db.delete('invitation:email:' + email, next); - } + }, ], callback); }; @@ -173,8 +172,7 @@ module.exports = function (User) { return db.setRemove('invitation:uids', uid, next); } setImmediate(next); - } + }, ], callback); } - }; diff --git a/src/user/jobs.js b/src/user/jobs.js index c01f2c613c..1eeeb5650e 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -22,12 +22,12 @@ module.exports = function (User) { } // Terminate any active cron jobs - for(var jobId in jobs) { + for (var jobId in jobs) { if (jobs.hasOwnProperty(jobId)) { winston.verbose('[user/jobs] Terminating job (' + jobId + ')'); jobs[jobId].stop(); delete jobs[jobId]; - ++terminated; + terminated += 1; } } winston.verbose('[user/jobs] ' + terminated + ' jobs terminated'); @@ -37,33 +37,31 @@ module.exports = function (User) { User.digest.execute('day'); }, null, true); winston.verbose('[user/jobs] Starting job (digest.daily)'); - ++started; + started += 1; jobs['digest.weekly'] = new cronJob('0 ' + digestHour + ' * * 0', function () { winston.verbose('[user/jobs] Digest job (weekly) started.'); User.digest.execute('week'); }, null, true); winston.verbose('[user/jobs] Starting job (digest.weekly)'); - ++started; + started += 1; jobs['digest.monthly'] = new cronJob('0 ' + digestHour + ' 1 * *', function () { winston.verbose('[user/jobs] Digest job (monthly) started.'); User.digest.execute('month'); }, null, true); winston.verbose('[user/jobs] Starting job (digest.monthly)'); - ++started; + started += 1; jobs['reset.clean'] = new cronJob('0 0 * * *', User.reset.clean, null, true); winston.verbose('[user/jobs] Starting job (reset.clean)'); - ++started; + started += 1; winston.verbose('[user/jobs] ' + started + ' jobs started'); if (typeof callback === 'function') { callback(); } - - return; }; }; diff --git a/src/user/notifications.js b/src/user/notifications.js index 7182c1a223..f830092b07 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -11,10 +11,9 @@ var notifications = require('../notifications'); var privileges = require('../privileges'); (function (UserNotifications) { - UserNotifications.get = function (uid, callback) { if (!parseInt(uid, 10)) { - return callback(null , {read: [], unread: []}); + return callback(null, { read: [], unread: [] }); } getNotifications(uid, 0, 9, function (err, notifications) { if (err) { @@ -54,7 +53,7 @@ var privileges = require('../privileges'); }, read: function (next) { getNotificationsFromSet('uid:' + uid + ':notifications:read', true, uid, start, stop, next); - } + }, }, callback); } @@ -64,7 +63,7 @@ var privileges = require('../privileges'); async.waterfall([ async.apply(db.getSortedSetRevRange, set, start, stop), function (nids, next) { - if(!Array.isArray(nids) || !nids.length) { + if (!Array.isArray(nids) || !nids.length) { return callback(null, []); } @@ -89,7 +88,7 @@ var privileges = require('../privileges'); } notifications.merge(notifs, next); - } + }, ], callback); } @@ -137,7 +136,7 @@ var privileges = require('../privileges'); }); db.getObjectsFields(keys, ['mergeId'], next); - } + }, ], function (err, mergeIds) { // A missing (null) mergeId means that notification is counted separately. mergeIds = mergeIds.map(function (set) { @@ -146,7 +145,7 @@ var privileges = require('../privileges'); callback(err, mergeIds.reduce(function (count, cur, idx, arr) { if (cur === null || idx === arr.indexOf(cur)) { - ++count; + count += 1; } return count; @@ -195,7 +194,7 @@ var privileges = require('../privileges'); }, function (next) { db.delete('uid:' + uid + ':notifications:read', next); - } + }, ], callback); }; @@ -229,9 +228,9 @@ var privileges = require('../privileges'); path: '/post/' + postData.pid, nid: 'tid:' + postData.tid + ':uid:' + uid, tid: postData.tid, - from: uid + from: uid, }, next); - } + }, ], function (err, notification) { if (err) { return winston.error(err); @@ -254,7 +253,7 @@ var privileges = require('../privileges'); notifications.create({ bodyShort: meta.config.welcomeNotification, path: path, - nid: 'welcome_' + uid + nid: 'welcome_' + uid, }, function (err, notification) { if (err || !notification) { return callback(err); @@ -269,7 +268,7 @@ var privileges = require('../privileges'); bodyShort: '[[user:username_taken_workaround, ' + username + ']]', image: 'brand:logo', nid: 'username_taken:' + uid, - datetime: Date.now() + datetime: Date.now(), }, function (err, notification) { if (!err && notification) { notifications.push(notification, uid); @@ -287,5 +286,4 @@ var privileges = require('../privileges'); websockets.in('uid_' + uid).emit('event:notifications.updateCount', count); }); }; - }(exports)); diff --git a/src/user/online.js b/src/user/online.js new file mode 100644 index 0000000000..6cb19cd22f --- /dev/null +++ b/src/user/online.js @@ -0,0 +1,70 @@ +'use strict'; + +var async = require('async'); + +var db = require('../database'); +var topics = require('../topics'); +var plugins = require('../plugins'); + +module.exports = function (User) { + User.updateLastOnlineTime = function (uid, callback) { + callback = callback || function () {}; + db.getObjectFields('user:' + uid, ['status', 'lastonline'], function (err, userData) { + var now = Date.now(); + if (err || userData.status === 'offline' || now - parseInt(userData.lastonline, 10) < 300000) { + return callback(err); + } + User.setUserField(uid, 'lastonline', now, callback); + }); + }; + + User.updateOnlineUsers = function (uid, callback) { + callback = callback || function () {}; + + var now = Date.now(); + async.waterfall([ + function (next) { + db.sortedSetScore('users:online', uid, next); + }, + function (userOnlineTime, next) { + if (now - parseInt(userOnlineTime, 10) < 300000) { + return callback(); + } + db.sortedSetAdd('users:online', now, uid, next); + }, + function (next) { + topics.pushUnreadCount(uid); + plugins.fireHook('action:user.online', { uid: uid, timestamp: now }); + next(); + }, + ], callback); + }; + + User.isOnline = function (uid, callback) { + var now = Date.now(); + async.waterfall([ + function (next) { + if (Array.isArray(uid)) { + db.sortedSetScores('users:online', uid, next); + } else { + db.sortedSetScore('users:online', uid, next); + } + }, + function (lastonline, next) { + function checkOnline(lastonline) { + return now - lastonline < 300000; + } + + var isOnline; + if (Array.isArray(uid)) { + isOnline = uid.map(function (uid, index) { + return checkOnline(lastonline[index]); + }); + } else { + isOnline = checkOnline(lastonline); + } + next(null, isOnline); + }, + ], callback); + }; +}; diff --git a/src/user/password.js b/src/user/password.js index 8e9b7780e3..6cf5d8e5d5 100644 --- a/src/user/password.js +++ b/src/user/password.js @@ -7,7 +7,6 @@ var db = require('../database'); var Password = require('../password'); module.exports = function (User) { - User.hashPassword = function (password, callback) { if (!password) { return callback(null, password); @@ -34,7 +33,7 @@ module.exports = function (User) { Password.compare(password, hashedPassword, next); }); - } + }, ], callback); }; @@ -43,5 +42,4 @@ module.exports = function (User) { callback(err, !!hashedPassword); }); }; - -}; \ No newline at end of file +}; diff --git a/src/user/picture.js b/src/user/picture.js index 09b7d636e8..2b4f45d344 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -2,7 +2,6 @@ var async = require('async'); var fs = require('fs'); -var nconf = require('nconf'); var winston = require('winston'); var request = require('request'); var mime = require('mime'); @@ -14,9 +13,8 @@ var meta = require('../meta'); var db = require('../database'); module.exports = function (User) { - User.uploadPicture = function (uid, picture, callback) { - User.uploadCroppedPicture({uid: uid, file: picture}, callback); + User.uploadCroppedPicture({ uid: uid, file: picture }, callback); }; User.uploadFromUrl = function (uid, url, callback) { @@ -46,18 +44,13 @@ module.exports = function (User) { uid: uid, image: { url: url, - name: '' - } + name: '', + }, }, next); }, function (image, next) { - User.setUserFields(uid, { - uploadedpicture: image.url, - picture: image.url - }, function (err) { - next(err, image); - }); - } + next(null, image); + }, ], callback); }; @@ -66,11 +59,10 @@ module.exports = function (User) { }; User.updateCoverPicture = function (data, callback) { - var url; var picture = { name: 'profileCover', - uid: data.uid + uid: data.uid, }; if (!data.imageData && data.position) { @@ -112,18 +104,17 @@ module.exports = function (User) { } else { setImmediate(next); } - } + }, ], function (err) { deleteFile(picture.path); callback(err, { - url: url + url: url, }); }); }; User.uploadCroppedPicture = function (data, callback) { - - if (parseInt(meta.config.allowProfileImageUploads) !== 1) { + if (parseInt(meta.config.allowProfileImageUploads, 10) !== 1) { return callback(new Error('[[error:profile-image-uploads-disabled]]')); } @@ -147,7 +138,7 @@ module.exports = function (User) { var picture = { name: 'profileAvatar', - uid: data.uid + uid: data.uid, }; async.waterfall([ @@ -168,7 +159,7 @@ module.exports = function (User) { path: picture.path, extension: extension, width: imageDimension, - height: imageDimension + height: imageDimension, }, next); }, function (next) { @@ -180,9 +171,9 @@ module.exports = function (User) { User.setUserFields(data.uid, { uploadedpicture: uploadedImage.url, - picture: uploadedImage.url + picture: uploadedImage.url, }, next); - } + }, ], function (err) { deleteFile(picture.path); callback(err, uploadedImage); @@ -208,7 +199,7 @@ module.exports = function (User) { if (plugins.hasListeners('filter:uploadImage')) { return plugins.fireHook('filter:uploadImage', { image: image, - uid: image.uid + uid: image.uid, }, callback); } @@ -231,11 +222,11 @@ module.exports = function (User) { }, function (upload, next) { next(null, { - url: nconf.get('relative_path') + upload.url, + url: upload.url, path: upload.path, - name: image.name + name: image.name, }); - } + }, ], callback); } diff --git a/src/user/posts.js b/src/user/posts.js index 37b5e92b16..3f2d608ee1 100644 --- a/src/user/posts.js +++ b/src/user/posts.js @@ -6,7 +6,6 @@ var meta = require('../meta'); var privileges = require('../privileges'); module.exports = function (User) { - User.isReadyToPost = function (uid, cid, callback) { if (parseInt(uid, 10) === 0) { return callback(); @@ -21,7 +20,7 @@ module.exports = function (User) { }, isAdminOrMod: function (next) { privileges.categories.isAdminOrMod(cid, uid, next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -75,7 +74,7 @@ module.exports = function (User) { }, function (next) { User.updateLastOnlineTime(postData.uid, next); - } + }, ], callback); }; @@ -101,5 +100,4 @@ module.exports = function (User) { callback(err, Array.isArray(pids) ? pids : []); }); }; - -}; \ No newline at end of file +}; diff --git a/src/user/profile.js b/src/user/profile.js index 37b280612f..b2b3b7eb5f 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -11,25 +11,30 @@ var groups = require('../groups'); var plugins = require('../plugins'); module.exports = function (User) { - User.updateProfile = function (uid, data, callback) { var fields = ['username', 'email', 'fullname', 'website', 'location', 'groupTitle', 'birthday', 'signature', 'aboutme']; + if (data.aboutme !== undefined && data.aboutme.length > meta.config.maximumAboutMeLength) { + return callback(new Error('[[error:about-me-too-long, ' + meta.config.maximumAboutMeLength + ']]')); + } + + if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) { + return callback(new Error('[[error:signature-too-long, ' + meta.config.maximumSignatureLength + ']]')); + } + async.waterfall([ function (next) { - plugins.fireHook('filter:user.updateProfile', {uid: uid, data: data, fields: fields}, next); + plugins.fireHook('filter:user.updateProfile', { uid: uid, data: data, fields: fields }, next); }, function (data, next) { fields = data.fields; data = data.data; async.series([ - async.apply(isAboutMeValid, data), - async.apply(isSignatureValid, data), async.apply(isEmailAvailable, data, uid), async.apply(isUsernameAvailable, data, uid), - async.apply(isGroupTitleValid, data) + async.apply(isGroupTitleValid, data), ], function (err) { next(err); }); @@ -56,28 +61,12 @@ module.exports = function (User) { }, next); }, function (next) { - plugins.fireHook('action:user.updateProfile', {data: data, uid: uid}); + plugins.fireHook('action:user.updateProfile', { data: data, uid: uid }); User.getUserFields(uid, ['email', 'username', 'userslug', 'picture', 'icon:text', 'icon:bgColor'], next); - } + }, ], callback); }; - function isAboutMeValid(data, callback) { - if (data.aboutme !== undefined && data.aboutme.length > meta.config.maximumAboutMeLength) { - callback(new Error('[[error:about-me-too-long, ' + meta.config.maximumAboutMeLength + ']]')); - } else { - callback(); - } - } - - function isSignatureValid(data, callback) { - if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) { - callback(new Error('[[error:signature-too-long, ' + meta.config.maximumSignatureLength + ']]')); - } else { - callback(); - } - } - function isEmailAvailable(data, uid, callback) { if (!data.email) { return callback(); @@ -99,7 +88,7 @@ module.exports = function (User) { }, function (available, next) { next(!available ? new Error('[[error:email-taken]]') : null); - } + }, ], callback); } @@ -134,7 +123,7 @@ module.exports = function (User) { }, function (exists, next) { next(exists ? new Error('[[error:username-taken]]') : null); - } + }, ], callback); } @@ -159,7 +148,7 @@ module.exports = function (User) { } async.series([ async.apply(db.sortedSetRemove, 'email:uid', oldEmail.toLowerCase()), - async.apply(db.sortedSetRemove, 'email:sorted', oldEmail.toLowerCase() + ':' + uid) + async.apply(db.sortedSetRemove, 'email:sorted', oldEmail.toLowerCase() + ':' + uid), ], function (err) { next(err); }); @@ -170,7 +159,7 @@ module.exports = function (User) { db.sortedSetAdd('email:uid', uid, newEmail.toLowerCase(), next); }, function (next) { - db.sortedSetAdd('email:sorted', 0, newEmail.toLowerCase() + ':' + uid, next); + db.sortedSetAdd('email:sorted', 0, newEmail.toLowerCase() + ':' + uid, next); }, function (next) { db.sortedSetAdd('user:' + uid + ':emails', Date.now(), newEmail + ':' + Date.now(), next); @@ -186,11 +175,11 @@ module.exports = function (User) { }, function (next) { db.sortedSetAdd('users:notvalidated', Date.now(), uid, next); - } + }, ], function (err) { next(err); }); - } + }, ], callback); } @@ -216,7 +205,7 @@ module.exports = function (User) { async.series([ async.apply(db.sortedSetRemove, 'username:sorted', userData.username.toLowerCase() + ':' + uid), async.apply(db.sortedSetAdd, 'username:sorted', 0, newUsername.toLowerCase() + ':' + uid), - async.apply(db.sortedSetAdd, 'user:' + uid + ':usernames', Date.now(), newUsername + ':' + Date.now()) + async.apply(db.sortedSetAdd, 'user:' + uid + ':usernames', Date.now(), newUsername + ':' + Date.now()), ], next); }, ], callback); @@ -241,7 +230,7 @@ module.exports = function (User) { } else { next(); } - } + }, ], callback); } @@ -252,7 +241,7 @@ module.exports = function (User) { }, function (fullname, next) { updateUidMapping('fullname', uid, newFullname, fullname, next); - } + }, ], callback); } @@ -282,11 +271,12 @@ module.exports = function (User) { function (hashedPassword, next) { async.parallel([ async.apply(User.setUserField, data.uid, 'password', hashedPassword), - async.apply(User.reset.updateExpiry, data.uid) + async.apply(User.reset.updateExpiry, data.uid), + async.apply(User.auth.revokeAllSessions, data.uid), ], function (err) { next(err); }); - } + }, ], callback); }; }; diff --git a/src/user/reset.js b/src/user/reset.js index 39bf1f0e07..ba0e18b513 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -1,16 +1,16 @@ 'use strict'; -var async = require('async'), - nconf = require('nconf'), - winston = require('winston'), +var async = require('async'); +var nconf = require('nconf'); +var winston = require('winston'); - user = require('../user'), - utils = require('../../public/src/utils'), - translator = require('../../public/src/modules/translator'), +var user = require('../user'); +var utils = require('../../public/src/utils'); +var translator = require('../../public/src/modules/translator'); - db = require('../database'), - meta = require('../meta'), - emailer = require('../emailer'); +var db = require('../database'); +var meta = require('../meta'); +var emailer = require('../emailer'); (function (UserReset) { var twoHours = 7200000; @@ -28,7 +28,7 @@ var async = require('async'), }, function (issueDate, next) { next(null, parseInt(issueDate, 10) > Date.now() - twoHours); - } + }, ], callback); }; @@ -36,7 +36,7 @@ var async = require('async'), var code = utils.generateUUID(); async.parallel([ async.apply(db.setObjectField, 'reset:uid', code, uid), - async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code) + async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), ], function (err) { callback(err, code); }); @@ -48,11 +48,11 @@ var async = require('async'), db.sortedSetScore('reset:issueDate:uid', uid, next); }, function (score, next) { - if (score > Date.now() - 1000 * 60) { + if (score > Date.now() - (1000 * 60)) { return next(new Error('[[error:cant-reset-password-more-than-once-a-minute]]')); } next(); - } + }, ], callback); } @@ -88,9 +88,9 @@ var async = require('async'), reset_link: reset_link, subject: subject, template: 'reset', - uid: uid + uid: uid, }, next); - } + }, ], callback); }; @@ -124,9 +124,9 @@ var async = require('async'), async.apply(db.sortedSetRemove, 'reset:issueDate', code), async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid), async.apply(user.reset.updateExpiry, uid), - async.apply(user.auth.resetLockout, uid) + async.apply(user.auth.resetLockout, uid), ], next); - } + }, ], callback); }; @@ -148,7 +148,7 @@ var async = require('async'), }, uids: function (next) { db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours, next); - } + }, }, next); }, function (results, next) { @@ -160,10 +160,9 @@ var async = require('async'), async.parallel([ async.apply(db.deleteObjectFields, 'reset:uid', results.tokens), async.apply(db.sortedSetRemove, 'reset:issueDate', results.tokens), - async.apply(db.sortedSetRemove, 'reset:issueDate:uid', results.uids) + async.apply(db.sortedSetRemove, 'reset:issueDate:uid', results.uids), ], next); - } + }, ], callback); }; - }(exports)); diff --git a/src/user/search.js b/src/user/search.js index 65d0e41a6a..4583e0e28f 100644 --- a/src/user/search.js +++ b/src/user/search.js @@ -7,7 +7,6 @@ var plugins = require('../plugins'); var db = require('../database'); module.exports = function (User) { - User.search = function (data, callback) { var query = data.query || ''; var searchBy = data.searchBy || 'username'; @@ -34,7 +33,7 @@ module.exports = function (User) { filterAndSortUids(uids, data, next); }, function (uids, next) { - plugins.fireHook('filter:users.search', {uids: uids, uid: uid}, next); + plugins.fireHook('filter:users.search', { uids: uids, uid: uid }, next); }, function (data, next) { var uids = data.uids; @@ -54,7 +53,7 @@ module.exports = function (User) { searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2); searchResult.users = userData; next(null, searchResult); - } + }, ], callback); }; @@ -135,9 +134,9 @@ module.exports = function (User) { }); } else { userData.sort(function (u1, u2) { - if(u1[sortBy] < u2[sortBy]) { + if (u1[sortBy] < u2[sortBy]) { return -1; - } else if(u1[sortBy] > u2[sortBy]) { + } else if (u1[sortBy] > u2[sortBy]) { return 1; } return 0; @@ -156,9 +155,9 @@ module.exports = function (User) { }, function (users, next) { var diff = process.hrtime(start); - var timing = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(1); - next(null, {timing: timing, users: users}); - } + var timing = ((diff[0] * 1e3) + (diff[1] / 1e6)).toFixed(1); + next(null, { timing: timing, users: users }); + }, ], callback); } }; diff --git a/src/user/settings.js b/src/user/settings.js index 3d93a9724a..bef20e0087 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -7,7 +7,6 @@ var db = require('../database'); var plugins = require('../plugins'); module.exports = function (User) { - User.getSettings = function (uid, callback) { if (!parseInt(uid, 10)) { return onSettingsLoaded(0, {}, callback); @@ -18,7 +17,7 @@ module.exports = function (User) { return callback(err); } - onSettingsLoaded(uid, settings ? settings : {}, callback); + onSettingsLoaded(uid, settings || {}, callback); }); }; @@ -36,7 +35,7 @@ module.exports = function (User) { return callback(err); } - for (var i = 0; i < settings.length; ++i) { + for (var i = 0; i < settings.length; i += 1) { settings[i] = settings[i] || {}; settings[i].uid = uids[i]; } @@ -48,7 +47,7 @@ module.exports = function (User) { }; function onSettingsLoaded(uid, settings, callback) { - plugins.fireHook('filter:user.getSettings', {uid: uid, settings: settings}, function (err, data) { + plugins.fireHook('filter:user.getSettings', { uid: uid, settings: settings }, function (err, data) { if (err) { return callback(err); } @@ -75,7 +74,7 @@ module.exports = function (User) { settings.restrictChat = parseInt(getSetting(settings, 'restrictChat', 0), 10) === 1; settings.topicSearchEnabled = parseInt(getSetting(settings, 'topicSearchEnabled', 0), 10) === 1; settings.delayImageLoading = parseInt(getSetting(settings, 'delayImageLoading', 1), 10) === 1; - settings.bootswatchSkin = settings.bootswatchSkin || 'default'; + settings.bootswatchSkin = settings.bootswatchSkin || meta.config.bootswatchSkin || 'default'; settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1; callback(null, settings); @@ -102,7 +101,7 @@ module.exports = function (User) { data.userLang = data.userLang || meta.config.defaultLang; - plugins.fireHook('action:user.saveSettings', {uid: uid, settings: data}); + plugins.fireHook('action:user.saveSettings', { uid: uid, settings: data }); var settings = { showemail: data.showemail, @@ -120,11 +119,11 @@ module.exports = function (User) { restrictChat: data.restrictChat, topicSearchEnabled: data.topicSearchEnabled, delayImageLoading: data.delayImageLoading, - homePageRoute : ((data.homePageRoute === 'custom' ? data.homePageCustom : data.homePageRoute) || '').replace(/^\//, ''), + homePageRoute: ((data.homePageRoute === 'custom' ? data.homePageCustom : data.homePageRoute) || '').replace(/^\//, ''), scrollToMyPost: data.scrollToMyPost, notificationSound: data.notificationSound, incomingChatSound: data.incomingChatSound, - outgoingChatSound: data.outgoingChatSound + outgoingChatSound: data.outgoingChatSound, }; if (data.bootswatchSkin) { @@ -140,7 +139,7 @@ module.exports = function (User) { }, function (next) { User.getSettings(uid, next); - } + }, ], callback); }; @@ -155,7 +154,7 @@ module.exports = function (User) { } else { next(); } - } + }, ], callback); }; diff --git a/src/user/topics.js b/src/user/topics.js index 53dade36e9..bd69e66e6f 100644 --- a/src/user/topics.js +++ b/src/user/topics.js @@ -4,7 +4,6 @@ var async = require('async'); var db = require('../database'); module.exports = function (User) { - User.getIgnoredTids = function (uid, start, stop, callback) { db.getSortedSetRevRange('uid:' + uid + ':ignored_tids', start, stop, callback); }; @@ -12,8 +11,7 @@ module.exports = function (User) { User.addTopicIdToUser = function (uid, tid, timestamp, callback) { async.parallel([ async.apply(db.sortedSetAdd, 'uid:' + uid + ':topics', timestamp, tid), - async.apply(User.incrementUserFieldBy, uid, 'topiccount', 1) + async.apply(User.incrementUserFieldBy, uid, 'topiccount', 1), ], callback); }; - -}; \ No newline at end of file +}; diff --git a/src/views/admin/general/sounds.tpl b/src/views/admin/general/sounds.tpl index c7b8df97a7..e5c7fc848d 100644 --- a/src/views/admin/general/sounds.tpl +++ b/src/views/admin/general/sounds.tpl @@ -7,7 +7,7 @@
    - @@ -33,7 +33,7 @@
    - @@ -54,7 +54,7 @@
    - diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 995dd13a8f..a6351009d8 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -105,7 +105,7 @@
    - [[posted-in, {posts.category.name}]], + [[admin/manage/flags:posted-in]] {posts.category.name} [[admin/manage/flags:read-more]] diff --git a/src/views/admin/partials/installed_plugin_item.tpl b/src/views/admin/partials/installed_plugin_item.tpl index b76ae9f964..2e95606ef8 100644 --- a/src/views/admin/partials/installed_plugin_item.tpl +++ b/src/views/admin/partials/installed_plugin_item.tpl @@ -36,13 +36,7 @@
  • - -<<<<<<< HEAD - - -======= ->>>>>>> `admin/extend` translations

    {installed.id}

    diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index 990509e41f..9a96706394 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -31,8 +31,8 @@
    - -
    +
    +
  • @@ -123,6 +123,11 @@ [[admin/settings/general:outgoing-links.warning-page]]
    + +
    +
    + +
    diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index 1c0b660361..fd696cb5ad 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -43,7 +43,7 @@

    [[admin/settings/group:default-cover-help]]

    -
    +
    diff --git a/src/views/admin/settings/uploads.tpl b/src/views/admin/settings/uploads.tpl index 6c9b59db80..feff2dbff3 100644 --- a/src/views/admin/settings/uploads.tpl +++ b/src/views/admin/settings/uploads.tpl @@ -50,7 +50,7 @@
    - +

    [[admin/settings/uploads:allowed-file-extensions-help]]

    @@ -131,7 +131,7 @@

    [[admin/settings/uploads:default-covers-help]]

    - +
    diff --git a/src/views/partials/fontawesome.tpl b/src/views/partials/fontawesome.tpl index f6a84268bc..377afe09ff 100644 --- a/src/views/partials/fontawesome.tpl +++ b/src/views/partials/fontawesome.tpl @@ -5,6 +5,10 @@
    + + + + @@ -53,11 +57,15 @@ + + + + @@ -207,19 +215,25 @@ + + + + + + @@ -287,6 +301,7 @@ + @@ -319,6 +334,7 @@ + @@ -335,6 +351,7 @@ + @@ -358,8 +375,12 @@ + + + + @@ -397,6 +418,7 @@ + @@ -429,8 +451,10 @@ + + @@ -495,6 +519,7 @@ + @@ -504,10 +529,12 @@ + + @@ -534,6 +561,7 @@ + @@ -558,6 +586,7 @@ + @@ -574,6 +603,7 @@ + @@ -619,6 +649,7 @@ + @@ -628,6 +659,7 @@ + @@ -637,6 +669,17 @@ + + + + + + + + + + + @@ -646,6 +689,8 @@ + + @@ -686,11 +731,16 @@ + + + + + @@ -715,10 +765,16 @@ + + + + + + diff --git a/src/webserver.js b/src/webserver.js index 9b3e816c5d..09da4a4d08 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -33,7 +33,7 @@ var helpers = require('../public/src/modules/helpers'); if (nconf.get('ssl')) { server = require('https').createServer({ key: fs.readFileSync(nconf.get('ssl').key), - cert: fs.readFileSync(nconf.get('ssl').cert) + cert: fs.readFileSync(nconf.get('ssl').cert), }, app); } else { server = require('http').createServer(app); @@ -61,25 +61,23 @@ module.exports.listen = function (callback) { logger.init(app); - initializeNodeBB(function (err) { - if (err) { - return callback(err); - } + async.waterfall([ + initializeNodeBB, + function (next) { + winston.info('NodeBB Ready'); - winston.info('NodeBB Ready'); + require('./socket.io').server.emit('event:nodebb.ready', { + 'cache-buster': meta.config['cache-buster'], + }); - require('./socket.io').server.emit('event:nodebb.ready', { - 'cache-buster': meta.config['cache-buster'] - }); + plugins.fireHook('action:nodebb.ready'); - plugins.fireHook('action:nodebb.ready'); - - listen(callback); - }); + listen(next); + }, + ], callback); }; function initializeNodeBB(callback) { - winston.info('initializing NodeBB ...'); var middleware = require('./middleware'); async.waterfall([ @@ -91,15 +89,14 @@ function initializeNodeBB(callback) { function (next) { plugins.fireHook('static:app.preload', { app: app, - middleware: middleware + middleware: middleware, }, next); }, function (next) { plugins.fireHook('filter:hotswap.prepare', [], next); }, function (hotswapIds, next) { - routes(app, middleware, hotswapIds); - next(); + routes(app, middleware, hotswapIds, next); }, function (next) { async.series([ @@ -107,8 +104,10 @@ function initializeNodeBB(callback) { languages.init, meta.blacklist.load, ], next); - } - ], callback); + }, + ], function (err) { + callback(err); + }); } function setupExpressApp(app) { @@ -146,7 +145,7 @@ function setupExpressApp(app) { key: nconf.get('sessionKey'), cookie: setupCookie(), resave: true, - saveUninitialized: true + saveUninitialized: true, })); app.use(middleware.addHeaders); @@ -172,7 +171,7 @@ function setupCookie() { var ttl = ttlSeconds || ttlDays || 1209600000; // Default to 14 days var cookie = { - maxAge: ttl + maxAge: ttl, }; if (nconf.get('cookieDomain') || meta.config.cookieDomain) { @@ -221,7 +220,7 @@ function listen(callback) { winston.info('Using ports 80 and 443 is not recommend; use a proxy instead. See README.md'); } - var bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')); + var bind_address = ((nconf.get('bind_address') === '0.0.0.0' || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')); var args = isSocket ? [socketPath] : [port, bind_address]; var oldUmask; @@ -285,4 +284,3 @@ module.exports.testSocket = function (socketPath, callback) { ], callback); }; - diff --git a/src/widgets/admin.js b/src/widgets/admin.js index ecfd73b750..dde3aca43d 100644 --- a/src/widgets/admin.js +++ b/src/widgets/admin.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var fs = require('fs'); var path = require('path'); @@ -16,8 +16,8 @@ admin.get = function (callback) { { name: 'Global Header', template: 'global', location: 'header' }, { name: 'Global Footer', template: 'global', location: 'footer' }, - { name: 'Group Page (Left)', template: 'groups/details.tpl', location: 'left'}, - { name: 'Group Page (Right)', template: 'groups/details.tpl', location: 'right'} + { name: 'Group Page (Left)', template: 'groups/details.tpl', location: 'left' }, + { name: 'Group Page (Right)', template: 'groups/details.tpl', location: 'right' }, ]; plugins.fireHook('filter:widgets.getAreas', defaultAreas, next); @@ -27,7 +27,7 @@ admin.get = function (callback) { }, adminTemplate: function (next) { fs.readFile(path.resolve(nconf.get('views_dir'), 'admin/partials/widget-settings.tpl'), 'utf8', next); - } + }, }, function (err, widgetData) { if (err) { return callback(err); @@ -48,33 +48,34 @@ admin.get = function (callback) { w.content += widgetData.adminTemplate; }); - var templates = [], - list = {}, index = 0; + var templates = []; + var list = {}; + var index = 0; widgetData.areas.forEach(function (area) { if (typeof list[area.template] === 'undefined') { list[area.template] = index; templates.push({ template: area.template, - areas: [] + areas: [], }); - index++; + index += 1; } templates[list[area.template]].areas.push({ name: area.name, - location: area.location + location: area.location, }); }); callback(false, { templates: templates, areas: widgetData.areas, - widgets: widgetData.widgets + widgets: widgetData.widgets, }); }); }); }; -module.exports = admin; \ No newline at end of file +module.exports = admin; diff --git a/src/widgets/index.js b/src/widgets/index.js index eac58e46e3..7ea6727a1e 100644 --- a/src/widgets/index.js +++ b/src/widgets/index.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; var async = require('async'); var winston = require('winston'); @@ -26,7 +26,7 @@ widgets.render = function (uid, area, req, res, callback) { widgetsByLocation[location] = data.global[location].concat(data[area.template][location]); if (!widgetsByLocation[location].length) { - return done(null, {location: location, widgets: []}); + return done(null, { location: location, widgets: [] }); } async.map(widgetsByLocation[location], function (widget, next) { @@ -42,7 +42,7 @@ widgets.render = function (uid, area, req, res, callback) { area: area, data: widget.data, req: req, - res: res + res: res, }, function (err, html) { if (err || html === null) { return next(err); @@ -56,17 +56,17 @@ widgets.render = function (uid, area, req, res, callback) { translator.translate(widget.data.title, function (title) { html = templates.parse(widget.data.container, { title: title, - body: html + body: html, }); - next(null, {html: html}); + next(null, { html: html }); }); } else { - next(null, {html: html}); + next(null, { html: html }); } }); }, function (err, result) { - done(err, {location: location, widgets: result.filter(Boolean)}); + done(err, { location: location, widgets: result.filter(Boolean) }); }); }, callback); }); @@ -89,7 +89,7 @@ widgets.getAreas = function (templates, locations, callback) { if (data && data[index] && data[index][location]) { try { returnData[template][location] = JSON.parse(data[index][location]); - } catch(err) { + } catch (err) { winston.error('can not parse widget data. template: ' + template + ' location: ' + location); returnData[template][location] = []; } @@ -113,7 +113,7 @@ widgets.getArea = function (template, location, callback) { } try { result = JSON.parse(result); - } catch(err) { + } catch (err) { return callback(err); } @@ -133,7 +133,7 @@ widgets.reset = function (callback) { var defaultAreas = [ { name: 'Draft Zone', template: 'global', location: 'header' }, { name: 'Draft Zone', template: 'global', location: 'footer' }, - { name: 'Draft Zone', template: 'global', location: 'sidebar' } + { name: 'Draft Zone', template: 'global', location: 'sidebar' }, ]; async.parallel({ @@ -142,7 +142,7 @@ widgets.reset = function (callback) { }, drafts: function (next) { widgets.getArea('global', 'drafts', next); - } + }, }, function (err, results) { if (err) { return callback(err); @@ -167,7 +167,7 @@ widgets.reset = function (callback) { widgets.setArea({ template: 'global', location: 'drafts', - widgets: drafts + widgets: drafts, }, callback); }); }); diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000000..4dea92c4c9 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,8 @@ +{ + "env": { + "mocha": true + }, + "rules": { + "no-unused-vars": "off" + } +} diff --git a/test/authentication.js b/test/authentication.js index fb26e0bfbf..7b49f69efa 100644 --- a/test/authentication.js +++ b/test/authentication.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require, before*/ + var assert = require('assert'); var nconf = require('nconf'); @@ -12,7 +12,7 @@ describe('authentication', function () { var jar = request.jar(); var regularUid; before(function (done) { - user.create({username: 'regular', password: 'regularpwd', email: 'regular@nodebb.org' }, function (err, uid) { + user.create({ username: 'regular', password: 'regularpwd', email: 'regular@nodebb.org' }, function (err, uid) { assert.ifError(err); regularUid = uid; done(); @@ -23,7 +23,7 @@ describe('authentication', function () { request({ url: nconf.get('url') + '/api/config', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); @@ -36,8 +36,8 @@ describe('authentication', function () { json: true, jar: jar, headers: { - 'x-csrf-token': body.csrf_token - } + 'x-csrf-token': body.csrf_token, + }, }, function (err, response, body) { assert.ifError(err); assert(body); @@ -45,7 +45,7 @@ describe('authentication', function () { request({ url: nconf.get('url') + '/api/me', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); assert(body); @@ -61,7 +61,7 @@ describe('authentication', function () { request({ url: nconf.get('url') + '/api/config', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); @@ -70,15 +70,15 @@ describe('authentication', function () { json: true, jar: jar, headers: { - 'x-csrf-token': body.csrf_token - } + 'x-csrf-token': body.csrf_token, + }, }, function (err) { assert.ifError(err); request({ url: nconf.get('url') + '/api/me', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); assert.equal(body, 'not-authorized'); @@ -93,7 +93,7 @@ describe('authentication', function () { request({ url: nconf.get('url') + '/api/config', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); @@ -105,8 +105,8 @@ describe('authentication', function () { json: true, jar: jar, headers: { - 'x-csrf-token': body.csrf_token - } + 'x-csrf-token': body.csrf_token, + }, }, function (err, response, body) { assert.ifError(err); assert(body); @@ -114,7 +114,7 @@ describe('authentication', function () { request({ url: nconf.get('url') + '/api/me', json: true, - jar: jar + jar: jar, }, function (err, response, body) { assert.ifError(err); assert(body); @@ -136,7 +136,7 @@ describe('authentication', function () { db.sortedSetCard('uid:' + regularUid + ':sessions', function (err, count) { assert.ifError(err); assert(count); - socketAdmin.deleteAllSessions({uid: 1}, {}, function (err) { + socketAdmin.deleteAllSessions({ uid: 1 }, {}, function (err) { assert.ifError(err); db.sortedSetCard('uid:' + regularUid + ':sessions', function (err, count) { assert.ifError(err); @@ -145,13 +145,11 @@ describe('authentication', function () { }); }); }); - }); after(function (done) { db.emptydb(done); }); - }); diff --git a/test/blacklist.js b/test/blacklist.js index 0ffc0f78a1..72f5e1e813 100644 --- a/test/blacklist.js +++ b/test/blacklist.js @@ -1,5 +1,6 @@ 'use strict'; -/*global require, after, before*/ + +/* global require, after, before*/ var async = require('async'); @@ -11,12 +12,11 @@ var user = require('../src/user'); var blacklist = require('../src/meta/blacklist'); describe('blacklist', function () { - var adminUid; before(function (done) { groups.resetCache(); - user.create({username: 'admin'}, function (err, uid) { + user.create({ username: 'admin' }, function (err, uid) { assert.ifError(err); adminUid = uid; groups.join('administrators', adminUid, done); @@ -27,8 +27,8 @@ describe('blacklist', function () { var rules = '1.1.1.1\n2.2.2.2\n::ffff:0:2.2.2.2\n127.0.0.1\n192.168.100.0/22'; it('should validate blacklist', function (done) { - socketBlacklist.validate({uid: adminUid}, { - rules: rules + socketBlacklist.validate({ uid: adminUid }, { + rules: rules, }, function (err, data) { assert.ifError(err); done(); @@ -36,14 +36,14 @@ describe('blacklist', function () { }); it('should error if not admin', function (done) { - socketBlacklist.save({uid: 0}, rules, function (err) { + socketBlacklist.save({ uid: 0 }, rules, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should save blacklist', function (done) { - socketBlacklist.save({uid: adminUid}, rules, function (err) { + socketBlacklist.save({ uid: adminUid }, rules, function (err) { assert.ifError(err); done(); }); diff --git a/test/build.js b/test/build.js index 5fe95561ba..3b6890ebe6 100644 --- a/test/build.js +++ b/test/build.js @@ -5,7 +5,6 @@ var assert = require('assert'); var db = require('./mocks/databasemock'); describe('Build', function () { - it('should build all assets', function (done) { this.timeout(50000); var build = require('../src/meta/build'); diff --git a/test/categories.js b/test/categories.js index e0e035410b..8ef059d8cb 100644 --- a/test/categories.js +++ b/test/categories.js @@ -1,5 +1,4 @@ 'use strict'; -/*global require, after, before*/ var async = require('async'); @@ -23,11 +22,11 @@ describe('Categories', function () { groups.resetCache(); async.parallel({ posterUid: function (next) { - User.create({username: 'poster'}, next); + User.create({ username: 'poster' }, next); }, adminUid: function (next) { - User.create({username: 'admin'}, next); - } + User.create({ username: 'admin' }, next); + }, }, function (err, results) { assert.ifError(err); posterUid = results.posterUid; @@ -38,13 +37,12 @@ describe('Categories', function () { it('should create a new category', function (done) { - Categories.create({ name: 'Test Category', description: 'Test category created by testing script', icon: 'fa-check', blockclass: 'category-blue', - order: '5' + order: '5', }, function (err, category) { assert.ifError(err); @@ -60,7 +58,7 @@ describe('Categories', function () { reverse: true, start: 0, stop: -1, - uid: 0 + uid: 0, }, function (err, categoryData) { assert.equal(err, null); @@ -90,7 +88,7 @@ describe('Categories', function () { reverse: true, start: 0, stop: -1, - uid: 0 + uid: 0, }, function (err, categoryData) { assert.ifError(err); Categories.getRecentTopicReplies(categoryData, 0, function (err) { @@ -109,7 +107,7 @@ describe('Categories', function () { reverse: true, start: 0, stop: 10, - uid: 0 + uid: 0, }, function (err, result) { assert.equal(err, null); @@ -130,7 +128,7 @@ describe('Categories', function () { start: 0, stop: 10, uid: 0, - targetUid: 1 + targetUid: 1, }, function (err, result) { assert.equal(err, null); assert(Array.isArray(result.topics)); @@ -151,7 +149,7 @@ describe('Categories', function () { category: function (next) { Categories.create({ name: 'Test Category 2', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, topic: function (next) { @@ -159,16 +157,16 @@ describe('Categories', function () { uid: posterUid, cid: categoryObj.cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }, next); - } + }, }, function (err, results) { if (err) { return done(err); } moveCid = results.category.cid; moveTid = results.topic.topicData.tid; - Topics.reply({uid: posterUid, content: 'test post', tid: moveTid}, function (err) { + Topics.reply({ uid: posterUid, content: 'test post', tid: moveTid }, function (err) { done(err); }); }); @@ -199,12 +197,12 @@ describe('Categories', function () { cid: categoryObj.cid, title: 'Test Topic Title', content: 'The content of test topic', - tags: ['nodebb'] + tags: ['nodebb'], }, done); }); it('should get recent replies in category', function (done) { - socketCategories.getRecentReplies({uid: posterUid}, categoryObj.cid, function (err, data) { + socketCategories.getRecentReplies({ uid: posterUid }, categoryObj.cid, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -212,7 +210,7 @@ describe('Categories', function () { }); it('should get categories', function (done) { - socketCategories.get({uid: posterUid}, {}, function (err, data) { + socketCategories.get({ uid: posterUid }, {}, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -220,7 +218,7 @@ describe('Categories', function () { }); it('should get watched categories', function (done) { - socketCategories.getWatchedCategories({uid: posterUid}, {}, function (err, data) { + socketCategories.getWatchedCategories({ uid: posterUid }, {}, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -228,7 +226,7 @@ describe('Categories', function () { }); it('should load more topics', function (done) { - socketCategories.loadMore({uid: posterUid}, {cid: categoryObj.cid, after: 0, author: 'poster', tag: 'nodebb'}, function (err, data) { + socketCategories.loadMore({ uid: posterUid }, { cid: categoryObj.cid, after: 0, author: 'poster', tag: 'nodebb' }, function (err, data) { assert.ifError(err); assert(Array.isArray(data.topics)); assert.equal(data.topics[0].user.username, 'poster'); @@ -239,7 +237,7 @@ describe('Categories', function () { }); it('should load page count', function (done) { - socketCategories.getPageCount({uid: posterUid}, categoryObj.cid, function (err, pageCount) { + socketCategories.getPageCount({ uid: posterUid }, categoryObj.cid, function (err, pageCount) { assert.ifError(err); assert.equal(pageCount, 1); done(); @@ -247,7 +245,7 @@ describe('Categories', function () { }); it('should load page count', function (done) { - socketCategories.getTopicCount({uid: posterUid}, categoryObj.cid, function (err, topicCount) { + socketCategories.getTopicCount({ uid: posterUid }, categoryObj.cid, function (err, topicCount) { assert.ifError(err); assert.equal(topicCount, 2); done(); @@ -255,7 +253,7 @@ describe('Categories', function () { }); it('should load category by privilege', function (done) { - socketCategories.getCategoriesByPrivilege({uid: posterUid}, 'find', function (err, data) { + socketCategories.getCategoriesByPrivilege({ uid: posterUid }, 'find', function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -263,7 +261,7 @@ describe('Categories', function () { }); it('should get move categories', function (done) { - socketCategories.getMoveCategories({uid: posterUid}, {}, function (err, data) { + socketCategories.getMoveCategories({ uid: posterUid }, {}, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -271,7 +269,7 @@ describe('Categories', function () { }); it('should ignore category', function (done) { - socketCategories.ignore({uid: posterUid}, categoryObj.cid, function (err) { + socketCategories.ignore({ uid: posterUid }, categoryObj.cid, function (err) { assert.ifError(err); Categories.isIgnored([categoryObj.cid], posterUid, function (err, isIgnored) { assert.ifError(err); @@ -282,7 +280,7 @@ describe('Categories', function () { }); it('should watch category', function (done) { - socketCategories.watch({uid: posterUid}, categoryObj.cid, function (err) { + socketCategories.watch({ uid: posterUid }, categoryObj.cid, function (err) { assert.ifError(err); Categories.isIgnored([categoryObj.cid], posterUid, function (err, isIgnored) { assert.ifError(err); @@ -293,15 +291,15 @@ describe('Categories', function () { }); it('should check if user is moderator', function (done) { - socketCategories.isModerator({uid: posterUid}, {}, function (err, isModerator) { + socketCategories.isModerator({ uid: posterUid }, {}, function (err, isModerator) { assert.ifError(err); assert(!isModerator); done(); }); }); - it('should get category data' , function (done) { - socketCategories.getCategory({uid: posterUid}, categoryObj.cid, function (err, data) { + it('should get category data', function (done) { + socketCategories.getCategory({ uid: posterUid }, categoryObj.cid, function (err, data) { assert.ifError(err); assert.equal(categoryObj.cid, data.cid); done(); @@ -313,12 +311,12 @@ describe('Categories', function () { var socketCategories = require('../src/socket.io/admin/categories'); var cid; before(function (done) { - socketCategories.create({uid: adminUid}, { + socketCategories.create({ uid: adminUid }, { name: 'update name', description: 'update description', parentCid: categoryObj.cid, icon: 'fa-check', - order: '5' + order: '5', }, function (err, category) { assert.ifError(err); @@ -328,7 +326,7 @@ describe('Categories', function () { }); it('should return error with invalid data', function (done) { - socketCategories.update({uid: adminUid}, null, function (err) { + socketCategories.update({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -337,9 +335,9 @@ describe('Categories', function () { it('should error if you try to set parent as self', function (done) { var updateData = {}; updateData[cid] = { - parentCid: cid + parentCid: cid, }; - socketCategories.update({uid: adminUid}, updateData, function (err) { + socketCategories.update({ uid: adminUid }, updateData, function (err) { assert.equal(err.message, '[[error:cant-set-self-as-parent]]'); done(); }); @@ -352,9 +350,9 @@ describe('Categories', function () { description: 'new description', parentCid: 0, order: 3, - icon: 'fa-hammer' + icon: 'fa-hammer', }; - socketCategories.update({uid: adminUid}, updateData, function (err) { + socketCategories.update({ uid: adminUid }, updateData, function (err) { assert.ifError(err); Categories.getCategoryData(cid, function (err, data) { assert.ifError(err); @@ -371,34 +369,34 @@ describe('Categories', function () { it('should purge category', function (done) { Categories.create({ name: 'purge me', - description: 'update description' + description: 'update description', }, function (err, category) { assert.ifError(err); Topics.post({ uid: posterUid, cid: category.cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }, function (err) { assert.ifError(err); - socketCategories.purge({uid: adminUid}, category.cid, function (err) { + socketCategories.purge({ uid: adminUid }, category.cid, function (err) { assert.ifError(err); done(); }); }); - }); }); it('should get all categories', function (done) { - socketCategories.getAll({uid: adminUid}, {}, function (err, data) { + socketCategories.getAll({ uid: adminUid }, {}, function (err, data) { assert.ifError(err); + assert(data); done(); }); }); it('should get all category names', function (done) { - socketCategories.getNames({uid: adminUid}, {}, function (err, data) { + socketCategories.getNames({ uid: adminUid }, {}, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); done(); @@ -406,7 +404,7 @@ describe('Categories', function () { }); it('should give privilege', function (done) { - socketCategories.setPrivilege({uid: adminUid}, {cid: categoryObj.cid, privilege: ['groups:topics:delete'], set: true, member: 'registered-users'}, function (err) { + socketCategories.setPrivilege({ uid: adminUid }, { cid: categoryObj.cid, privilege: ['groups:topics:delete'], set: true, member: 'registered-users' }, function (err) { assert.ifError(err); privileges.categories.can('topics:delete', categoryObj.cid, posterUid, function (err, canDeleteTopcis) { assert.ifError(err); @@ -417,7 +415,7 @@ describe('Categories', function () { }); it('should remove privilege', function (done) { - socketCategories.setPrivilege({uid: adminUid}, {cid: categoryObj.cid, privilege: 'groups:topics:delete', set: false, member: 'registered-users'}, function (err) { + socketCategories.setPrivilege({ uid: adminUid }, { cid: categoryObj.cid, privilege: 'groups:topics:delete', set: false, member: 'registered-users' }, function (err) { assert.ifError(err); privileges.categories.can('topics:delete', categoryObj.cid, posterUid, function (err, canDeleteTopcis) { assert.ifError(err); @@ -428,7 +426,7 @@ describe('Categories', function () { }); it('should get privilege settings', function (done) { - socketCategories.getPrivilegeSettings({uid: adminUid}, categoryObj.cid, function (err, data) { + socketCategories.getPrivilegeSettings({ uid: adminUid }, categoryObj.cid, function (err, data) { assert.ifError(err); assert(data); done(); @@ -441,22 +439,22 @@ describe('Categories', function () { var child2Cid; async.waterfall([ function (next) { - Categories.create({name: 'parent'}, next); + Categories.create({ name: 'parent' }, next); }, function (category, next) { parentCid = category.cid; - Categories.create({name: 'child1', parentCid: parentCid}, next); + Categories.create({ name: 'child1', parentCid: parentCid }, next); }, function (category, next) { child1Cid = category.cid; - Categories.create({name: 'child2', parentCid: child1Cid}, next); + Categories.create({ name: 'child2', parentCid: child1Cid }, next); }, function (category, next) { child2Cid = category.cid; - socketCategories.setPrivilege({uid: adminUid}, {cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users'}, next); + socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next); }, function (next) { - socketCategories.copyPrivilegesToChildren({uid: adminUid}, parentCid, next); + socketCategories.copyPrivilegesToChildren({ uid: adminUid }, parentCid, next); }, function (next) { privileges.categories.can('topics:delete', child2Cid, posterUid, next); @@ -464,7 +462,7 @@ describe('Categories', function () { function (canDelete, next) { assert(canDelete); next(); - } + }, ], done); }); @@ -473,15 +471,15 @@ describe('Categories', function () { var parentCid; async.waterfall([ function (next) { - Categories.create({name: 'parent', description: 'copy me'}, next); + Categories.create({ name: 'parent', description: 'copy me' }, next); }, function (category, next) { parentCid = category.cid; - Categories.create({name: 'child1'}, next); + Categories.create({ name: 'child1' }, next); }, function (category, next) { child1Cid = category.cid; - socketCategories.copySettingsFrom({uid: adminUid}, {fromCid: parentCid, toCid: child1Cid}, next); + socketCategories.copySettingsFrom({ uid: adminUid }, { fromCid: parentCid, toCid: child1Cid }, next); }, function (canDelete, next) { Categories.getCategoryField(child1Cid, 'description', next); @@ -489,7 +487,7 @@ describe('Categories', function () { function (description, next) { assert.equal(description, 'copy me'); next(); - } + }, ], done); }); @@ -498,18 +496,18 @@ describe('Categories', function () { var parentCid; async.waterfall([ function (next) { - Categories.create({name: 'parent', description: 'copy me'}, next); + Categories.create({ name: 'parent', description: 'copy me' }, next); }, function (category, next) { parentCid = category.cid; - Categories.create({name: 'child1'}, next); + Categories.create({ name: 'child1' }, next); }, function (category, next) { child1Cid = category.cid; - socketCategories.setPrivilege({uid: adminUid}, {cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users'}, next); + socketCategories.setPrivilege({ uid: adminUid }, { cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users' }, next); }, function (next) { - socketCategories.copyPrivilegesFrom({uid: adminUid}, {fromCid: parentCid, toCid: child1Cid}, next); + socketCategories.copyPrivilegesFrom({ uid: adminUid }, { fromCid: parentCid, toCid: child1Cid }, next); }, function (next) { privileges.categories.can('topics:delete', child1Cid, posterUid, next); @@ -517,21 +515,21 @@ describe('Categories', function () { function (canDelete, next) { assert(canDelete); next(); - } + }, ], done); }); }); it('should get active users', function (done) { Categories.create({ - name: 'test' + name: 'test', }, function (err, category) { assert.ifError(err); Topics.post({ uid: posterUid, cid: category.cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }, function (err) { assert.ifError(err); Categories.getActiveUsers(category.cid, function (err, uids) { @@ -548,7 +546,7 @@ describe('Categories', function () { var socketTopics = require('../src/socket.io/topics'); before(function (done) { Categories.create({ - name: 'test' + name: 'test', }, function (err, category) { assert.ifError(err); cid = category.cid; @@ -557,14 +555,14 @@ describe('Categories', function () { }); it('should error if data is invalid', function (done) { - socketTopics.isTagAllowed({uid: posterUid}, null, function (err) { + socketTopics.isTagAllowed({ uid: posterUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should return true if category whitelist is empty', function (done) { - socketTopics.isTagAllowed({uid: posterUid}, {tag: 'notallowed', cid: cid}, function (err, allowed) { + socketTopics.isTagAllowed({ uid: posterUid }, { tag: 'notallowed', cid: cid }, function (err, allowed) { assert.ifError(err); assert(allowed); done(); @@ -574,7 +572,7 @@ describe('Categories', function () { it('should add tags to category whitelist', function (done) { var data = {}; data[cid] = { - tagWhitelist: 'nodebb,jquery,javascript' + tagWhitelist: 'nodebb,jquery,javascript', }; Categories.update(data, function (err) { assert.ifError(err); @@ -587,7 +585,7 @@ describe('Categories', function () { }); it('should return false if category whitelist does not have tag', function (done) { - socketTopics.isTagAllowed({uid: posterUid}, {tag: 'notallowed', cid: cid}, function (err, allowed) { + socketTopics.isTagAllowed({ uid: posterUid }, { tag: 'notallowed', cid: cid }, function (err, allowed) { assert.ifError(err); assert(!allowed); done(); @@ -595,7 +593,7 @@ describe('Categories', function () { }); it('should return true if category whitelist has tag', function (done) { - socketTopics.isTagAllowed({uid: posterUid}, {tag: 'nodebb', cid: cid}, function (err, allowed) { + socketTopics.isTagAllowed({ uid: posterUid }, { tag: 'nodebb', cid: cid }, function (err, allowed) { assert.ifError(err); assert(allowed); done(); @@ -608,7 +606,7 @@ describe('Categories', function () { cid: cid, title: 'Test Topic Title', content: 'The content of test topic', - tags: ['nodebb', 'jquery', 'notallowed'] + tags: ['nodebb', 'jquery', 'notallowed'], }, function (err, data) { assert.ifError(err); assert.equal(data.topicData.tags.length, 2); @@ -618,6 +616,72 @@ describe('Categories', function () { }); + describe('privileges', function () { + var privileges = require('../src/privileges'); + + it('should return empty array if uids is empty array', function (done) { + privileges.categories.filterUids('find', categoryObj.cid, [], function (err, uids) { + assert.ifError(err); + assert.equal(uids.length, 0); + done(); + }); + }); + + it('should filter uids by privilege', function (done) { + privileges.categories.filterUids('find', categoryObj.cid, [1, 2, 3, 4], function (err, uids) { + assert.ifError(err); + assert.deepEqual(uids, [1, 2]); + done(); + }); + }); + + it('should load user privileges', function (done) { + privileges.categories.userPrivileges(categoryObj.cid, 1, function (err, data) { + assert.ifError(err); + assert.deepEqual(data, { + find: false, + mods: false, + 'posts:delete': false, + read: false, + 'topics:reply': false, + 'topics:read': false, + 'topics:create': false, + 'topics:delete': false, + 'posts:edit': false, + }); + + done(); + }); + }); + + it('should load group privileges', function (done) { + privileges.categories.groupPrivileges(categoryObj.cid, 'registered-users', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, { + 'groups:find': true, + 'groups:posts:edit': true, + 'groups:topics:delete': false, + 'groups:topics:create': true, + 'groups:topics:reply': true, + 'groups:posts:delete': true, + 'groups:read': true, + 'groups:topics:read': true, + }); + + done(); + }); + }); + + it('should return false if cid is falsy', function (done) { + privileges.categories.isUserAllowedTo('find', null, adminUid, function (err, isAllowed) { + assert.ifError(err); + assert.equal(isAllowed, false); + done(); + }); + }); + }); + + after(function (done) { db.emptydb(done); }); diff --git a/test/controllers-admin.js b/test/controllers-admin.js index 41ffacca29..5a17ca96a9 100644 --- a/test/controllers-admin.js +++ b/test/controllers-admin.js @@ -13,7 +13,6 @@ var groups = require('../src/groups'); var helpers = require('./helpers'); describe('Admin Controllers', function () { - var tid; var cid; var pid; @@ -22,19 +21,20 @@ describe('Admin Controllers', function () { var jar; before(function (done) { + groups.resetCache(); async.series({ category: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, adminUid: function (next) { - user.create({username: 'admin', password: 'barbar'}, next); + user.create({ username: 'admin', password: 'barbar' }, next); }, regularUid: function (next) { - user.create({username: 'regular'}, next); - } + user.create({ username: 'regular' }, next); + }, }, function (err, results) { if (err) { return done(err); @@ -43,10 +43,11 @@ describe('Admin Controllers', function () { regularUid = results.regularUid; cid = results.category.cid; - topics.post({uid: adminUid, title: 'test topic title', content: 'test topic content', cid: results.category.cid}, function (err, result) { + topics.post({ uid: adminUid, title: 'test topic title', content: 'test topic content', cid: results.category.cid }, function (err, result) { + assert.ifError(err); tid = result.topicData.tid; pid = result.postData.pid; - done(err); + done(); }); }); }); @@ -55,7 +56,7 @@ describe('Admin Controllers', function () { helpers.loginUser('admin', 'barbar', function (err, _jar) { assert.ifError(err); jar = _jar; - request(nconf.get('url') + '/admin', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 403); assert(body); @@ -67,7 +68,7 @@ describe('Admin Controllers', function () { it('should load admin dashboard', function (done) { groups.join('administrators', adminUid, function (err) { assert.ifError(err); - request(nconf.get('url') + '/admin', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -77,7 +78,7 @@ describe('Admin Controllers', function () { }); it('should load groups page', function (done) { - request(nconf.get('url') + '/admin/manage/groups', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin/manage/groups', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -86,7 +87,7 @@ describe('Admin Controllers', function () { }); it('should load groups detail page', function (done) { - request(nconf.get('url') + '/admin/manage/groups/administrators', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin/manage/groups/administrators', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -96,7 +97,7 @@ describe('Admin Controllers', function () { it('should load general settings page', function (done) { - request(nconf.get('url') + '/admin/settings', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin/settings', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -105,7 +106,7 @@ describe('Admin Controllers', function () { }); it('should load email settings page', function (done) { - request(nconf.get('url') + '/admin/settings/email', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/admin/settings/email', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -114,7 +115,7 @@ describe('Admin Controllers', function () { }); it('should load info page for a user', function (done) { - request(nconf.get('url') + '/api/user/regular/info', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/regular/info', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body.history); @@ -127,7 +128,7 @@ describe('Admin Controllers', function () { }); it('should 404 for edit/email page if user does not exist', function (done) { - request(nconf.get('url') + '/api/user/doesnotexist/edit/email', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/doesnotexist/edit/email', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 404); done(); @@ -135,7 +136,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/general/homepage', function (done) { - request(nconf.get('url') + '/api/admin/general/homepage', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/general/homepage', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body.routes); @@ -144,7 +145,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/database', function (done) { - request(nconf.get('url') + '/api/admin/advanced/database', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/database', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); @@ -158,7 +159,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/extend/plugins', function (done) { - request(nconf.get('url') + '/api/admin/extend/plugins', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/extend/plugins', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body.hasOwnProperty('installed')); assert(body.hasOwnProperty('upgradeCount')); @@ -169,7 +170,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users', function (done) { - request(nconf.get('url') + '/api/admin/manage/users', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -177,7 +178,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/search', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/search', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/search', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body.users); done(); @@ -185,7 +186,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/not-validated', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/not-validated', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/not-validated', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -193,7 +194,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/no-posts', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/no-posts', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/no-posts', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -201,7 +202,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/top-posters', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/top-posters', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/top-posters', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -209,7 +210,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/most-reputation', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/most-reputation', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/most-reputation', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -217,7 +218,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/inactive', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/inactive', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/inactive', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -225,7 +226,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/flagged', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/flagged', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/flagged', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -233,7 +234,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/users/banned', function (done) { - request(nconf.get('url') + '/api/admin/manage/users/banned', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/users/banned', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -241,7 +242,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/registration', function (done) { - request(nconf.get('url') + '/api/admin/manage/registration', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/registration', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -249,7 +250,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/users/csv', function (done) { - request(nconf.get('url') + '/api/admin/users/csv', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/users/csv', { jar: jar }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -257,7 +258,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/flags', function (done) { - request(nconf.get('url') + '/api/admin/manage/flags', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/flags', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -265,7 +266,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/cache', function (done) { - request(nconf.get('url') + '/api/admin/advanced/cache', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/cache', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -273,7 +274,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/errors', function (done) { - request(nconf.get('url') + '/api/admin/advanced/errors', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/errors', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -281,7 +282,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/errors/export', function (done) { - request(nconf.get('url') + '/api/admin/advanced/errors/export', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/errors/export', { jar: jar }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -289,7 +290,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/logs', function (done) { - request(nconf.get('url') + '/api/admin/advanced/logs', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/logs', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -297,7 +298,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/general/navigation', function (done) { - request(nconf.get('url') + '/api/admin/general/navigation', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/general/navigation', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -305,7 +306,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/development/info', function (done) { - request(nconf.get('url') + '/api/admin/development/info', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/development/info', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -313,7 +314,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/development/logger', function (done) { - request(nconf.get('url') + '/api/admin/development/logger', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/development/logger', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -321,7 +322,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/advanced/events', function (done) { - request(nconf.get('url') + '/api/admin/advanced/events', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/advanced/events', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -329,7 +330,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/general/sounds', function (done) { - request(nconf.get('url') + '/api/admin/general/sounds', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/general/sounds', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -337,7 +338,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/categories', function (done) { - request(nconf.get('url') + '/api/admin/manage/categories', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/categories', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -345,7 +346,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/categories/1', function (done) { - request(nconf.get('url') + '/api/admin/manage/categories/1', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/categories/1', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -353,7 +354,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/categories/1/analytics', function (done) { - request(nconf.get('url') + '/api/admin/manage/categories/1/analytics', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/categories/1/analytics', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -361,7 +362,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/extend/rewards', function (done) { - request(nconf.get('url') + '/api/admin/extend/rewards', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/extend/rewards', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -369,7 +370,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/extend/widgets', function (done) { - request(nconf.get('url') + '/api/admin/extend/widgets', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/extend/widgets', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -377,7 +378,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/general/languages', function (done) { - request(nconf.get('url') + '/api/admin/general/languages', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/general/languages', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -385,7 +386,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/general/social', function (done) { - request(nconf.get('url') + '/api/admin/general/social', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/general/social', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -393,7 +394,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/tags', function (done) { - request(nconf.get('url') + '/api/admin/manage/tags', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/tags', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -401,7 +402,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/manage/ip-blacklist', function (done) { - request(nconf.get('url') + '/api/admin/manage/ip-blacklist', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/ip-blacklist', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -409,7 +410,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/appearance/themes', function (done) { - request(nconf.get('url') + '/api/admin/appearance/themes', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/appearance/themes', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -417,7 +418,7 @@ describe('Admin Controllers', function () { }); it('should load /admin/appearance/customise', function (done) { - request(nconf.get('url') + '/api/admin/appearance/customise', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/appearance/customise', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); @@ -427,7 +428,7 @@ describe('Admin Controllers', function () { it('should load /recent in maintenance mode', function (done) { var meta = require('../src/meta'); meta.config.maintenanceMode = 1; - request(nconf.get('url') + '/api/recent', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/recent', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -438,7 +439,7 @@ describe('Admin Controllers', function () { it('should load /posts/flags', function (done) { - request(nconf.get('url') + '/api/posts/flags', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/posts/flags', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert(body); done(); diff --git a/test/controllers.js b/test/controllers.js index 42070e4c36..e86ae0c00e 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -13,7 +13,6 @@ var meta = require('../src/meta'); describe('Controllers', function () { - var tid; var cid; var pid; @@ -24,18 +23,18 @@ describe('Controllers', function () { category: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, user: function (next) { - user.create({username: 'foo', password: 'barbar'}, next); + user.create({ username: 'foo', password: 'barbar', email: 'foo@test.com' }, next); }, navigation: function (next) { var navigation = require('../src/navigation/admin'); var data = require('../install/data/navigation.json'); navigation.save(data, next); - } + }, }, function (err, results) { if (err) { return done(err); @@ -43,7 +42,7 @@ describe('Controllers', function () { cid = results.category.cid; fooUid = results.user; - topics.post({uid: results.user, title: 'test topic title', content: 'test topic content', cid: results.category.cid}, function (err, result) { + topics.post({ uid: results.user, title: 'test topic title', content: 'test topic content', cid: results.category.cid }, function (err, result) { tid = result.topicData.tid; pid = result.postData.pid; done(err); @@ -52,7 +51,6 @@ describe('Controllers', function () { }); - it('should load default home route', function (done) { request(nconf.get('url'), function (err, res, body) { assert.ifError(err); @@ -138,6 +136,59 @@ describe('Controllers', function () { }); }); + it('should load /register/complete', function (done) { + var plugins = require('../src/plugins'); + function hookMethod(data, next) { + data.interstitials.push({ template: 'topic.tpl', data: {} }); + next(null, data); + } + + plugins.registerHook('myTestPlugin', { + hook: 'filter:register.interstitial', + method: hookMethod, + }); + + var data = { + username: 'interstitial', + password: '123456', + email: 'test@me.com', + }; + + var jar = request.jar(); + request({ + url: nconf.get('url') + '/api/config', + json: true, + jar: jar, + }, function (err, response, body) { + assert.ifError(err); + + request.post(nconf.get('url') + '/register', { + form: data, + json: true, + jar: jar, + headers: { + 'x-csrf-token': body.csrf_token, + }, + }, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert.equal(body.referrer, nconf.get('relative_path') + '/register/complete'); + request(nconf.get('url') + '/api/register/complete', { + jar: jar, + json: true, + }, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body.sections); + assert(body.errors); + assert(body.title); + plugins.unregisterHook('myTestPlugin', 'filter:register.interstitial', hookMethod); + done(); + }); + }); + }); + }); + it('should load /robots.txt', function (done) { request(nconf.get('url') + '/robots.txt', function (err, res, body) { assert.ifError(err); @@ -444,14 +495,26 @@ describe('Controllers', function () { groups.create({ name: 'group-details', description: 'Foobar!', - hidden: 0 + hidden: 0, }, function (err) { assert.ifError(err); - request(nconf.get('url') + '/groups/group-details', function (err, res, body) { + groups.join('group-details', fooUid, function (err) { assert.ifError(err); - assert.equal(res.statusCode, 200); - assert(body); - done(); + topics.post({ + uid: fooUid, + title: 'topic title', + content: 'test topic content', + cid: cid, + }, function (err) { + assert.ifError(err); + request(nconf.get('url') + '/api/groups/group-details', { json: true }, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + assert.equal(body.posts[0].content, 'test topic content'); + done(); + }); + }); }); }); }); @@ -470,10 +533,10 @@ describe('Controllers', function () { groups.create({ name: 'hidden-group', description: 'Foobar!', - hidden: 1 + hidden: 1, }, function (err) { assert.ifError(err); - request(nconf.get('url') + '/groups/hidden-group/members', function (err, res, body) { + request(nconf.get('url') + '/groups/hidden-group/members', function (err, res) { assert.ifError(err); assert.equal(res.statusCode, 404); done(); @@ -481,6 +544,15 @@ describe('Controllers', function () { }); }); + it('should get recent posts', function (done) { + request(nconf.get('url') + '/api/recent/posts/month', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + it('should get post data', function (done) { request(nconf.get('url') + '/api/post/pid/' + pid, function (err, res, body) { assert.ifError(err); @@ -515,7 +587,7 @@ describe('Controllers', function () { var csrf_token; var helpers = require('./helpers'); before(function (done) { - user.create({username: 'revokeme', password: 'barbar'}, function (err, _uid) { + user.create({ username: 'revokeme', password: 'barbar' }, function (err, _uid) { assert.ifError(err); uid = _uid; helpers.loginUser('revokeme', 'barbar', function (err, _jar, io, _csrf_token) { @@ -531,9 +603,9 @@ describe('Controllers', function () { request.del(nconf.get('url') + '/api/user/revokeme/session', { jar: jar, headers: { - 'x-csrf-token': csrf_token - } - }, function (err, res, body) { + 'x-csrf-token': csrf_token, + }, + }, function (err, res) { assert.ifError(err); assert.equal(res.statusCode, 404); done(); @@ -544,8 +616,8 @@ describe('Controllers', function () { request.del(nconf.get('url') + '/api/user/doesnotexist/session/1112233', { jar: jar, headers: { - 'x-csrf-token': csrf_token - } + 'x-csrf-token': csrf_token, + }, }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 403); @@ -564,8 +636,8 @@ describe('Controllers', function () { request.del(nconf.get('url') + '/api/user/revokeme/session/' + sessionObj.meta.uuid, { jar: jar, headers: { - 'x-csrf-token': csrf_token - } + 'x-csrf-token': csrf_token, + }, }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); @@ -592,25 +664,25 @@ describe('Controllers', function () { widgets: [ { widget: 'html', - data: [ { + data: [{ widget: 'html', data: { html: 'test', title: '', - container: '' - } - } ] - } - ] + container: '', + }, + }], + }, + ], }; widgets.setArea(data, next); - } + }, ], done); }); it('should return {} if there is no template or locations', function (done) { - request(nconf.get('url') + '/api/widgets/render', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/widgets/render', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -621,7 +693,7 @@ describe('Controllers', function () { it('should render templates', function (done) { var url = nconf.get('url') + '/api/widgets/render?template=categories.tpl&url=&isMobile=false&locations%5B%5D=sidebar&locations%5B%5D=footer&locations%5B%5D=header'; - request(url, {json: true}, function (err, res, body) { + request(url, { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -638,7 +710,7 @@ describe('Controllers', function () { title: 'topic title', content: 'test topic content', cid: cid, - tags: ['nodebb', 'bug', 'test'] + tags: ['nodebb', 'bug', 'test'], }, function (err, result) { assert.ifError(err); tid = result.topicData.tid; @@ -647,7 +719,7 @@ describe('Controllers', function () { }); it('should render tags page', function (done) { - request(nconf.get('url') + '/api/tags', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/tags', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -657,7 +729,7 @@ describe('Controllers', function () { }); it('should render tag page with no topics', function (done) { - request(nconf.get('url') + '/api/tags/notag', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/tags/notag', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -668,7 +740,7 @@ describe('Controllers', function () { }); it('should render tag page with 1 topic', function (done) { - request(nconf.get('url') + '/api/tags/nodebb', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/tags/nodebb', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -681,7 +753,6 @@ describe('Controllers', function () { describe('maintenance mode', function () { - before(function (done) { meta.config.maintenanceMode = 1; done(); @@ -692,7 +763,7 @@ describe('Controllers', function () { }); it('should return 503 in maintenance mode', function (done) { - request(nconf.get('url') + '/recent', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/recent', { json: true }, function (err, res) { assert.ifError(err); assert.equal(res.statusCode, 503); done(); @@ -700,7 +771,7 @@ describe('Controllers', function () { }); it('should return 503 in maintenance mode', function (done) { - request(nconf.get('url') + '/api/recent', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/recent', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 503); assert(body); @@ -709,7 +780,7 @@ describe('Controllers', function () { }); it('should return 200 in maintenance mode', function (done) { - request(nconf.get('url') + '/api/login', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/login', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -748,7 +819,7 @@ describe('Controllers', function () { }); it('should load /user/foo/bookmarks', function (done) { - request(nconf.get('url') + '/api/user/foo/bookmarks', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/bookmarks', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -757,7 +828,7 @@ describe('Controllers', function () { }); it('should load /user/foo/upvoted', function (done) { - request(nconf.get('url') + '/api/user/foo/upvoted', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/upvoted', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -766,7 +837,7 @@ describe('Controllers', function () { }); it('should load /user/foo/downvoted', function (done) { - request(nconf.get('url') + '/api/user/foo/downvoted', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/downvoted', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -784,7 +855,7 @@ describe('Controllers', function () { }); it('should load /user/foo/watched', function (done) { - request(nconf.get('url') + '/api/user/foo/watched', {jar: jar}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/watched', { jar: jar }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -812,7 +883,7 @@ describe('Controllers', function () { tid: 1, from: fooUid, mergeId: 'notifications:user_posted_to|' + 1, - topicTitle: 'topic title' + topicTitle: 'topic title', }; async.waterfall([ function (next) { @@ -825,7 +896,7 @@ describe('Controllers', function () { setTimeout(next, 2500); }, function (next) { - request(nconf.get('url') + '/api/notifications', {jar: jar, json: true}, next); + request(nconf.get('url') + '/api/notifications', { jar: jar, json: true }, next); }, function (res, body, next) { assert.equal(res.statusCode, 200); @@ -837,21 +908,57 @@ describe('Controllers', function () { assert.equal(notif.path, notifData.path); assert.equal(notif.nid, notifData.nid); next(); - } + }, ], done); }); + + it('should 404 if user does not exist', function (done) { + request(nconf.get('url') + '/api/user/email/doesnotexist', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + assert(body); + done(); + }); + }); + + it('should load user by uid', function (done) { + request(nconf.get('url') + '/api/user/uid/' + fooUid, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load user by username', function (done) { + request(nconf.get('url') + '/api/user/username/foo', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load user by email', function (done) { + request(nconf.get('url') + '/api/user/email/foo@test.com', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); }); describe('account follow page', function () { var socketUser = require('../src/socket.io/user'); var uid; before(function (done) { - user.create({username: 'follower'}, function (err, _uid) { + user.create({ username: 'follower' }, function (err, _uid) { assert.ifError(err); uid = _uid; - socketUser.follow({uid: uid}, {uid: fooUid}, function (err) { + socketUser.follow({ uid: uid }, { uid: fooUid }, function (err) { assert.ifError(err); - socketUser.isFollowing({uid: uid}, {uid: fooUid}, function (err, isFollowing) { + socketUser.isFollowing({ uid: uid }, { uid: fooUid }, function (err, isFollowing) { assert.ifError(err); assert(isFollowing); done(); @@ -861,7 +968,7 @@ describe('Controllers', function () { }); it('should get followers page', function (done) { - request(nconf.get('url') + '/api/user/foo/followers', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/followers', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert.equal(body.users[0].username, 'follower'); @@ -870,7 +977,7 @@ describe('Controllers', function () { }); it('should get following page', function (done) { - request(nconf.get('url') + '/api/user/follower/following', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/follower/following', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert.equal(body.users[0].username, 'foo'); @@ -878,10 +985,10 @@ describe('Controllers', function () { }); }); - it('should return empty after unfollow', function (done ) { - socketUser.unfollow({uid: uid}, {uid: fooUid}, function (err) { + it('should return empty after unfollow', function (done) { + socketUser.unfollow({ uid: uid }, { uid: fooUid }, function (err) { assert.ifError(err); - request(nconf.get('url') + '/api/user/foo/followers', {json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/foo/followers', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert.equal(body.users.length, 0); @@ -893,7 +1000,7 @@ describe('Controllers', function () { describe('post redirect', function () { it('should 404 for invalid pid', function (done) { - request(nconf.get('url') + '/post/fail', function (err, res) { + request(nconf.get('url') + '/api/post/fail', function (err, res) { assert.ifError(err); assert.equal(res.statusCode, 404); done(); diff --git a/test/database.js b/test/database.js index 36b2ef932d..f55bf78edb 100644 --- a/test/database.js +++ b/test/database.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var db = require('./mocks/databasemock'); @@ -25,5 +25,4 @@ describe('Test database', function () { require('./database/sets'); require('./database/hash'); require('./database/sorted'); - }); diff --git a/test/database/hash.js b/test/database/hash.js index 811f5254e7..4da340b960 100644 --- a/test/database/hash.js +++ b/test/database/hash.js @@ -1,15 +1,15 @@ 'use strict'; -/*global require, after, before*/ -var async = require('async'), - assert = require('assert'), - db = require('../mocks/databasemock'); + +var async = require('async'); +var assert = require('assert'); +var db = require('../mocks/databasemock'); describe('Hash methods', function () { var testData = { name: 'baris', lastname: 'usakli', - age: 99 + age: 99, }; beforeEach(function (done) { @@ -18,7 +18,7 @@ describe('Hash methods', function () { describe('setObject()', function () { it('should create a object', function (done) { - db.setObject('testObject1', {foo: 'baris', bar: 99}, function (err) { + db.setObject('testObject1', { foo: 'baris', bar: 99 }, function (err) { assert.equal(err, null); assert.equal(arguments.length, 1); done(); @@ -26,7 +26,7 @@ describe('Hash methods', function () { }); it('should do nothing if key is falsy', function (done) { - db.setObject('', {foo: 1, derp: 2}, function (err) { + db.setObject('', { foo: 1, derp: 2 }, function (err) { assert.ifError(err); done(); }); @@ -86,8 +86,8 @@ describe('Hash methods', function () { describe('getObjects()', function () { before(function (done) { async.parallel([ - async.apply(db.setObject, 'testObject4', {name: 'baris'}), - async.apply(db.setObjectField, 'testObject5', 'name', 'ginger') + async.apply(db.setObject, 'testObject4', { name: 'baris' }), + async.apply(db.setObjectField, 'testObject5', 'name', 'ginger'), ], done); }); @@ -161,8 +161,8 @@ describe('Hash methods', function () { describe('getObjectsFields()', function () { before(function (done) { async.parallel([ - async.apply(db.setObject, 'testObject8', {name: 'baris', age:99}), - async.apply(db.setObject, 'testObject9', {name: 'ginger', age: 3}) + async.apply(db.setObject, 'testObject8', { name: 'baris', age: 99 }), + async.apply(db.setObject, 'testObject9', { name: 'ginger', age: 3 }), ], done); }); @@ -278,7 +278,7 @@ describe('Hash methods', function () { describe('deleteObjectField()', function () { before(function (done) { - db.setObject('testObject10', {foo: 'bar', delete: 'this', delete1: 'this', delete2: 'this'}, done); + db.setObject('testObject10', { foo: 'bar', delete: 'this', delete1: 'this', delete2: 'this' }, done); }); it('should delete an objects field', function (done) { @@ -299,7 +299,7 @@ describe('Hash methods', function () { assert.equal(arguments.length, 1); async.parallel({ delete1: async.apply(db.isObjectField, 'testObject10', 'delete1'), - delete2: async.apply(db.isObjectField, 'testObject10', 'delete2') + delete2: async.apply(db.isObjectField, 'testObject10', 'delete2'), }, function (err, results) { assert.ifError(err); assert.equal(results.delete1, false); @@ -312,7 +312,7 @@ describe('Hash methods', function () { describe('incrObjectField()', function () { before(function (done) { - db.setObject('testObject11', {age: 99}, done); + db.setObject('testObject11', { age: 99 }, done); }); it('should set an objects field to 1 if object does not exist', function (done) { @@ -336,7 +336,7 @@ describe('Hash methods', function () { describe('decrObjectField()', function () { before(function (done) { - db.setObject('testObject13', {age: 99}, done); + db.setObject('testObject13', { age: 99 }, done); }); it('should set an objects field to -1 if object does not exist', function (done) { @@ -360,7 +360,7 @@ describe('Hash methods', function () { describe('incrObjectFieldBy()', function () { before(function (done) { - db.setObject('testObject15', {age: 100}, done); + db.setObject('testObject15', { age: 100 }, done); }); it('should set an objects field to 5 if object does not exist', function (done) { @@ -391,7 +391,6 @@ describe('Hash methods', function () { }); - after(function (done) { db.emptydb(done); }); diff --git a/test/database/keys.js b/test/database/keys.js index 430ceebdb5..157cc2ca97 100644 --- a/test/database/keys.js +++ b/test/database/keys.js @@ -1,12 +1,11 @@ 'use strict'; -/*global require, after*/ -var async = require('async'), - assert = require('assert'), - db = require('../mocks/databasemock'); + +var async = require('async'); +var assert = require('assert'); +var db = require('../mocks/databasemock'); describe('Key methods', function () { - beforeEach(function (done) { db.set('testKey', 'testValue', done); }); @@ -78,7 +77,7 @@ describe('Key methods', function () { }, function (next) { db.set('key2', 'value2', next); - } + }, ], function (err) { if (err) { return done(err); @@ -92,7 +91,7 @@ describe('Key methods', function () { }, key2exists: function (next) { db.exists('key2', next); - } + }, }, function (err, results) { assert.equal(err, null); assert.equal(results.key1exists, false); diff --git a/test/database/list.js b/test/database/list.js index cbac21984f..8475ad2f52 100644 --- a/test/database/list.js +++ b/test/database/list.js @@ -1,12 +1,11 @@ 'use strict'; -/*global require, after, before*/ -var async = require('async'), - assert = require('assert'), - db = require('../mocks/databasemock'); + +var async = require('async'); +var assert = require('assert'); +var db = require('../mocks/databasemock'); describe('List methods', function () { - describe('listAppend()', function () { it('should append to a list', function (done) { db.listAppend('testList1', 5, function (err) { @@ -33,7 +32,7 @@ describe('List methods', function () { }, function (next) { db.listPrepend('testList2', 1, next); - } + }, ], function (err) { assert.equal(err, null); done(); @@ -52,7 +51,7 @@ describe('List methods', function () { }, function (next) { db.listAppend('testList4', 5, next); - } + }, ], done); }); @@ -94,7 +93,7 @@ describe('List methods', function () { }, function (next) { db.listPrepend('testList4', 9, next); - } + }, ], done); }); @@ -115,7 +114,7 @@ describe('List methods', function () { async.apply(db.listAppend, 'testList5', 1), async.apply(db.listAppend, 'testList5', 1), async.apply(db.listAppend, 'testList5', 2), - async.apply(db.listAppend, 'testList5', 5) + async.apply(db.listAppend, 'testList5', 5), ], done); }); diff --git a/test/database/sets.js b/test/database/sets.js index aa3eda0c3d..a3e79df81c 100644 --- a/test/database/sets.js +++ b/test/database/sets.js @@ -1,12 +1,11 @@ 'use strict'; -/*global require, after, before*/ -var async = require('async'), - assert = require('assert'), - db = require('../mocks/databasemock'); + +var async = require('async'); +var assert = require('assert'); +var db = require('../mocks/databasemock'); describe('Set methods', function () { - describe('setAdd()', function () { it('should add to a set', function (done) { db.setAdd('testSet1', 5, function (err) { @@ -27,7 +26,7 @@ describe('Set methods', function () { describe('getSetMembers()', function () { before(function (done) { - db.setAdd('testSet2', [1,2,3,4,5], done); + db.setAdd('testSet2', [1, 2, 3, 4, 5], done); }); it('should return an empty set', function (done) { @@ -139,7 +138,7 @@ describe('Set methods', function () { describe('setCount()', function () { before(function (done) { - db.setAdd('testSet5', [1,2,3,4,5], done); + db.setAdd('testSet5', [1, 2, 3, 4, 5], done); }); it('should return the element count of set', function (done) { @@ -155,9 +154,9 @@ describe('Set methods', function () { describe('setsCount()', function () { before(function (done) { async.parallel([ - async.apply(db.setAdd, 'set5', [1,2,3,4,5]), + async.apply(db.setAdd, 'set5', [1, 2, 3, 4, 5]), async.apply(db.setAdd, 'set6', 1), - async.apply(db.setAdd, 'set7', 2) + async.apply(db.setAdd, 'set7', 2), ], done); }); @@ -211,7 +210,7 @@ describe('Set methods', function () { describe('setRemoveRandom()', function () { before(function (done) { - db.setAdd('testSet7', [1,2,3,4,5], done); + db.setAdd('testSet7', [1, 2, 3, 4, 5], done); }); it('should remove a random element from set', function (done) { diff --git a/test/database/sorted.js b/test/database/sorted.js index ac95fcbe09..939f4b259e 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -1,12 +1,11 @@ 'use strict'; -/*global require, after, before*/ -var async = require('async'), - assert = require('assert'), - db = require('../mocks/databasemock'); + +var async = require('async'); +var assert = require('assert'); +var db = require('../mocks/databasemock'); describe('Sorted Set methods', function () { - before(function (done) { async.parallel([ function (next) { @@ -20,7 +19,7 @@ describe('Sorted Set methods', function () { }, function (next) { db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd'], next); - } + }, ], done); }); @@ -97,7 +96,7 @@ describe('Sorted Set methods', function () { db.getSortedSetRangeWithScores('sortedSetTest1', 0, -1, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); - assert.deepEqual(values, [{value: 'value1', score: 1.1}, {value: 'value2', score: 1.2}, {value: 'value3', score: 1.3}]); + assert.deepEqual(values, [{ value: 'value1', score: 1.1 }, { value: 'value2', score: 1.2 }, { value: 'value3', score: 1.3 }]); done(); }); }); @@ -108,7 +107,7 @@ describe('Sorted Set methods', function () { db.getSortedSetRevRangeWithScores('sortedSetTest1', 0, -1, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); - assert.deepEqual(values, [{value: 'value3', score: 1.3}, {value: 'value2', score: 1.2}, {value: 'value1', score: 1.1}]); + assert.deepEqual(values, [{ value: 'value3', score: 1.3 }, { value: 'value2', score: 1.2 }, { value: 'value1', score: 1.1 }]); done(); }); }); @@ -141,7 +140,7 @@ describe('Sorted Set methods', function () { db.getSortedSetRangeByScoreWithScores('sortedSetTest1', 0, -1, '-inf', 1.2, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); - assert.deepEqual(values, [{value: 'value1', score: 1.1}, {value: 'value2', score: 1.2}]); + assert.deepEqual(values, [{ value: 'value1', score: 1.1 }, { value: 'value2', score: 1.2 }]); done(); }); }); @@ -152,7 +151,7 @@ describe('Sorted Set methods', function () { db.getSortedSetRevRangeByScoreWithScores('sortedSetTest1', 0, -1, '+inf', 1.2, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); - assert.deepEqual(values, [{value: 'value3', score: 1.3}, {value: 'value2', score: 1.2}]); + assert.deepEqual(values, [{ value: 'value3', score: 1.3 }, { value: 'value2', score: 1.2 }]); done(); }); }); @@ -451,7 +450,7 @@ describe('Sorted Set methods', function () { describe('getSortedSetUnion()', function () { it('should return an array of values from both sorted sets sorted by scores lowest to highest', function (done) { - db.getSortedSetUnion({sets: ['sortedSetTest2', 'sortedSetTest3'], start: 0, stop: -1}, function (err, values) { + db.getSortedSetUnion({ sets: ['sortedSetTest2', 'sortedSetTest3'], start: 0, stop: -1 }, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); assert.deepEqual(values, ['value1', 'value2', 'value4']); @@ -462,7 +461,7 @@ describe('Sorted Set methods', function () { describe('getSortedSetRevUnion()', function () { it('should return an array of values from both sorted sets sorted by scores highest to lowest', function (done) { - db.getSortedSetRevUnion({sets: ['sortedSetTest2', 'sortedSetTest3'], start: 0, stop: -1}, function (err, values) { + db.getSortedSetRevUnion({ sets: ['sortedSetTest2', 'sortedSetTest3'], start: 0, stop: -1 }, function (err, values) { assert.equal(err, null); assert.equal(arguments.length, 2); assert.deepEqual(values, ['value4', 'value2', 'value1']); @@ -521,8 +520,8 @@ describe('Sorted Set methods', function () { describe('sortedSetsRemove()', function () { before(function (done) { async.parallel([ - async.apply(db.sortedSetAdd, 'sorted4', [1,2], ['value1', 'value2']), - async.apply(db.sortedSetAdd, 'sorted5', [1,2], ['value1', 'value3']), + async.apply(db.sortedSetAdd, 'sorted4', [1, 2], ['value1', 'value2']), + async.apply(db.sortedSetAdd, 'sorted5', [1, 2], ['value1', 'value3']), ], done); }); @@ -541,7 +540,7 @@ describe('Sorted Set methods', function () { describe('sortedSetsRemoveRangeByScore()', function () { before(function (done) { - db.sortedSetAdd('sorted6', [1,2,3,4,5], ['value1','value2','value3','value4','value5'], done); + db.sortedSetAdd('sorted6', [1, 2, 3, 4, 5], ['value1', 'value2', 'value3', 'value4', 'value5'], done); }); it('should remove elements with scores between min max inclusive', function (done) { @@ -561,11 +560,11 @@ describe('Sorted Set methods', function () { before(function (done) { async.parallel([ function (next) { - db.sortedSetAdd('interSet1', [1,2,3], ['value1', 'value2', 'value3'], next); + db.sortedSetAdd('interSet1', [1, 2, 3], ['value1', 'value2', 'value3'], next); }, function (next) { - db.sortedSetAdd('interSet2', [4,5,6], ['value2', 'value3', 'value5'], next); - } + db.sortedSetAdd('interSet2', [4, 5, 6], ['value2', 'value3', 'value5'], next); + }, ], done); }); @@ -573,7 +572,7 @@ describe('Sorted Set methods', function () { db.getSortedSetIntersect({ sets: ['interSet1', 'interSet2'], start: 0, - stop: -1 + stop: -1, }, function (err, data) { assert.ifError(err); assert.deepEqual(['value2', 'value3'], data); @@ -586,10 +585,10 @@ describe('Sorted Set methods', function () { sets: ['interSet1', 'interSet2'], start: 0, stop: -1, - withScores: true + withScores: true, }, function (err, data) { assert.ifError(err); - assert.deepEqual([{value: 'value2', score: 6}, {value: 'value3', score: 8}], data); + assert.deepEqual([{ value: 'value2', score: 6 }, { value: 'value3', score: 8 }], data); done(); }); }); @@ -600,10 +599,10 @@ describe('Sorted Set methods', function () { start: 0, stop: -1, withScores: true, - aggregate: 'MIN' + aggregate: 'MIN', }, function (err, data) { assert.ifError(err); - assert.deepEqual([{value: 'value2', score: 2}, {value: 'value3', score: 3}], data); + assert.deepEqual([{ value: 'value2', score: 2 }, { value: 'value3', score: 3 }], data); done(); }); }); @@ -614,10 +613,10 @@ describe('Sorted Set methods', function () { start: 0, stop: -1, withScores: true, - aggregate: 'MAX' + aggregate: 'MAX', }, function (err, data) { assert.ifError(err); - assert.deepEqual([{value: 'value2', score: 4}, {value: 'value3', score: 5}], data); + assert.deepEqual([{ value: 'value2', score: 4 }, { value: 'value3', score: 5 }], data); done(); }); }); @@ -628,10 +627,10 @@ describe('Sorted Set methods', function () { start: 0, stop: -1, withScores: true, - weights: [1, 0.5] + weights: [1, 0.5], }, function (err, data) { assert.ifError(err); - assert.deepEqual([{value: 'value2', score: 4}, {value: 'value3', score: 5.5}], data); + assert.deepEqual([{ value: 'value2', score: 4 }, { value: 'value3', score: 5.5 }], data); done(); }); }); @@ -640,7 +639,7 @@ describe('Sorted Set methods', function () { db.getSortedSetIntersect({ sets: ['interSet10', 'interSet12'], start: 0, - stop: -1 + stop: -1, }, function (err, data) { assert.ifError(err); assert.equal(data.length, 0); @@ -652,14 +651,13 @@ describe('Sorted Set methods', function () { db.getSortedSetIntersect({ sets: ['interSet1', 'interSet12'], start: 0, - stop: -1 + stop: -1, }, function (err, data) { assert.ifError(err); assert.equal(data.length, 0); done(); }); }); - }); describe('sortedSetIntersectCard', function () { @@ -676,7 +674,7 @@ describe('Sorted Set methods', function () { }, function (next) { db.sortedSetAdd('interCard4', [0, 0, 0], ['value4', 'value5', 'value6'], next); - } + }, ], done); }); diff --git a/test/groups.js b/test/groups.js index 6e8bf6e0b7..6b52787efa 100644 --- a/test/groups.js +++ b/test/groups.js @@ -20,7 +20,7 @@ describe('Groups', function () { // Create a group to play around with Groups.create({ name: 'Test', - description: 'Foobar!' + description: 'Foobar!', }, next); }, function (next) { @@ -28,7 +28,7 @@ describe('Groups', function () { name: 'PrivateNoJoin', description: 'Private group', private: 1, - disableJoinRequests: 1 + disableJoinRequests: 1, }, next); }, function (next) { @@ -36,27 +36,27 @@ describe('Groups', function () { name: 'PrivateCanJoin', description: 'Private group', private: 1, - disableJoinRequests: 0 + disableJoinRequests: 0, }, next); }, function (next) { // Create a new user User.create({ username: 'testuser', - email: 'b@c.com' + email: 'b@c.com', }, next); }, function (next) { User.create({ username: 'admin', email: 'admin@admin.com', - password: '123456' + password: '123456', }, next); }, function (next) { // Also create a hidden group Groups.join('Hidden', 'Test', next); - } + }, ], function (err, results) { assert.ifError(err); testUid = results[3]; @@ -99,7 +99,7 @@ describe('Groups', function () { var socketGroups = require('../src/socket.io/groups'); it('should return the groups when search query is empty', function (done) { - socketGroups.search({uid: adminUid}, {query: ''}, function (err, groups) { + socketGroups.search({ uid: adminUid }, { query: '' }, function (err, groups) { assert.ifError(err); assert.equal(3, groups.length); done(); @@ -107,7 +107,7 @@ describe('Groups', function () { }); it('should return the "Test" group when searched for', function (done) { - socketGroups.search({uid: adminUid}, {query: 'test'}, function (err, groups) { + socketGroups.search({ uid: adminUid }, { query: 'test' }, function (err, groups) { assert.ifError(err); assert.equal(1, groups.length); assert.strictEqual('Test', groups[0].name); @@ -116,7 +116,7 @@ describe('Groups', function () { }); it('should return the "Test" group when searched for and sort by member count', function (done) { - Groups.search('test', {filterHidden: true, sort: 'count'}, function (err, groups) { + Groups.search('test', { filterHidden: true, sort: 'count' }, function (err, groups) { assert.ifError(err); assert.equal(1, groups.length); assert.strictEqual('Test', groups[0].name); @@ -125,7 +125,7 @@ describe('Groups', function () { }); it('should return the "Test" group when searched for and sort by creation time', function (done) { - Groups.search('test', {filterHidden: true, sort: 'date'}, function (err, groups) { + Groups.search('test', { filterHidden: true, sort: 'date' }, function (err, groups) { assert.ifError(err); assert.equal(1, groups.length); assert.strictEqual('Test', groups[0].name); @@ -136,12 +136,12 @@ describe('Groups', function () { it('should return all users if no query', function (done) { User.create({ username: 'newuser', - email: 'newuser@b.com' + email: 'newuser@b.com', }, function (err, uid) { assert.ifError(err); Groups.join('Test', uid, function (err) { assert.ifError(err); - socketGroups.searchMembers({uid: adminUid}, {groupName: 'Test', query: ''}, function (err, data) { + socketGroups.searchMembers({ uid: adminUid }, { groupName: 'Test', query: '' }, function (err, data) { assert.ifError(err); assert.equal(data.users.length, 2); done(); @@ -151,13 +151,12 @@ describe('Groups', function () { }); it('should search group members', function (done) { - socketGroups.searchMembers({uid: adminUid}, {groupName: 'Test', query: 'test'}, function (err, data) { + socketGroups.searchMembers({ uid: adminUid }, { groupName: 'Test', query: 'test' }, function (err, data) { assert.ifError(err); assert.strictEqual('testuser', data.users[0].username); done(); }); }); - }); describe('.isMember()', function () { @@ -227,7 +226,7 @@ describe('Groups', function () { it('should create another group', function (done) { Groups.create({ name: 'foo', - description: 'bar' + description: 'bar', }, function (err) { assert.ifError(err); Groups.get('foo', {}, done); @@ -235,7 +234,7 @@ describe('Groups', function () { }); it('should fail to create group with duplicate group name', function (done) { - Groups.create({name: 'foo'}, function (err) { + Groups.create({ name: 'foo' }, function (err) { assert(err); assert.equal(err.message, '[[error:group-already-exists]]'); done(); @@ -243,21 +242,21 @@ describe('Groups', function () { }); it('should fail to create group if slug is empty', function (done) { - Groups.create({name: '>>>>'}, function (err) { + Groups.create({ name: '>>>>' }, function (err) { assert.equal(err.message, '[[error:invalid-group-name]]'); done(); }); }); it('should fail if group name is invalid', function (done) { - Groups.create({name: 'not/valid'}, function (err) { + Groups.create({ name: 'not/valid' }, function (err) { assert.equal(err.message, '[[error:invalid-group-name]]'); done(); }); }); it('should fail if group name is invalid', function (done) { - Groups.create({name: 'not:valid'}, function (err) { + Groups.create({ name: 'not:valid' }, function (err) { assert.equal(err.message, '[[error:invalid-group-name]]'); done(); }); @@ -284,13 +283,13 @@ describe('Groups', function () { name: 'updateTestGroup', description: 'bar', system: 0, - hidden: 0 + hidden: 0, }, done); }); it('should change an aspect of a group', function (done) { Groups.update('updateTestGroup', { - description: 'baz' + description: 'baz', }, function (err) { assert.ifError(err); @@ -304,7 +303,7 @@ describe('Groups', function () { it('should rename a group if the name was updated', function (done) { Groups.update('updateTestGroup', { - name: 'updateTestGroup?' + name: 'updateTestGroup?', }, function (err) { assert.ifError(err); @@ -316,6 +315,15 @@ describe('Groups', function () { }); }); }); + + it('should fail if system groups is being renamed', function (done) { + Groups.update('administrators', { + name: 'administrators_fail', + }, function (err) { + assert.equal(err.message, '[[error:not-allowed-to-rename-system-group]]'); + done(); + }); + }); }); describe('.destroy()', function () { @@ -434,35 +442,35 @@ describe('Groups', function () { var meta = require('../src/meta'); it('should error if data is null', function (done) { - socketGroups.before({uid: 0}, 'groups.join', null, function (err) { + socketGroups.before({ uid: 0 }, 'groups.join', null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should not error if data is valid', function (done) { - socketGroups.before({uid: 0}, 'groups.join', {}, function (err) { + socketGroups.before({ uid: 0 }, 'groups.join', {}, function (err) { assert.ifError(err); done(); }); }); it('should return error if not logged in', function (done) { - socketGroups.join({uid: 0}, {}, function (err) { + socketGroups.join({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:invalid-uid]]'); done(); }); }); it('should return error if group name is special', function (done) { - socketGroups.join({uid: adminUid}, {groupName: 'administrators'}, function (err) { + socketGroups.join({ uid: adminUid }, { groupName: 'administrators' }, function (err) { assert.equal(err.message, '[[error:not-allowed]]'); done(); }); }); it('should error if group does not exist', function (done) { - socketGroups.join({uid: adminUid}, {groupName: 'doesnotexist'}, function (err) { + socketGroups.join({ uid: adminUid }, { groupName: 'doesnotexist' }, function (err) { assert.equal(err.message, '[[error:no-group]]'); done(); }); @@ -470,7 +478,7 @@ describe('Groups', function () { it('should join test group', function (done) { meta.config.allowPrivateGroups = 0; - socketGroups.join({uid: adminUid}, {groupName: 'Test'}, function (err) { + socketGroups.join({ uid: adminUid }, { groupName: 'Test' }, function (err) { assert.ifError(err); Groups.isMember(adminUid, 'Test', function (err, isMember) { assert.ifError(err); @@ -481,21 +489,21 @@ describe('Groups', function () { }); it('should error if not logged in', function (done) { - socketGroups.leave({uid: 0}, {}, function (err) { + socketGroups.leave({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:invalid-uid]]'); done(); }); }); it('should return error if group name is special', function (done) { - socketGroups.leave({uid: adminUid}, {groupName: 'administrators'}, function (err) { + socketGroups.leave({ uid: adminUid }, { groupName: 'administrators' }, function (err) { assert.equal(err.message, '[[error:cant-remove-self-as-admin]]'); done(); }); }); it('should leave test group', function (done) { - socketGroups.leave({uid: adminUid}, {groupName: 'Test'}, function (err) { + socketGroups.leave({ uid: adminUid }, { groupName: 'Test' }, function (err) { assert.ifError(err); Groups.isMember('Test', adminUid, function (err, isMember) { assert.ifError(err); @@ -507,14 +515,14 @@ describe('Groups', function () { it('should fail to join if group is private and join requests are disabled', function (done) { meta.config.allowPrivateGroups = 1; - socketGroups.join({uid: testUid}, {groupName: 'PrivateNoJoin'}, function (err) { + socketGroups.join({ uid: testUid }, { groupName: 'PrivateNoJoin' }, function (err) { assert.equal(err.message, '[[error:join-requests-disabled]]'); done(); }); }); it('should join if user is admin', function (done) { - socketGroups.join({uid: adminUid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.join({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.ifError(err); Groups.isMember(adminUid, 'PrivateCanJoin', function (err, isMember) { assert.ifError(err); @@ -525,7 +533,7 @@ describe('Groups', function () { }); it('should request membership for regular user', function (done) { - socketGroups.join({uid: testUid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.join({ uid: testUid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.ifError(err); Groups.isPending(testUid, 'PrivateCanJoin', function (err, isPending) { assert.ifError(err); @@ -536,7 +544,7 @@ describe('Groups', function () { }); it('should reject membership of user', function (done) { - socketGroups.reject({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: testUid}, function (err) { + socketGroups.reject({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { assert.ifError(err); Groups.isInvited(testUid, 'PrivateCanJoin', function (err, invited) { assert.ifError(err); @@ -547,16 +555,16 @@ describe('Groups', function () { }); it('should error if not owner or admin', function (done) { - socketGroups.accept({uid: 0}, {groupName: 'PrivateCanJoin', toUid: testUid}, function (err) { + socketGroups.accept({ uid: 0 }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should accept membership of user', function (done) { - socketGroups.join({uid: testUid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.join({ uid: testUid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.ifError(err); - socketGroups.accept({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: testUid}, function (err) { + socketGroups.accept({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { assert.ifError(err); Groups.isMember(testUid, 'PrivateCanJoin', function (err, isMember) { assert.ifError(err); @@ -571,11 +579,11 @@ describe('Groups', function () { function requestMembership(uids, callback) { async.series([ function (next) { - socketGroups.join({uid: uids.uid1}, {groupName: 'PrivateCanJoin'}, next); + socketGroups.join({ uid: uids.uid1 }, { groupName: 'PrivateCanJoin' }, next); }, function (next) { - socketGroups.join({uid: uids.uid2}, {groupName: 'PrivateCanJoin'}, next); - } + socketGroups.join({ uid: uids.uid2 }, { groupName: 'PrivateCanJoin' }, next); + }, ], function (err) { callback(err); }); @@ -585,11 +593,11 @@ describe('Groups', function () { function (next) { async.parallel({ uid1: function (next) { - User.create({username: 'groupuser1'}, next); + User.create({ username: 'groupuser1' }, next); }, uid2: function (next) { - User.create({username: 'groupuser2'}, next); - } + User.create({ username: 'groupuser2' }, next); + }, }, next); }, function (results, next) { @@ -597,7 +605,7 @@ describe('Groups', function () { requestMembership(results, next); }, function (next) { - socketGroups.rejectAll({uid: adminUid}, {groupName: 'PrivateCanJoin'}, next); + socketGroups.rejectAll({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, next); }, function (next) { Groups.getPending('PrivateCanJoin', next); @@ -607,7 +615,7 @@ describe('Groups', function () { requestMembership(uids, next); }, function (next) { - socketGroups.acceptAll({uid: adminUid}, {groupName: 'PrivateCanJoin'}, next); + socketGroups.acceptAll({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, next); }, function (next) { Groups.isMembers([uids.uid1, uids.uid2], 'PrivateCanJoin', next); @@ -616,16 +624,16 @@ describe('Groups', function () { assert(isMembers[0]); assert(isMembers[1]); next(); - } + }, ], function (err) { done(err); }); }); it('should issue invite to user', function (done) { - User.create({username: 'invite1'}, function (err, uid) { + User.create({ username: 'invite1' }, function (err, uid) { assert.ifError(err); - socketGroups.issueInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: uid}, function (err) { + socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) { assert.ifError(err); Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) { assert.ifError(err); @@ -637,16 +645,16 @@ describe('Groups', function () { }); it('should fail with invalid data', function (done) { - socketGroups.issueMassInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', usernames: null}, function (err) { + socketGroups.issueMassInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', usernames: null }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should issue mass invite to users', function (done) { - User.create({username: 'invite2'}, function (err, uid) { + User.create({ username: 'invite2' }, function (err, uid) { assert.ifError(err); - socketGroups.issueMassInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', usernames: 'invite1, invite2'}, function (err) { + socketGroups.issueMassInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', usernames: 'invite1, invite2' }, function (err) { assert.ifError(err); Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) { assert.ifError(err); @@ -658,11 +666,11 @@ describe('Groups', function () { }); it('should rescind invite', function (done) { - User.create({username: 'invite3'}, function (err, uid) { + User.create({ username: 'invite3' }, function (err, uid) { assert.ifError(err); - socketGroups.issueInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: uid}, function (err) { + socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) { assert.ifError(err); - socketGroups.rescindInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: uid}, function (err) { + socketGroups.rescindInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) { assert.ifError(err); Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) { assert.ifError(err); @@ -675,18 +683,18 @@ describe('Groups', function () { }); it('should error if user is not invited', function (done) { - socketGroups.acceptInvite({uid: adminUid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.acceptInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.equal(err.message, '[[error:not-invited]]'); done(); }); }); it('should accept invite', function (done) { - User.create({username: 'invite4'}, function (err, uid) { + User.create({ username: 'invite4' }, function (err, uid) { assert.ifError(err); - socketGroups.issueInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: uid}, function (err) { + socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) { assert.ifError(err); - socketGroups.acceptInvite({uid: uid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.acceptInvite({ uid: uid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.ifError(err); Groups.isMember(uid, 'PrivateCanJoin', function (err, isMember) { assert.ifError(err); @@ -699,11 +707,11 @@ describe('Groups', function () { }); it('should reject invite', function (done) { - User.create({username: 'invite5'}, function (err, uid) { + User.create({ username: 'invite5' }, function (err, uid) { assert.ifError(err); - socketGroups.issueInvite({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: uid}, function (err) { + socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) { assert.ifError(err); - socketGroups.rejectInvite({uid: uid}, {groupName: 'PrivateCanJoin'}, function (err) { + socketGroups.rejectInvite({ uid: uid }, { groupName: 'PrivateCanJoin' }, function (err) { assert.ifError(err); Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) { assert.ifError(err); @@ -716,7 +724,7 @@ describe('Groups', function () { }); it('should grant ownership to user', function (done) { - socketGroups.grant({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: testUid}, function (err) { + socketGroups.grant({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { assert.ifError(err); Groups.ownership.isOwner(testUid, 'PrivateCanJoin', function (err, isOwner) { assert.ifError(err); @@ -727,7 +735,7 @@ describe('Groups', function () { }); it('should rescind ownership from user', function (done) { - socketGroups.rescind({uid: adminUid}, {groupName: 'PrivateCanJoin', toUid: testUid}, function (err) { + socketGroups.rescind({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { assert.ifError(err); Groups.ownership.isOwner(testUid, 'PrivateCanJoin', function (err, isOwner) { assert.ifError(err); @@ -738,14 +746,14 @@ describe('Groups', function () { }); it('should fail to kick user with invalid data', function (done) { - socketGroups.kick({uid: adminUid}, {groupName: 'PrivateCanJoin', uid: adminUid}, function (err) { + socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: adminUid }, function (err) { assert.equal(err.message, '[[error:cant-kick-self]]'); done(); }); }); it('should kick user from group', function (done) { - socketGroups.kick({uid: adminUid}, {groupName: 'PrivateCanJoin', uid: testUid}, function (err) { + socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: testUid }, function (err) { assert.ifError(err); Groups.isMember(testUid, 'PrivateCanJoin', function (err, isMember) { assert.ifError(err); @@ -756,7 +764,7 @@ describe('Groups', function () { }); it('should fail to create group with invalid data', function (done) { - socketGroups.create({uid: 0}, {}, function (err) { + socketGroups.create({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); @@ -765,7 +773,7 @@ describe('Groups', function () { it('should fail to create group if group creation is disabled', function (done) { var oldValue = meta.config.allowGroupCreation; meta.config.allowGroupCreation = 0; - socketGroups.create({uid: 1}, {}, function (err) { + socketGroups.create({ uid: 1 }, {}, function (err) { assert.equal(err.message, '[[error:group-creation-disabled]]'); meta.config.allowGroupCreation = oldValue; done(); @@ -775,7 +783,7 @@ describe('Groups', function () { it('should fail to create group if name is privilege group', function (done) { var oldValue = meta.config.allowGroupCreation; meta.config.allowGroupCreation = 1; - socketGroups.create({uid: 1}, {name: 'cid:1:privileges:groups:find'}, function (err) { + socketGroups.create({ uid: 1 }, { name: 'cid:1:privileges:groups:find' }, function (err) { assert.equal(err.message, '[[error:invalid-group-name]]'); meta.config.allowGroupCreation = oldValue; done(); @@ -786,7 +794,7 @@ describe('Groups', function () { it('should create/update group', function (done) { var oldValue = meta.config.allowGroupCreation; meta.config.allowGroupCreation = 1; - socketGroups.create({uid: adminUid}, {name: 'createupdategroup'}, function (err, groupData) { + socketGroups.create({ uid: adminUid }, { name: 'createupdategroup' }, function (err, groupData) { meta.config.allowGroupCreation = oldValue; assert.ifError(err); assert(groupData); @@ -799,10 +807,10 @@ describe('Groups', function () { userTitleEnabled: 1, disableJoinRequests: 1, hidden: 1, - private: 0 - } + private: 0, + }, }; - socketGroups.update({uid: adminUid}, data, function (err) { + socketGroups.update({ uid: adminUid }, data, function (err) { assert.ifError(err); Groups.get('renamedupdategroup', {}, function (err, groupData) { assert.ifError(err); @@ -819,7 +827,7 @@ describe('Groups', function () { }); it('should delete group', function (done) { - socketGroups.delete({uid: adminUid}, {groupName: 'renamedupdategroup'}, function (err) { + socketGroups.delete({ uid: adminUid }, { groupName: 'renamedupdategroup' }, function (err) { assert.ifError(err); Groups.exists('renamedupdategroup', function (err, exists) { assert.ifError(err); @@ -830,35 +838,35 @@ describe('Groups', function () { }); it('should fail to delete group if name is special', function (done) { - socketGroups.delete({uid: adminUid}, {groupName: 'administrators'}, function (err) { + socketGroups.delete({ uid: adminUid }, { groupName: 'administrators' }, function (err) { assert.equal(err.message, '[[error:not-allowed]]'); done(); }); }); it('should fail to delete group if name is special', function (done) { - socketGroups.delete({uid: adminUid}, {groupName: 'registered-users'}, function (err) { + socketGroups.delete({ uid: adminUid }, { groupName: 'registered-users' }, function (err) { assert.equal(err.message, '[[error:not-allowed]]'); done(); }); }); it('should fail to delete group if name is special', function (done) { - socketGroups.delete({uid: adminUid}, {groupName: 'Global Moderators'}, function (err) { + socketGroups.delete({ uid: adminUid }, { groupName: 'Global Moderators' }, function (err) { assert.equal(err.message, '[[error:not-allowed]]'); done(); }); }); it('should fail to load more groups with invalid data', function (done) { - socketGroups.loadMore({uid: adminUid}, {}, function (err) { + socketGroups.loadMore({ uid: adminUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more groups', function (done) { - socketGroups.loadMore({uid: adminUid}, {after: 0, sort: 'count'}, function (err, data) { + socketGroups.loadMore({ uid: adminUid }, { after: 0, sort: 'count' }, function (err, data) { assert.ifError(err); assert(Array.isArray(data.groups)); done(); @@ -866,14 +874,14 @@ describe('Groups', function () { }); it('should fail to load more members with invalid data', function (done) { - socketGroups.loadMoreMembers({uid: adminUid}, {}, function (err) { + socketGroups.loadMoreMembers({ uid: adminUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more members', function (done) { - socketGroups.loadMoreMembers({uid: adminUid}, {after: 0, groupName: 'PrivateCanJoin'}, function (err, data) { + socketGroups.loadMoreMembers({ uid: adminUid }, { after: 0, groupName: 'PrivateCanJoin' }, function (err, data) { assert.ifError(err); assert(Array.isArray(data.users)); done(); @@ -885,21 +893,21 @@ describe('Groups', function () { var socketGroups = require('../src/socket.io/admin/groups'); it('should fail to create group with invalid data', function (done) { - socketGroups.create({uid: adminUid}, null, function (err) { + socketGroups.create({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should fail to create group if group name is privilege group', function (done) { - socketGroups.create({uid: adminUid}, {name: 'cid:1:privileges:read'}, function (err) { + socketGroups.create({ uid: adminUid }, { name: 'cid:1:privileges:read' }, function (err) { assert.equal(err.message, '[[error:invalid-group-name]]'); done(); }); }); it('should create a group', function (done) { - socketGroups.create({uid: adminUid}, {name: 'newgroup', description: 'group created by admin'}, function (err, groupData) { + socketGroups.create({ uid: adminUid }, { name: 'newgroup', description: 'group created by admin' }, function (err, groupData) { assert.ifError(err); assert.equal(groupData.name, 'newgroup'); assert.equal(groupData.description, 'group created by admin'); @@ -911,14 +919,14 @@ describe('Groups', function () { }); it('should fail to join with invalid data', function (done) { - socketGroups.join({uid: adminUid}, null, function (err) { + socketGroups.join({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should add user to group', function (done) { - socketGroups.join({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) { + socketGroups.join({ uid: adminUid }, { uid: testUid, groupName: 'newgroup' }, function (err) { assert.ifError(err); Groups.isMember(testUid, 'newgroup', function (err, isMember) { assert.ifError(err); @@ -929,35 +937,35 @@ describe('Groups', function () { }); it('should fail to if user is already member', function (done) { - socketGroups.join({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) { + socketGroups.join({ uid: adminUid }, { uid: testUid, groupName: 'newgroup' }, function (err) { assert.equal(err.message, '[[error:group-already-member]]'); done(); }); }); it('it should fail with invalid data', function (done) { - socketGroups.leave({uid: adminUid}, null, function (err) { + socketGroups.leave({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('it should fail if admin tries to remove self', function (done) { - socketGroups.leave({uid: adminUid}, {uid: adminUid, groupName: 'administrators'}, function (err) { + socketGroups.leave({ uid: adminUid }, { uid: adminUid, groupName: 'administrators' }, function (err) { assert.equal(err.message, '[[error:cant-remove-self-as-admin]]'); done(); }); }); it('should fail if user is not member', function (done) { - socketGroups.leave({uid: adminUid}, {uid: 3, groupName: 'newgroup'}, function (err) { + socketGroups.leave({ uid: adminUid }, { uid: 3, groupName: 'newgroup' }, function (err) { assert.equal(err.message, '[[error:group-not-member]]'); done(); }); }); it('should remove user from group', function (done) { - socketGroups.leave({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) { + socketGroups.leave({ uid: adminUid }, { uid: testUid, groupName: 'newgroup' }, function (err) { assert.ifError(err); Groups.isMember(testUid, 'newgroup', function (err, isMember) { assert.ifError(err); @@ -968,7 +976,7 @@ describe('Groups', function () { }); it('should fail with invalid data', function (done) { - socketGroups.update({uid: adminUid}, null, function (err) { + socketGroups.update({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -984,10 +992,10 @@ describe('Groups', function () { userTitleEnabled: 1, disableJoinRequests: 1, hidden: 1, - private: 0 - } + private: 0, + }, }; - socketGroups.update({uid: adminUid}, data, function (err) { + socketGroups.update({ uid: adminUid }, data, function (err) { assert.ifError(err); Groups.get('renamedgroup', {}, function (err, groupData) { assert.ifError(err); @@ -1009,7 +1017,7 @@ describe('Groups', function () { var logoPath = path.join(__dirname, '../test/files/test.png'); var imagePath = path.join(__dirname, '../test/files/groupcover.png'); before(function (done) { - User.create({username: 'regularuser', password: '123456'}, function (err, uid) { + User.create({ username: 'regularuser', password: '123456' }, function (err, uid) { assert.ifError(err); regularUid = uid; async.series([ @@ -1021,15 +1029,15 @@ describe('Groups', function () { }, function (next) { helpers.copyFile(logoPath, imagePath, next); - } + }, ], done); }); }); it('should fail if user is not logged in or not owner', function (done) { - socketGroups.cover.update({uid: 0}, {}, function (err) { + socketGroups.cover.update({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); - socketGroups.cover.update({uid: regularUid}, {}, function (err) { + socketGroups.cover.update({ uid: regularUid }, {}, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); @@ -1039,9 +1047,9 @@ describe('Groups', function () { it('should upload group cover image from file', function (done) { var data = { groupName: 'Test', - file: imagePath + file: imagePath, }; - socketGroups.cover.update({uid: adminUid}, data, function (err, data) { + socketGroups.cover.update({ uid: adminUid }, data, function (err, data) { assert.ifError(err); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); @@ -1055,9 +1063,9 @@ describe('Groups', function () { it('should upload group cover image from data', function (done) { var data = { groupName: 'Test', - imageData: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAAACXBIWXMAAC4jAAAuIwF4pT92AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAACcJJREFUeNqMl9tvnNV6xn/f+s5z8DCeg88Zj+NYdhJH4KShFoJAIkzVphLVJnsDaiV6gUKaC2qQUFVATbnoValAakuQYKMqBKUUJCgI9XBBSmOROMqGoCStHbA9sWM7nrFn/I3n9B17kcwoabfarj9gvet53+d9nmdJAwMDAAgh8DyPtbU1XNfFMAwkScK2bTzPw/M8dF1/SAhxKAiCxxVF2aeqqqTr+q+Af+7o6Ch0d3f/69TU1KwkSRiGwbFjx3jmmWd47rnn+OGHH1BVFYX/5QRBkPQ87xeSJP22YRi/oapqStM0PM/D931kWSYIgnHf98cXFxepVqtomjZt2/Zf2bb990EQ4Pv+PXfeU1CSpGYhfN9/TgjxQTQaJQgCwuEwQRBQKpUwDAPTNPF9n0ajAYDv+8zPzzM+Pr6/Wq2eqdVqfxOJRA6Zpnn57hrivyEC0IQQZ4Mg+MAwDCKRCJIkUa/XEUIQi8XQNI1QKIQkSQghUBQFIQSmaTI7OwtAuVxOTE9Pfzc9Pf27lUqlBUgulUoUi0VKpRKqqg4EQfAfiqLsDIfDAC0E4XCYaDSKEALXdalUKvfM1/d9hBBYlkUul2N4eJi3335bcl33mW+++aaUz+cvSJKE8uKLL6JpGo7j8Omnn/7d+vp6sr+/HyEEjuMgyzKu6yJJEsViEVVV8TyPjY2NVisV5fZkTNMkkUhw8+ZN6vU6Kysr7Nmzh9OnT7/12GOPDS8sLByT7rQR4A9XV1d/+cILLzA9PU0kEmF4eBhFUTh//jyWZaHrOkII0uk0jUaDWq1GJpOhWCyysrLC1tYWnuehqir79+9H13W6urp48803+f7773n++ef/4G7S/H4ikUCSJNbX11trcuvWLcrlMrIs4zgODzzwABMTE/i+T7lcpq2tjUqlwubmJrZts7y8jBCCkZERGo0G2WyWkydPkkql6Onp+eMmwihwc3JyMvrWW2+RTCYBcF0XWZbRdZ3l5WX27NnD008/TSwWQ1VVyuVy63GhUIhEIkEqlcJxHCzLIhaLMTQ0xJkzZ7Btm3379lmS53kIIczZ2dnFsbGxRK1Wo729HQDP8zAMg5WVFXp7e5mcnKSzs5N8Po/rutTrdVzXbQmHrutEo1FM00RVVXp7e0kkEgRBwMWLF9F1vaxUq1UikUjtlVdeuV6pVBJ9fX3Ytn2bwrLMysoKXV1dTE5OkslksCwLTdMwDANVVdnY2CAIApLJJJFIBMdxiMfj7Nq1C1VViUajLQCvvvrqkhKJRJiZmfmdb7/99jeTySSyLLfWodFoEAqFOH78OLt37yaXy2GaJoqisLy8zNTUFFevXiUIAtrb29m5cyePPPJIa+cymQz1eh2A0dFRCoXCsgIwNTW1J5/P093dTbFYRJZlJEmiWq1y4MABxsbGqNVqhEIh6vU6QRBQLpcxDIPh4WE8z2NxcZFTp05x7tw5Xn755ZY6dXZ2tliZzWa/EwD1ev3RsbExxsfHSafTVCoVGo0Gqqqya9cuIpEIQgh832dtbY3FxUUA+vr62LZtG2NjYxw5coTDhw+ztLTEyZMnuXr1KoVC4R4d3bt375R84sQJEY/H/2Jubq7N9326urqwbZt6vY5pmhw5coS+vr4W9YvFIrdu3WJqagohBFeuXOHcuXOtue7evRtN01rtfO+991haWmJkZGQrkUi8JIC9iqL0BkFAIpFACMETTzxBV1cXiUSC7u5uHMfB8zyCIMA0TeLxONlsFlmW8X2fwcFBHMdhfn6eer1Oe3s7Dz30EBMTE1y6dImjR49y6tSppR07dqwrjuM8+OWXXzI0NMTly5e5du0aQ0NDTExMkMvlCIKAIAhaIh2LxQiHw0QiEfL5POl0mlqtRq1Wo6OjA8uykGWZdDrN0tISvb29vPPOOzz++OPk83lELpf7rXfffRfDMOjo6MBxHEqlEocOHWLHjh00Gg0kSULTNIS4bS6qqhKPxxkaGmJ4eJjR0VH279/PwMAA27dvJ5vN4vs+X331FR9//DGzs7OEQiE++eQTlPb29keuX7/OtWvXOH78ONVqlZs3b9LW1kYmk8F13dZeCiGQJAnXdRFCYBgGsiwjhMC2bQqFAkEQoOs6P/74Iw8++CCDg4Pous6xY8f47LPPkIIguDo2Nrbzxo0bfPjhh9i2zczMTHNvcF2XpsZalkWj0cB1Xe4o1O3YoCisra3x008/EY/H6erqAuDAgQNEIhGCIODQoUP/ubCwMCKAjx599FHW19f56KOP6OjooFgsks/niUajKIqCbds4joMQAiFESxxs226xd2Zmhng8Tl9fH67r0mg0sG2bbDZLpVIhl8vd5gHwtysrKy8Dcdd1mZubo6enh1gsRrVabZlrk6VND/R9n3q9TqVSQdd1QqEQi4uLnD9/nlKpxODgIHv37gXAcRyCICiFQiHEzp07i1988cUfKYpCIpHANE22b9/eUhNFUVotDIKghc7zPCzLolKpsLW1RVtbG0EQ4DgOmqbR09NDM1qUSiWAPwdQ7ujjmf7+/kQymfxrSZJQVZWtra2WG+i63iKH53m4rku1WqVcLmNZFu3t7S2x7+/vJ51O89prr7VYfenSpcPAP1UqFeSHH36YeDxOKpW6eP/9988Bv9d09nw+T7VapVKptJjZnE2tVmNtbY1cLke5XGZra4vNzU16enp49tlnGRgYaD7iTxqNxgexWIzDhw+jNEPQHV87NT8/f+PChQtnR0ZGqFarrUVuOsDds2u2b2FhgVQqRSQSYWFhgStXrtDf308ymcwBf3nw4EEOHjx4O5c2lURVVRzHYXp6+t8uX7785IULFz7LZDLous59991HOBy+h31N9xgdHSWTyVCtVhkaGmLfvn1MT08zPz/PzMzM6c8//9xr+uE9QViWZer1OhsbGxiG8fns7OzPc7ncx729vXR3d1OpVNi2bRuhUAhZljEMA9/3sW0bVVVZWlri4sWLjI+P8/rrr/P111/z5JNPXrIs69cn76ZeGoaBpmm0tbX9Q6FQeHhubu7fC4UCkUiE1dVVstks8Xgc0zSRZZlGo9ESAdM02djYoNFo8MYbb2BZ1mYoFOKuZPjr/xZBEHCHred83x/b3Nz8l/X19aRlWWxsbNDZ2cnw8DDhcBjf96lWq/T09HD06FGeeuopXnrpJc6ePUs6nb4hhPi/C959ZFn+TtO0lG3bJ0ql0p85jsPW1haFQoG2tjYkSWpF/Uwmw9raGu+//z7A977vX2+GrP93wSZiTdNOGIbxy3K5/DPHcfYXCoVe27Yzpmm2m6bppVKp/Orqqnv69OmoZVn/mEwm/9TzvP9x138NAMpJ4VFTBr6SAAAAAElFTkSuQmCC' + imageData: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAAACXBIWXMAAC4jAAAuIwF4pT92AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAACcJJREFUeNqMl9tvnNV6xn/f+s5z8DCeg88Zj+NYdhJH4KShFoJAIkzVphLVJnsDaiV6gUKaC2qQUFVATbnoValAakuQYKMqBKUUJCgI9XBBSmOROMqGoCStHbA9sWM7nrFn/I3n9B17kcwoabfarj9gvet53+d9nmdJAwMDAAgh8DyPtbU1XNfFMAwkScK2bTzPw/M8dF1/SAhxKAiCxxVF2aeqqqTr+q+Af+7o6Ch0d3f/69TU1KwkSRiGwbFjx3jmmWd47rnn+OGHH1BVFYX/5QRBkPQ87xeSJP22YRi/oapqStM0PM/D931kWSYIgnHf98cXFxepVqtomjZt2/Zf2bb990EQ4Pv+PXfeU1CSpGYhfN9/TgjxQTQaJQgCwuEwQRBQKpUwDAPTNPF9n0ajAYDv+8zPzzM+Pr6/Wq2eqdVqfxOJRA6Zpnn57hrivyEC0IQQZ4Mg+MAwDCKRCJIkUa/XEUIQi8XQNI1QKIQkSQghUBQFIQSmaTI7OwtAuVxOTE9Pfzc9Pf27lUqlBUgulUoUi0VKpRKqqg4EQfAfiqLsDIfDAC0E4XCYaDSKEALXdalUKvfM1/d9hBBYlkUul2N4eJi3335bcl33mW+++aaUz+cvSJKE8uKLL6JpGo7j8Omnn/7d+vp6sr+/HyEEjuMgyzKu6yJJEsViEVVV8TyPjY2NVisV5fZkTNMkkUhw8+ZN6vU6Kysr7Nmzh9OnT7/12GOPDS8sLByT7rQR4A9XV1d/+cILLzA9PU0kEmF4eBhFUTh//jyWZaHrOkII0uk0jUaDWq1GJpOhWCyysrLC1tYWnuehqir79+9H13W6urp48803+f7773n++ef/4G7S/H4ikUCSJNbX11trcuvWLcrlMrIs4zgODzzwABMTE/i+T7lcpq2tjUqlwubmJrZts7y8jBCCkZERGo0G2WyWkydPkkql6Onp+eMmwihwc3JyMvrWW2+RTCYBcF0XWZbRdZ3l5WX27NnD008/TSwWQ1VVyuVy63GhUIhEIkEqlcJxHCzLIhaLMTQ0xJkzZ7Btm3379lmS53kIIczZ2dnFsbGxRK1Wo729HQDP8zAMg5WVFXp7e5mcnKSzs5N8Po/rutTrdVzXbQmHrutEo1FM00RVVXp7e0kkEgRBwMWLF9F1vaxUq1UikUjtlVdeuV6pVBJ9fX3Ytn2bwrLMysoKXV1dTE5OkslksCwLTdMwDANVVdnY2CAIApLJJJFIBMdxiMfj7Nq1C1VViUajLQCvvvrqkhKJRJiZmfmdb7/99jeTySSyLLfWodFoEAqFOH78OLt37yaXy2GaJoqisLy8zNTUFFevXiUIAtrb29m5cyePPPJIa+cymQz1eh2A0dFRCoXCsgIwNTW1J5/P093dTbFYRJZlJEmiWq1y4MABxsbGqNVqhEIh6vU6QRBQLpcxDIPh4WE8z2NxcZFTp05x7tw5Xn755ZY6dXZ2tliZzWa/EwD1ev3RsbExxsfHSafTVCoVGo0Gqqqya9cuIpEIQgh832dtbY3FxUUA+vr62LZtG2NjYxw5coTDhw+ztLTEyZMnuXr1KoVC4R4d3bt375R84sQJEY/H/2Jubq7N9326urqwbZt6vY5pmhw5coS+vr4W9YvFIrdu3WJqagohBFeuXOHcuXOtue7evRtN01rtfO+991haWmJkZGQrkUi8JIC9iqL0BkFAIpFACMETTzxBV1cXiUSC7u5uHMfB8zyCIMA0TeLxONlsFlmW8X2fwcFBHMdhfn6eer1Oe3s7Dz30EBMTE1y6dImjR49y6tSppR07dqwrjuM8+OWXXzI0NMTly5e5du0aQ0NDTExMkMvlCIKAIAhaIh2LxQiHw0QiEfL5POl0mlqtRq1Wo6OjA8uykGWZdDrN0tISvb29vPPOOzz++OPk83lELpf7rXfffRfDMOjo6MBxHEqlEocOHWLHjh00Gg0kSULTNIS4bS6qqhKPxxkaGmJ4eJjR0VH279/PwMAA27dvJ5vN4vs+X331FR9//DGzs7OEQiE++eQTlPb29keuX7/OtWvXOH78ONVqlZs3b9LW1kYmk8F13dZeCiGQJAnXdRFCYBgGsiwjhMC2bQqFAkEQoOs6P/74Iw8++CCDg4Pous6xY8f47LPPkIIguDo2Nrbzxo0bfPjhh9i2zczMTHNvcF2XpsZalkWj0cB1Xe4o1O3YoCisra3x008/EY/H6erqAuDAgQNEIhGCIODQoUP/ubCwMCKAjx599FHW19f56KOP6OjooFgsks/niUajKIqCbds4joMQAiFESxxs226xd2Zmhng8Tl9fH67r0mg0sG2bbDZLpVIhl8vd5gHwtysrKy8Dcdd1mZubo6enh1gsRrVabZlrk6VND/R9n3q9TqVSQdd1QqEQi4uLnD9/nlKpxODgIHv37gXAcRyCICiFQiHEzp07i1988cUfKYpCIpHANE22b9/eUhNFUVotDIKghc7zPCzLolKpsLW1RVtbG0EQ4DgOmqbR09NDM1qUSiWAPwdQ7ujjmf7+/kQymfxrSZJQVZWtra2WG+i63iKH53m4rku1WqVcLmNZFu3t7S2x7+/vJ51O89prr7VYfenSpcPAP1UqFeSHH36YeDxOKpW6eP/9988Bv9d09nw+T7VapVKptJjZnE2tVmNtbY1cLke5XGZra4vNzU16enp49tlnGRgYaD7iTxqNxgexWIzDhw+jNEPQHV87NT8/f+PChQtnR0ZGqFarrUVuOsDds2u2b2FhgVQqRSQSYWFhgStXrtDf308ymcwBf3nw4EEOHjx4O5c2lURVVRzHYXp6+t8uX7785IULFz7LZDLous59991HOBy+h31N9xgdHSWTyVCtVhkaGmLfvn1MT08zPz/PzMzM6c8//9xr+uE9QViWZer1OhsbGxiG8fns7OzPc7ncx729vXR3d1OpVNi2bRuhUAhZljEMA9/3sW0bVVVZWlri4sWLjI+P8/rrr/P111/z5JNPXrIs69cn76ZeGoaBpmm0tbX9Q6FQeHhubu7fC4UCkUiE1dVVstks8Xgc0zSRZZlGo9ESAdM02djYoNFo8MYbb2BZ1mYoFOKuZPjr/xZBEHCHred83x/b3Nz8l/X19aRlWWxsbNDZ2cnw8DDhcBjf96lWq/T09HD06FGeeuopXnrpJc6ePUs6nb4hhPi/C959ZFn+TtO0lG3bJ0ql0p85jsPW1haFQoG2tjYkSWpF/Uwmw9raGu+//z7A977vX2+GrP93wSZiTdNOGIbxy3K5/DPHcfYXCoVe27Yzpmm2m6bppVKp/Orqqnv69OmoZVn/mEwm/9TzvP9x138NAMpJ4VFTBr6SAAAAAElFTkSuQmCC', }; - socketGroups.cover.update({uid: adminUid}, data, function (err, data) { + socketGroups.cover.update({ uid: adminUid }, data, function (err, data) { assert.ifError(err); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); @@ -1070,9 +1078,9 @@ describe('Groups', function () { it('should update group cover position', function (done) { var data = { groupName: 'Test', - position: '50% 50%' + position: '50% 50%', }; - socketGroups.cover.update({uid: adminUid}, data, function (err) { + socketGroups.cover.update({ uid: adminUid }, data, function (err) { assert.ifError(err); Groups.getGroupFields('Test', ['cover:position'], function (err, groupData) { assert.ifError(err); @@ -1092,7 +1100,7 @@ describe('Groups', function () { it('should error if user is not owner of group', function (done) { helpers.loginUser('regularuser', '123456', function (err, jar, io, csrf_token) { assert.ifError(err); - helpers.uploadFile(nconf.get('url') + '/api/groups/uploadpicture', logoPath, {params: JSON.stringify({groupName: 'Test'})}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/groups/uploadpicture', logoPath, { params: JSON.stringify({ groupName: 'Test' }) }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 500); assert.equal(body.error, '[[error:no-privileges]]'); @@ -1104,7 +1112,7 @@ describe('Groups', function () { it('should upload group cover with api route', function (done) { helpers.loginUser('admin', '123456', function (err, jar, io, csrf_token) { assert.ifError(err); - helpers.uploadFile(nconf.get('url') + '/api/groups/uploadpicture', logoPath, {params: JSON.stringify({groupName: 'Test'})}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/groups/uploadpicture', logoPath, { params: JSON.stringify({ groupName: 'Test' }) }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { @@ -1117,21 +1125,21 @@ describe('Groups', function () { }); it('should fail to remove cover if not logged in', function (done) { - socketGroups.cover.remove({uid: 0}, {groupName: 'Test'}, function (err) { + socketGroups.cover.remove({ uid: 0 }, { groupName: 'Test' }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should fail to remove cover if not owner', function (done) { - socketGroups.cover.remove({uid: regularUid}, {groupName: 'Test'}, function (err) { + socketGroups.cover.remove({ uid: regularUid }, { groupName: 'Test' }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should remove cover', function (done) { - socketGroups.cover.remove({uid: adminUid}, {groupName: 'Test'}, function (err) { + socketGroups.cover.remove({ uid: adminUid }, { groupName: 'Test' }, function (err) { assert.ifError(err); Groups.getGroupFields('Test', ['cover:url'], function (err, groupData) { assert.ifError(err); diff --git a/test/helpers/index.js b/test/helpers/index.js index a0624a69d6..2c37f85500 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -14,7 +14,7 @@ helpers.loginUser = function (username, password, callback) { request({ url: nconf.get('url') + '/api/config', json: true, - jar: jar + jar: jar, }, function (err, res, body) { if (err || res.statusCode !== 200) { return callback(err || new Error('[[error:invalid-response]]')); @@ -28,76 +28,68 @@ helpers.loginUser = function (username, password, callback) { json: true, jar: jar, headers: { - 'x-csrf-token': body.csrf_token - } + 'x-csrf-token': body.csrf_token, + }, }, function (err, res) { if (err || res.statusCode !== 200) { return callback(err || new Error('[[error:invalid-response]]')); } - myXhr.callbacks.test2 = function () { - this.setDisableHeaderCheck(true); - var stdOpen = this.open; - this.open = function () { - stdOpen.apply(this, arguments); - this.setRequestHeader('Cookie', res.headers['set-cookie'][0].split(';')[0]); - this.setRequestHeader('Origin', nconf.get('url')); - }; - }; - - var socketClient = require('socket.io-client'); - - var io = socketClient.connect(nconf.get('url'), {forceNew: true, multiplex: false}); - io.on('connect', function () { - callback(null, jar, io, body.csrf_token); - }); - - io.on('error', function (err) { - callback(err); + helpers.connectSocketIO(res, function (err, io) { + callback(err, jar, io, body.csrf_token); }); }); }); }; +helpers.connectSocketIO = function (res, callback) { + myXhr.callbacks.headerCallback = function () { + this.setDisableHeaderCheck(true); + var stdOpen = this.open; + this.open = function () { + stdOpen.apply(this, arguments); + this.setRequestHeader('Cookie', res.headers['set-cookie'][0].split(';')[0]); + this.setRequestHeader('Origin', nconf.get('url')); + }; + }; + + var socketClient = require('socket.io-client'); + + var io = socketClient.connect(nconf.get('base_url'), { + path: nconf.get('relative_path') + '/socket.io', + forceNew: true, + multiplex: false, + }); + io.on('connect', function () { + callback(null, io); + }); + + io.on('error', function (err) { + callback(err); + }); +}; + helpers.initSocketIO = function (callback) { var jar; request.get({ url: nconf.get('url') + '/api/config', jar: jar, - json: true - }, function (err, res, body) { + json: true, + }, function (err, res) { if (err) { return callback(err); } - - myXhr.callbacks.test2 = function () { - this.setDisableHeaderCheck(true); - var stdOpen = this.open; - this.open = function () { - stdOpen.apply(this, arguments); - this.setRequestHeader('Cookie', res.headers['set-cookie'][0].split(';')[0]); - this.setRequestHeader('Origin', nconf.get('url')); - }; - }; - - var io = require('socket.io-client')(nconf.get('url'), {forceNew: true}); - - io.on('connect', function () { - callback(null, jar, io); - }); - - io.on('error', function (err) { - callback(err); + helpers.connectSocketIO(res, function (err, io) { + callback(err, jar, io); }); }); }; - helpers.uploadFile = function (uploadEndPoint, filePath, body, jar, csrf_token, callback) { var formData = { files: [ fs.createReadStream(filePath), - fs.createReadStream(filePath) // see https://github.com/request/request/issues/2445 - ] + fs.createReadStream(filePath), // see https://github.com/request/request/issues/2445 + ], }; formData = utils.merge(formData, body); request.post({ @@ -106,8 +98,8 @@ helpers.uploadFile = function (uploadEndPoint, filePath, body, jar, csrf_token, json: true, jar: jar, headers: { - 'x-csrf-token': csrf_token - } + 'x-csrf-token': csrf_token, + }, }, function (err, res, body) { if (err) { return callback(err); @@ -121,7 +113,7 @@ helpers.registerUser = function (data, callback) { request({ url: nconf.get('url') + '/api/config', json: true, - jar: jar + jar: jar, }, function (err, response, body) { if (err) { return callback(err); @@ -132,32 +124,27 @@ helpers.registerUser = function (data, callback) { json: true, jar: jar, headers: { - 'x-csrf-token': body.csrf_token - } - }, function (err, res, body) { - if (err) { - return callback(err); - } - - callback(null, jar); + 'x-csrf-token': body.csrf_token, + }, + }, function (err) { + callback(err, jar); }); }); }; -//http://stackoverflow.com/a/14387791/583363 +// http://stackoverflow.com/a/14387791/583363 helpers.copyFile = function (source, target, callback) { - var cbCalled = false; var rd = fs.createReadStream(source); - rd.on("error", function (err) { + rd.on('error', function (err) { done(err); }); var wr = fs.createWriteStream(target); - wr.on("error", function (err) { + wr.on('error', function (err) { done(err); }); - wr.on("close", function () { + wr.on('close', function () { done(); }); rd.pipe(wr); @@ -168,4 +155,4 @@ helpers.copyFile = function (source, target, callback) { cbCalled = true; } } -}; \ No newline at end of file +}; diff --git a/test/messaging.js b/test/messaging.js index 12922f9e1d..4fbaad717f 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -25,7 +25,7 @@ describe('Messaging Library', function () { async.series([ async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user - async.apply(User.create, { username: 'herp', password: 'derpderp' }) // regular user + async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user ], function (err, uids) { if (err) { return done(err); @@ -37,7 +37,7 @@ describe('Messaging Library', function () { async.parallel([ async.apply(Groups.join, 'administrators', fooUid), - async.apply(User.setSetting, bazUid, 'restrictChat', '1') + async.apply(User.setSetting, bazUid, 'restrictChat', '1'), ], done); }); }); @@ -80,7 +80,7 @@ describe('Messaging Library', function () { describe('rooms', function () { var socketModules = require('../src/socket.io/modules'); it('should create a new chat room', function (done) { - socketModules.chats.newRoom({uid: fooUid}, {touid: bazUid}, function (err, _roomId) { + socketModules.chats.newRoom({ uid: fooUid }, { touid: bazUid }, function (err, _roomId) { roomId = _roomId; assert.ifError(err); assert(roomId); @@ -89,14 +89,14 @@ describe('Messaging Library', function () { }); it('should add a user to room', function (done) { - socketModules.chats.addUserToRoom({uid: fooUid}, {roomId: roomId, username: 'herp'}, function (err) { + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'herp' }, function (err) { assert.ifError(err); done(); }); }); it('should leave the chat room', function (done) { - socketModules.chats.leave({uid: bazUid}, roomId, function (err) { + socketModules.chats.leave({ uid: bazUid }, roomId, function (err) { assert.ifError(err); Messaging.isUserInRoom(bazUid, roomId, function (err, isUserInRoom) { assert.ifError(err); @@ -107,13 +107,13 @@ describe('Messaging Library', function () { }); it('should send a message to a room', function (done) { - socketModules.chats.send({uid: fooUid}, {roomId: roomId, message: 'first chat message'}, function (err, messageData) { + socketModules.chats.send({ uid: fooUid }, { roomId: roomId, message: 'first chat message' }, function (err, messageData) { assert.ifError(err); assert(messageData); assert.equal(messageData.content, 'first chat message'); assert(messageData.fromUser); assert(messageData.roomId, roomId); - socketModules.chats.getRaw({uid: fooUid}, {roomId: roomId, mid: messageData.mid}, function (err, raw) { + socketModules.chats.getRaw({ uid: fooUid }, { roomId: roomId, mid: messageData.mid }, function (err, raw) { assert.ifError(err); assert.equal(raw, 'first chat message'); done(); @@ -126,7 +126,7 @@ describe('Messaging Library', function () { db.sortedSetAdd('users:online', Date.now() - 350000, herpUid, function (err) { assert.ifError(err); - socketModules.chats.send({uid: fooUid}, {roomId: roomId, message: 'second chat message'}, function (err) { + socketModules.chats.send({ uid: fooUid }, { roomId: roomId, message: 'second chat message' }, function (err) { assert.ifError(err); setTimeout(function () { User.notifications.get(herpUid, function (err, data) { @@ -144,10 +144,10 @@ describe('Messaging Library', function () { }); it('should get messages from room', function (done) { - socketModules.chats.getMessages({uid: fooUid}, { + socketModules.chats.getMessages({ uid: fooUid }, { uid: fooUid, roomId: roomId, - start: 0 + start: 0, }, function (err, messages) { assert.ifError(err); assert(Array.isArray(messages)); @@ -158,21 +158,21 @@ describe('Messaging Library', function () { }); it('should mark room read', function (done) { - socketModules.chats.markRead({uid: fooUid}, roomId, function (err) { + socketModules.chats.markRead({ uid: fooUid }, roomId, function (err) { assert.ifError(err); done(); }); }); it('should mark all rooms read', function (done) { - socketModules.chats.markAllRead({uid: fooUid}, {}, function (err) { + socketModules.chats.markAllRead({ uid: fooUid }, {}, function (err) { assert.ifError(err); done(); }); }); it('should rename room', function (done) { - socketModules.chats.renameRoom({uid: fooUid}, {roomId: roomId, newName: 'new room name'}, function (err) { + socketModules.chats.renameRoom({ uid: fooUid }, { roomId: roomId, newName: 'new room name' }, function (err) { assert.ifError(err); done(); @@ -180,7 +180,7 @@ describe('Messaging Library', function () { }); it('should load chat room', function (done) { - socketModules.chats.loadRoom({uid: fooUid}, {roomId: roomId}, function (err, data) { + socketModules.chats.loadRoom({ uid: fooUid }, { roomId: roomId }, function (err, data) { assert.ifError(err); assert(data); assert.equal(data.roomName, 'new room name'); @@ -193,7 +193,7 @@ describe('Messaging Library', function () { var socketModules = require('../src/socket.io/modules'); var mid; before(function (done) { - socketModules.chats.send({uid: fooUid}, {roomId: roomId, message: 'first chat message'}, function (err, messageData) { + socketModules.chats.send({ uid: fooUid }, { roomId: roomId, message: 'first chat message' }, function (err, messageData) { assert.ifError(err); mid = messageData.mid; done(); @@ -201,9 +201,9 @@ describe('Messaging Library', function () { }); it('should edit message', function (done) { - socketModules.chats.edit({uid: fooUid}, {mid: mid, roomId: roomId, message: 'message edited'}, function (err) { + socketModules.chats.edit({ uid: fooUid }, { mid: mid, roomId: roomId, message: 'message edited' }, function (err) { assert.ifError(err); - socketModules.chats.getRaw({uid: fooUid}, {roomId: roomId, mid: mid}, function (err, raw) { + socketModules.chats.getRaw({ uid: fooUid }, { roomId: roomId, mid: mid }, function (err, raw) { assert.ifError(err); assert.equal(raw, 'message edited'); done(); @@ -212,7 +212,7 @@ describe('Messaging Library', function () { }); it('should delete message', function (done) { - socketModules.chats.delete({uid: fooUid}, {messageId: mid, roomId: roomId}, function (err) { + socketModules.chats.delete({ uid: fooUid }, { messageId: mid, roomId: roomId }, function (err) { assert.ifError(err); db.exists('message:' + mid, function (err, exists) { assert.ifError(err); @@ -249,7 +249,6 @@ describe('Messaging Library', function () { done(); }); }); - }); describe('logged in chat controller', function () { @@ -263,7 +262,7 @@ describe('Messaging Library', function () { }); it('should return chats page data', function (done) { - request(nconf.get('url') + '/api/user/herp/chats', {json: true, jar: jar}, function (err, response, body) { + request(nconf.get('url') + '/api/user/herp/chats', { json: true, jar: jar }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 200); assert(Array.isArray(body.rooms)); @@ -274,7 +273,7 @@ describe('Messaging Library', function () { }); it('should return room data', function (done) { - request(nconf.get('url') + '/api/user/herp/chats/' + roomId, {json: true, jar: jar}, function (err, response, body) { + request(nconf.get('url') + '/api/user/herp/chats/' + roomId, { json: true, jar: jar }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 200); assert.equal(body.roomId, roomId); @@ -284,7 +283,7 @@ describe('Messaging Library', function () { }); it('should redirect to chats page', function (done) { - request(nconf.get('url') + '/api/chats', {jar: jar}, function (err, response, body) { + request(nconf.get('url') + '/api/chats', { jar: jar }, function (err, response, body) { assert.ifError(err); assert.equal(body, '"/user/herp/chats"'); assert.equal(response.statusCode, 308); @@ -295,7 +294,7 @@ describe('Messaging Library', function () { it('should return 404 if user is not in room', function (done) { helpers.loginUser('baz', 'quuxquux', function (err, jar) { assert.ifError(err); - request(nconf.get('url') + '/api/user/baz/chats/' + roomId, {json: true, jar: jar}, function (err, response, body) { + request(nconf.get('url') + '/api/user/baz/chats/' + roomId, { json: true, jar: jar }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 404); done(); diff --git a/test/meta.js b/test/meta.js index 6f27de6a8e..4544570b42 100644 --- a/test/meta.js +++ b/test/meta.js @@ -19,7 +19,7 @@ describe('meta', function () { async.series([ async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user - async.apply(User.create, { username: 'herp', password: 'derpderp' }) // regular user + async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user ], function (err, uids) { if (err) { return done(err); @@ -36,7 +36,7 @@ describe('meta', function () { describe('settings', function () { var socketAdmin = require('../src/socket.io/admin'); it('it should set setting', function (done) { - socketAdmin.settings.set({uid: fooUid}, {hash: 'some:hash', values: {foo: '1', derp: 'value'}}, function (err) { + socketAdmin.settings.set({ uid: fooUid }, { hash: 'some:hash', values: { foo: '1', derp: 'value' } }, function (err) { assert.ifError(err); db.getObject('settings:some:hash', function (err, data) { assert.ifError(err); @@ -48,7 +48,7 @@ describe('meta', function () { }); it('it should get setting', function (done) { - socketAdmin.settings.get({uid: fooUid}, {hash: 'some:hash'}, function (err, data) { + socketAdmin.settings.get({ uid: fooUid }, { hash: 'some:hash' }, function (err, data) { assert.ifError(err); assert.equal(data.foo, '1'); assert.equal(data.derp, 'value'); @@ -57,7 +57,7 @@ describe('meta', function () { }); it('should not set setting if not empty', function (done) { - meta.settings.setOnEmpty('some:hash', {foo: 2}, function (err) { + meta.settings.setOnEmpty('some:hash', { foo: 2 }, function (err) { assert.ifError(err); db.getObject('settings:some:hash', function (err, data) { assert.ifError(err); @@ -69,7 +69,7 @@ describe('meta', function () { }); it('should set setting if empty', function (done) { - meta.settings.setOnEmpty('some:hash', {empty: '2'}, function (err) { + meta.settings.setOnEmpty('some:hash', { empty: '2' }, function (err) { assert.ifError(err); db.getObject('settings:some:hash', function (err, data) { assert.ifError(err); @@ -91,14 +91,13 @@ describe('meta', function () { }); }); }); - }); describe('config', function () { var socketAdmin = require('../src/socket.io/admin'); before(function (done) { - db.setObject('config', {minimumTagLength: 3, maximumTagLength: 15}, done); + db.setObject('config', { minimumTagLength: 3, maximumTagLength: 15 }, done); }); it('should get config fields', function (done) { @@ -118,12 +117,23 @@ describe('meta', function () { }); it('should fail if data is invalid', function (done) { - socketAdmin.config.set({uid: fooUid}, null, function (err) { + socketAdmin.config.set({ uid: fooUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); + it('should set single config value', function (done) { + socketAdmin.config.set({ uid: fooUid }, { key: 'someKey', value: 'someValue' }, function (err) { + assert.ifError(err); + meta.configs.getFields(['someKey'], function (err, data) { + assert.ifError(err); + assert.equal(data.someKey, 'someValue'); + done(); + }); + }); + }); + it('should set config value', function (done) { meta.configs.set('someField', 'someValue', function (err) { assert.ifError(err); @@ -136,17 +146,17 @@ describe('meta', function () { }); it('should fail if data is invalid', function (done) { - socketAdmin.config.setMultiple({uid: fooUid}, null, function (err) { + socketAdmin.config.setMultiple({ uid: fooUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); - it('should set multiple values', function (done ) { - socketAdmin.config.setMultiple({uid: fooUid}, { + it('should set multiple values', function (done) { + socketAdmin.config.setMultiple({ uid: fooUid }, { someField1: 'someValue1', someField2: 'someValue2', - customCSS: '.derp{color:#00ff00;}' + customCSS: '.derp{color:#00ff00;}', }, function (err) { assert.ifError(err); meta.configs.getFields(['someField1', 'someField2'], function (err, data) { @@ -159,7 +169,7 @@ describe('meta', function () { }); it('should not set config if not empty', function (done) { - meta.configs.setOnEmpty({someField1: 'foo'}, function (err) { + meta.configs.setOnEmpty({ someField1: 'foo' }, function (err) { assert.ifError(err); db.getObjectField('config', 'someField1', function (err, value) { assert.ifError(err); @@ -170,7 +180,7 @@ describe('meta', function () { }); it('should remove config field', function (done) { - socketAdmin.config.remove({uid: fooUid}, 'someField1', function (err) { + socketAdmin.config.remove({ uid: fooUid }, 'someField1', function (err) { assert.ifError(err); db.isObjectField('config', 'someField1', function (err, isObjectField) { assert.ifError(err); @@ -179,11 +189,9 @@ describe('meta', function () { }); }); }); - }); - after(function (done) { db.emptydb(done); }); diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index db28b8025c..412a255dc6 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -1,15 +1,14 @@ +'use strict'; + /** * Database Mock - wrapper for database.js, makes system use separate test db, instead of production * ATTENTION: testing db is flushed before every use! */ (function (module) { - 'use strict'; - /*global require, before, __dirname*/ - var async = require('async'); var winston = require('winston'); - var path = require('path'); + var path = require('path'); var nconf = require('nconf'); var url = require('url'); var errorText; @@ -17,11 +16,11 @@ nconf.file({ file: path.join(__dirname, '../../config.json') }); nconf.defaults({ - base_dir: path.join(__dirname,'../..'), + base_dir: path.join(__dirname, '../..'), themes_path: path.join(__dirname, '../../node_modules'), upload_path: 'public/uploads', views_dir: path.join(__dirname, '../../build/public/templates'), - relative_path: '' + relative_path: '', }); if (!nconf.get('isCluster')) { @@ -39,27 +38,27 @@ '\n===========================================================\n' + 'Please, add parameters for test database in config.json\n' + 'For example (redis):\n' + - '"test_database": {' + '\n' + - ' "host": "127.0.0.1",' + '\n' + - ' "port": "6379",' + '\n' + - ' "password": "",' + '\n' + - ' "database": "1"' + '\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1",\n' + + ' "port": "6379",\n' + + ' "password": "",\n' + + ' "database": "1"\n' + '}\n' + ' or (mongo):\n' + - '"test_database": {' + '\n' + - ' "host": "127.0.0.1",' + '\n' + - ' "port": "27017",' + '\n' + - ' "password": "",' + '\n' + - ' "database": "1"' + '\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1",\n' + + ' "port": "27017",\n' + + ' "password": "",\n' + + ' "database": "1\n' + + '}\n' + + ' or (mongo) in a replicaset\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1,127.0.0.1,127.0.0.1",\n' + + ' "port": "27017,27018,27019",\n' + + ' "username": "",\n' + + ' "password": "",\n' + + ' "database": "nodebb_test"\n' + '}\n' + - ' or (mongo) in a replicaset' + '\n' + - '"test_database": {' + '\n' + - ' "host": "127.0.0.1,127.0.0.1,127.0.0.1",' + '\n' + - ' "port": "27017,27018,27019",' + '\n' + - ' "username": "",' + '\n' + - ' "password": "",' + '\n' + - ' "database": "nodebb_test"' + '\n' + - '}\n' + '===========================================================' ); winston.error(errorText); @@ -116,7 +115,7 @@ function (next) { meta.themes.set({ type: 'local', - id: 'nodebb-theme-persona' + id: 'nodebb-theme-persona', }, next); }, function (next) { @@ -151,7 +150,7 @@ require('../../src/user').startJobs(); webserver.listen(next); - } + }, ], done); }); @@ -167,7 +166,7 @@ winston.info('Enabling default plugins\n'); var defaultEnabled = [ - 'nodebb-plugin-dbsearch' + 'nodebb-plugin-dbsearch', ]; winston.info('[install/enableDefaultPlugins] activating default plugins', defaultEnabled); @@ -176,5 +175,4 @@ } module.exports = db; - }(module)); diff --git a/test/mocks/newXhr.js b/test/mocks/newXhr.js index a523d77617..5631b68cae 100644 --- a/test/mocks/newXhr.js +++ b/test/mocks/newXhr.js @@ -1,3 +1,5 @@ +'use strict'; + // see https://gist.github.com/jfromaniello/4087861#gistcomment-1447029 // XMLHttpRequest to override. @@ -35,7 +37,7 @@ var callbacks = {}; var newXhr = function () { stdXhr.apply(this, arguments); for (var method in callbacks) { - if (typeof callbacks[method] == "function") { + if (typeof callbacks[method] === 'function') { callbacks[method].apply(this, arguments); } } @@ -45,4 +47,4 @@ newXhr.XMLHttpRequest = newXhr; cachedXhr.exports = newXhr; module.exports = newXhr; -module.exports.callbacks = callbacks; \ No newline at end of file +module.exports.callbacks = callbacks; diff --git a/test/notifications.js b/test/notifications.js index c36c8008e4..f21d46cf32 100644 --- a/test/notifications.js +++ b/test/notifications.js @@ -1,5 +1,4 @@ 'use strict'; -/*global require, after, before*/ var assert = require('assert'); @@ -15,7 +14,7 @@ describe('Notifications', function () { var notification; before(function (done) { - user.create({username: 'poster'}, function (err, _uid) { + user.create({ username: 'poster' }, function (err, _uid) { if (err) { return done(err); } @@ -29,7 +28,7 @@ describe('Notifications', function () { notifications.create({ bodyShort: 'bodyShort', nid: 'notification_id', - path: '/notification/path' + path: '/notification/path', }, function (err, _notification) { notification = _notification; assert.ifError(err); @@ -96,7 +95,7 @@ describe('Notifications', function () { }); it('should mark a notification read', function (done) { - socketNotifications.markRead({uid: uid}, notification.nid, function (err) { + socketNotifications.markRead({ uid: uid }, notification.nid, function (err) { assert.ifError(err); db.isSortedSetMember('uid:' + uid + ':notifications:unread', notification.nid, function (err, isMember) { assert.ifError(err); @@ -111,7 +110,7 @@ describe('Notifications', function () { }); it('should mark a notification unread', function (done) { - socketNotifications.markUnread({uid: uid}, notification.nid, function (err) { + socketNotifications.markUnread({ uid: uid }, notification.nid, function (err) { assert.ifError(err); db.isSortedSetMember('uid:' + uid + ':notifications:unread', notification.nid, function (err, isMember) { assert.ifError(err); @@ -119,7 +118,7 @@ describe('Notifications', function () { db.isSortedSetMember('uid:' + uid + ':notifications:read', notification.nid, function (err, isMember) { assert.ifError(err); assert.equal(isMember, false); - socketNotifications.getCount({uid: uid}, null, function (err, count) { + socketNotifications.getCount({ uid: uid }, null, function (err, count) { assert.ifError(err); assert.equal(count, 1); done(); @@ -130,7 +129,7 @@ describe('Notifications', function () { }); it('should mark all notifications read', function (done) { - socketNotifications.markAllRead({uid: uid}, null, function (err) { + socketNotifications.markAllRead({ uid: uid }, null, function (err) { assert.ifError(err); db.isSortedSetMember('uid:' + uid + ':notifications:unread', notification.nid, function (err, isMember) { assert.ifError(err); @@ -155,14 +154,14 @@ describe('Notifications', function () { async.waterfall([ function (next) { - user.create({username: 'watcher'}, next); + user.create({ username: 'watcher' }, next); }, function (_watcherUid, next) { watcherUid = _watcherUid; categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, function (category, next) { @@ -172,7 +171,7 @@ describe('Notifications', function () { uid: watcherUid, cid: cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }, next); }, function (topic, next) { @@ -184,7 +183,7 @@ describe('Notifications', function () { topics.reply({ uid: uid, content: 'This is the first reply.', - tid: tid + tid: tid, }, next); }, function (post, next) { @@ -193,7 +192,7 @@ describe('Notifications', function () { topics.reply({ uid: uid, content: 'This is the second reply.', - tid: tid + tid: tid, }, next); }, function (post, next) { @@ -207,7 +206,7 @@ describe('Notifications', function () { assert.equal(notifications.unread.length, 1, 'there should be 1 unread notification'); assert.equal('/post/' + pid, notifications.unread[0].path, 'the notification should link to the first unread post'); next(); - } + }, ], function (err) { assert.ifError(err); done(); @@ -215,7 +214,7 @@ describe('Notifications', function () { }); it('should get notification by nid', function (done) { - socketNotifications.get({uid: uid}, {nids: [notification.nid]}, function (err, data) { + socketNotifications.get({ uid: uid }, { nids: [notification.nid] }, function (err, data) { assert.ifError(err); assert.equal(data[0].bodyShort, 'bodyShort'); assert.equal(data[0].nid, 'notification_id'); @@ -225,7 +224,7 @@ describe('Notifications', function () { }); it('should get user\'s notifications', function (done) { - socketNotifications.get({uid: uid}, {}, function (err, data) { + socketNotifications.get({ uid: uid }, {}, function (err, data) { assert.ifError(err); assert.equal(data.unread.length, 0); assert.equal(data.read[0].nid, 'notification_id'); @@ -234,21 +233,21 @@ describe('Notifications', function () { }); it('should error with invalid data', function (done) { - socketNotifications.loadMore({uid: uid}, {after: 'test'}, function (err) { + socketNotifications.loadMore({ uid: uid }, { after: 'test' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if not logged in', function (done) { - socketNotifications.loadMore({uid: 0}, {after: 10}, function (err) { + socketNotifications.loadMore({ uid: 0 }, { after: 10 }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should load more notifications', function (done) { - socketNotifications.loadMore({uid: uid}, {after: 0}, function (err, data) { + socketNotifications.loadMore({ uid: uid }, { after: 0 }, function (err, data) { assert.ifError(err); assert.equal(data.notifications[0].bodyShort, 'bodyShort'); assert.equal(data.notifications[0].nid, 'notification_id'); @@ -259,16 +258,16 @@ describe('Notifications', function () { it('should error if not logged in', function (done) { - socketNotifications.deleteAll({uid: 0}, null, function (err) { + socketNotifications.deleteAll({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should delete all user notifications', function (done) { - socketNotifications.deleteAll({uid: uid}, null, function (err) { + socketNotifications.deleteAll({ uid: uid }, null, function (err) { assert.ifError(err); - socketNotifications.get({uid: uid}, {}, function (err, data) { + socketNotifications.get({ uid: uid }, {}, function (err, data) { assert.ifError(err); assert.equal(data.unread.length, 0); assert.equal(data.read.length, 0); diff --git a/test/pagination.js b/test/pagination.js index b3c50e57f2..30f79a718e 100644 --- a/test/pagination.js +++ b/test/pagination.js @@ -1,11 +1,10 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var pagination = require('../src/pagination'); describe('Pagination', function () { - it('should create empty pagination for 1 page', function (done) { var data = pagination.create(1, 1); assert.equal(data.pages.length, 0); @@ -28,7 +27,7 @@ describe('Pagination', function () { }); it('should create pagination for 3 pages with query params', function (done) { - var data = pagination.create(1, 3, {key: 'value'}); + var data = pagination.create(1, 3, { key: 'value' }); assert.equal(data.pages.length, 3); assert.equal(data.rel.length, 1); assert.equal(data.pageCount, 3); diff --git a/test/plugins.js b/test/plugins.js index 09537d8990..97a9c1908b 100644 --- a/test/plugins.js +++ b/test/plugins.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var path = require('path'); @@ -10,7 +10,6 @@ var db = require('./mocks/databasemock'); var plugins = require('../src/plugins'); describe('Plugins', function () { - it('should load plugin data', function (done) { var pluginId = 'nodebb-plugin-markdown'; plugins.loadPlugin(path.join(nconf.get('base_dir'), 'node_modules/' + pluginId), function (err) { @@ -30,7 +29,7 @@ describe('Plugins', function () { it('should register and fire a filter hook', function (done) { function filterMethod1(data, callback) { - data.foo ++; + data.foo += 1; callback(null, data); } function filterMethod2(data, callback) { @@ -38,15 +37,14 @@ describe('Plugins', function () { callback(null, data); } - plugins.registerHook('test-plugin', {hook: 'filter:test.hook', method: filterMethod1}); - plugins.registerHook('test-plugin', {hook: 'filter:test.hook', method: filterMethod2}); + plugins.registerHook('test-plugin', { hook: 'filter:test.hook', method: filterMethod1 }); + plugins.registerHook('test-plugin', { hook: 'filter:test.hook', method: filterMethod2 }); - plugins.fireHook('filter:test.hook', {foo: 1}, function (err, data) { + plugins.fireHook('filter:test.hook', { foo: 1 }, function (err, data) { assert.ifError(err); assert.equal(data.foo, 7); done(); }); - }); it('should register and fire an action hook', function (done) { @@ -55,8 +53,8 @@ describe('Plugins', function () { done(); } - plugins.registerHook('test-plugin', {hook: 'action:test.hook', method: actionMethod}); - plugins.fireHook('action:test.hook', {bar: 'test'}); + plugins.registerHook('test-plugin', { hook: 'action:test.hook', method: actionMethod }); + plugins.fireHook('action:test.hook', { bar: 'test' }); }); it('should register and fire a static hook', function (done) { @@ -65,8 +63,8 @@ describe('Plugins', function () { callback(); } - plugins.registerHook('test-plugin', {hook: 'static:test.hook', method: actionMethod}); - plugins.fireHook('static:test.hook', {bar: 'test'}, function (err) { + plugins.registerHook('test-plugin', { hook: 'static:test.hook', method: actionMethod }); + plugins.fireHook('static:test.hook', { bar: 'test' }, function (err) { assert.ifError(err); done(); }); @@ -179,8 +177,5 @@ describe('Plugins', function () { }); }); }); - - - }); diff --git a/test/posts.js b/test/posts.js index 42ebbde345..49a4783872 100644 --- a/test/posts.js +++ b/test/posts.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require, before, after*/ + var assert = require('assert'); var async = require('async'); @@ -11,6 +11,7 @@ var categories = require('../src/categories'); var privileges = require('../src/privileges'); var user = require('../src/user'); var groups = require('../src/groups'); +var socketPosts = require('../src/socket.io/posts'); describe('Post\'s', function () { var voterUid; @@ -24,20 +25,20 @@ describe('Post\'s', function () { groups.resetCache(); async.series({ voterUid: function (next) { - user.create({username: 'upvoter'}, next); + user.create({ username: 'upvoter' }, next); }, voteeUid: function (next) { - user.create({username: 'upvotee'}, next); + user.create({ username: 'upvotee' }, next); }, globalModUid: function (next) { - user.create({username: 'globalmod'}, next); + user.create({ username: 'globalmod' }, next); }, category: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); - } + }, }, function (err, results) { if (err) { return done(err); @@ -52,7 +53,7 @@ describe('Post\'s', function () { uid: results.voteeUid, cid: results.category.cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }, function (err, data) { if (err) { return done(err); @@ -66,9 +67,8 @@ describe('Post\'s', function () { }); describe('voting', function () { - var socketPosts = require('../src/socket.io/posts'); it('should upvote a post', function (done) { - socketPosts.upvote({uid: voterUid}, {pid: postData.pid, room_id: 'topic_1'}, function (err, result) { + socketPosts.upvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err, result) { assert.ifError(err); assert.equal(result.post.upvotes, 1); assert.equal(result.post.downvotes, 0); @@ -84,7 +84,7 @@ describe('Post\'s', function () { }); it('should get voters', function (done) { - socketPosts.getVoters({uid: globalModUid}, {pid: postData.pid, cid: cid}, function (err, data) { + socketPosts.getVoters({ uid: globalModUid }, { pid: postData.pid, cid: cid }, function (err, data) { assert.ifError(err); assert.equal(data.upvoteCount, 1); assert.equal(data.downvoteCount, 0); @@ -95,7 +95,7 @@ describe('Post\'s', function () { }); it('should get upvoters', function (done) { - socketPosts.getUpvoters({uid: globalModUid}, [postData.pid], function (err, data) { + socketPosts.getUpvoters({ uid: globalModUid }, [postData.pid], function (err, data) { assert.ifError(err); assert.equal(data[0].otherCount, 0); assert.equal(data[0].usernames, 'upvoter'); @@ -104,7 +104,7 @@ describe('Post\'s', function () { }); it('should unvote a post', function (done) { - socketPosts.unvote({uid: voterUid}, {pid: postData.pid, room_id: 'topic_1'}, function (err, result) { + socketPosts.unvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err, result) { assert.ifError(err); assert.equal(result.post.upvotes, 0); assert.equal(result.post.downvotes, 0); @@ -120,7 +120,7 @@ describe('Post\'s', function () { }); it('should downvote a post', function (done) { - socketPosts.downvote({uid: voterUid}, {pid: postData.pid, room_id: 'topic_1'}, function (err, result) { + socketPosts.downvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err, result) { assert.ifError(err); assert.equal(result.post.upvotes, 0); assert.equal(result.post.downvotes, 1); @@ -138,7 +138,7 @@ describe('Post\'s', function () { describe('bookmarking', function () { it('should bookmark a post', function (done) { - posts.bookmark(postData.pid, voterUid, function (err, data) { + socketPosts.bookmark({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_' + postData.tid }, function (err, data) { assert.ifError(err); assert.equal(data.isBookmarked, true); posts.hasBookmarked(postData.pid, voterUid, function (err, hasBookmarked) { @@ -150,7 +150,7 @@ describe('Post\'s', function () { }); it('should unbookmark a post', function (done) { - posts.unbookmark(postData.pid, voterUid, function (err, data) { + socketPosts.unbookmark({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_' + postData.tid }, function (err, data) { assert.ifError(err); assert.equal(data.isBookmarked, false); posts.hasBookmarked([postData.pid], voterUid, function (err, hasBookmarked) { @@ -163,17 +163,15 @@ describe('Post\'s', function () { }); describe('post tools', function () { - var socketPosts = require('../src/socket.io/posts'); - it('should error if data is invalid', function (done) { - socketPosts.loadPostTools({uid: globalModUid}, null, function (err) { + socketPosts.loadPostTools({ uid: globalModUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load post tools', function (done) { - socketPosts.loadPostTools({uid: globalModUid}, {pid: postData.pid, cid: cid}, function (err, data) { + socketPosts.loadPostTools({ uid: globalModUid }, { pid: postData.pid, cid: cid }, function (err, data) { assert.ifError(err); assert(data.posts.display_edit_tools); assert(data.posts.display_delete_tools); @@ -190,14 +188,14 @@ describe('Post\'s', function () { uid: voterUid, cid: cid, title: 'topic to delete/restore/purge', - content: 'A post to delete/restore/purge' + content: 'A post to delete/restore/purge', }, function (err, topicPostData) { assert.ifError(err); topics.reply({ uid: voterUid, tid: topicPostData.topicData.tid, timestamp: Date.now(), - content: 'A post to delete/restore and purge' + content: 'A post to delete/restore and purge', }, function (err, replyData) { assert.ifError(err); callback(topicPostData, replyData); @@ -209,7 +207,6 @@ describe('Post\'s', function () { var mainPid; var replyPid; - var socketPosts = require('../src/socket.io/posts'); before(function (done) { createTopicWithReply(function (topicPostData, replyData) { tid = topicPostData.topicData.tid; @@ -220,14 +217,14 @@ describe('Post\'s', function () { }); it('should error with invalid data', function (done) { - socketPosts.delete({uid: voterUid}, null, function (err) { + socketPosts.delete({ uid: voterUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should delete a post', function (done) { - socketPosts.delete({uid: voterUid}, {pid: replyPid, tid: tid}, function (err) { + socketPosts.delete({ uid: voterUid }, { pid: replyPid, tid: tid }, function (err) { assert.ifError(err); posts.getPostField(replyPid, 'deleted', function (err, isDeleted) { assert.ifError(err); @@ -238,7 +235,7 @@ describe('Post\'s', function () { }); it('should restore a post', function (done) { - socketPosts.restore({uid: voterUid}, {pid: replyPid, tid: tid}, function (err) { + socketPosts.restore({ uid: voterUid }, { pid: replyPid, tid: tid }, function (err) { assert.ifError(err); posts.getPostField(replyPid, 'deleted', function (err, isDeleted) { assert.ifError(err); @@ -249,7 +246,7 @@ describe('Post\'s', function () { }); it('should delete posts', function (done) { - socketPosts.deletePosts({uid: globalModUid}, {pids: [replyPid, mainPid], tid: tid}, function (err) { + socketPosts.deletePosts({ uid: globalModUid }, { pids: [replyPid, mainPid], tid: tid }, function (err) { assert.ifError(err); posts.getPostField(replyPid, 'deleted', function (err, deleted) { assert.ifError(err); @@ -264,9 +261,9 @@ describe('Post\'s', function () { }); it('should delete topic if last main post is deleted', function (done) { - topics.post({uid: voterUid, cid: cid, title: 'test topic', content: 'test topic'}, function (err, data) { + topics.post({ uid: voterUid, cid: cid, title: 'test topic', content: 'test topic' }, function (err, data) { assert.ifError(err); - socketPosts.deletePosts({uid: globalModUid}, {pids: [data.postData.pid], tid: data.topicData.tid}, function (err) { + socketPosts.deletePosts({ uid: globalModUid }, { pids: [data.postData.pid], tid: data.topicData.tid }, function (err) { assert.ifError(err); topics.getTopicField(data.topicData.tid, 'deleted', function (err, deleted) { assert.ifError(err); @@ -278,9 +275,8 @@ describe('Post\'s', function () { }); it('should purge posts and delete topic', function (done) { - createTopicWithReply(function (topicPostData, replyData) { - socketPosts.purgePosts({uid: voterUid}, {pids: [replyData.pid, topicPostData.postData.pid], tid: topicPostData.topicData.tid}, function (err) { + socketPosts.purgePosts({ uid: voterUid }, { pids: [replyData.pid, topicPostData.postData.pid], tid: topicPostData.topicData.tid }, function (err) { assert.ifError(err); posts.exists('post:' + replyData.pid, function (err, exists) { assert.ifError(err); @@ -300,14 +296,13 @@ describe('Post\'s', function () { var pid; var replyPid; var tid; - var socketPosts = require('../src/socket.io/posts'); var meta = require('../src/meta'); before(function (done) { topics.post({ uid: voterUid, cid: cid, title: 'topic to edit', - content: 'A post to edit' + content: 'A post to edit', }, function (err, data) { assert.ifError(err); pid = data.postData.pid; @@ -316,7 +311,7 @@ describe('Post\'s', function () { uid: voterUid, tid: tid, timestamp: Date.now(), - content: 'A reply to edit' + content: 'A reply to edit', }, function (err, data) { assert.ifError(err); replyPid = data.pid; @@ -326,21 +321,21 @@ describe('Post\'s', function () { }); it('should error if user is not logged in', function (done) { - socketPosts.edit({uid: 0}, {}, function (err) { + socketPosts.edit({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:not-logged-in]]'); done(); }); }); it('should error if data is invalid or missing', function (done) { - socketPosts.edit({uid: voterUid}, {}, function (err) { + socketPosts.edit({ uid: voterUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if title is too short', function (done) { - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited post content', title: 'a'}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited post content', title: 'a' }, function (err) { assert.equal(err.message, '[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'); done(); }); @@ -348,7 +343,7 @@ describe('Post\'s', function () { it('should error if title is too long', function (done) { var longTitle = new Array(parseInt(meta.config.maximumTitleLength, 10) + 2).join('a'); - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited post content', title: longTitle}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited post content', title: longTitle }, function (err) { assert.equal(err.message, '[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'); done(); }); @@ -357,7 +352,7 @@ describe('Post\'s', function () { it('should error with too few tags', function (done) { var oldValue = meta.config.minimumTagsPerTopic; meta.config.minimumTagsPerTopic = 1; - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited post content', tags: []}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited post content', tags: [] }, function (err) { assert.equal(err.message, '[[error:not-enough-tags, ' + meta.config.minimumTagsPerTopic + ']]'); meta.config.minimumTagsPerTopic = oldValue; done(); @@ -366,17 +361,17 @@ describe('Post\'s', function () { it('should error with too many tags', function (done) { var tags = []; - for(var i = 0; i < meta.config.maximumTagsPerTopic + 1; ++i) { + for (var i = 0; i < meta.config.maximumTagsPerTopic + 1; i += 1) { tags.push('tag' + i); } - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited post content', tags: tags}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited post content', tags: tags }, function (err) { assert.equal(err.message, '[[error:too-many-tags, ' + meta.config.maximumTagsPerTopic + ']]'); done(); }); }); it('should error if content is too short', function (done) { - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'e'}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'e' }, function (err) { assert.equal(err.message, '[[error:content-too-short, ' + meta.config.minimumPostLength + ']]'); done(); }); @@ -384,14 +379,14 @@ describe('Post\'s', function () { it('should error if content is too long', function (done) { var longContent = new Array(parseInt(meta.config.maximumPostLength, 10) + 2).join('a'); - socketPosts.edit({uid: voterUid}, {pid: pid, content: longContent}, function (err) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: longContent }, function (err) { assert.equal(err.message, '[[error:content-too-long, ' + meta.config.maximumPostLength + ']]'); done(); }); }); it('should edit post', function (done) { - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited post content', title: 'edited title', tags: ['edited']}, function (err, data) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited post content', title: 'edited title', tags: ['edited'] }, function (err, data) { assert.ifError(err); assert.equal(data.content, 'edited post content'); assert.equal(data.editor, voterUid); @@ -402,9 +397,9 @@ describe('Post\'s', function () { }); it('should edit a deleted post', function (done) { - socketPosts.delete({uid: voterUid}, {pid: pid, tid: tid}, function (err) { + socketPosts.delete({ uid: voterUid }, { pid: pid, tid: tid }, function (err) { assert.ifError(err); - socketPosts.edit({uid: voterUid}, {pid: pid, content: 'edited deleted content', title: 'edited deleted title', tags: ['deleted']}, function (err, data) { + socketPosts.edit({ uid: voterUid }, { pid: pid, content: 'edited deleted content', title: 'edited deleted title', tags: ['deleted'] }, function (err, data) { assert.ifError(err); assert.equal(data.content, 'edited deleted content'); assert.equal(data.editor, voterUid); @@ -416,7 +411,7 @@ describe('Post\'s', function () { }); it('should edit a reply post', function (done) { - socketPosts.edit({uid: voterUid}, {pid: replyPid, content: 'edited reply'}, function (err, data) { + socketPosts.edit({ uid: voterUid }, { pid: replyPid, content: 'edited reply' }, function (err, data) { assert.ifError(err); assert.equal(data.content, 'edited reply'); assert.equal(data.editor, voterUid); @@ -431,7 +426,6 @@ describe('Post\'s', function () { var replyPid; var tid; var moveTid; - var socketPosts = require('../src/socket.io/posts'); before(function (done) { async.waterfall([ @@ -440,7 +434,7 @@ describe('Post\'s', function () { uid: voterUid, cid: cid, title: 'topic 1', - content: 'some content' + content: 'some content', }, next); }, function (data, next) { @@ -449,7 +443,7 @@ describe('Post\'s', function () { uid: voterUid, cid: cid, title: 'topic 2', - content: 'some content' + content: 'some content', }, next); }, function (data, next) { @@ -458,32 +452,32 @@ describe('Post\'s', function () { uid: voterUid, tid: tid, timestamp: Date.now(), - content: 'A reply to move' + content: 'A reply to move', }, function (err, data) { assert.ifError(err); replyPid = data.pid; next(); }); - } + }, ], done); }); it('should error if uid is not logged in', function (done) { - socketPosts.movePost({uid: 0}, {}, function (err) { + socketPosts.movePost({ uid: 0 }, {}, function (err) { assert.equal(err.message, '[[error:not-logged-in]]'); done(); }); }); it('should error if data is invalid', function (done) { - socketPosts.movePost({uid: globalModUid}, {}, function (err) { + socketPosts.movePost({ uid: globalModUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if user does not have move privilege', function (done) { - socketPosts.movePost({uid: voterUid}, {pid: replyPid, tid: moveTid}, function (err) { + socketPosts.movePost({ uid: voterUid }, { pid: replyPid, tid: moveTid }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); @@ -491,7 +485,7 @@ describe('Post\'s', function () { it('should move a post', function (done) { - socketPosts.movePost({uid: globalModUid}, {pid: replyPid, tid: moveTid}, function (err) { + socketPosts.movePost({ uid: globalModUid }, { pid: replyPid, tid: moveTid }, function (err) { assert.ifError(err); posts.getPostField(replyPid, 'tid', function (err, tid) { assert.ifError(err); @@ -504,7 +498,6 @@ describe('Post\'s', function () { describe('flagging a post', function () { var meta = require('../src/meta'); - var socketPosts = require('../src/socket.io/posts'); it('should fail to flag a post due to low reputation', function (done) { meta.config['privileges:flag'] = 10; flagPost(function (err) { @@ -522,9 +515,9 @@ describe('Post\'s', function () { }); it('should return nothing without a uid or a reason', function (done) { - socketPosts.flag({uid: 0}, {pid: postData.pid, reason: 'reason'}, function (err) { + socketPosts.flag({ uid: 0 }, { pid: postData.pid, reason: 'reason' }, function (err) { assert.equal(err.message, '[[error:not-logged-in]]'); - socketPosts.flag({uid: voteeUid}, {}, function (err) { + socketPosts.flag({ uid: voteeUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -532,14 +525,14 @@ describe('Post\'s', function () { }); it('should return an error without an existing post', function (done) { - socketPosts.flag({uid: voteeUid}, {pid: 12312312, reason: 'reason'}, function (err) { + socketPosts.flag({ uid: voteeUid }, { pid: 12312312, reason: 'reason' }, function (err) { assert.equal(err.message, '[[error:no-post]]'); done(); }); }); it('should return an error if the flag already exists', function (done) { - socketPosts.flag({uid: voteeUid}, {pid: postData.pid, reason: 'reason'}, function (err) { + socketPosts.flag({ uid: voteeUid }, { pid: postData.pid, reason: 'reason' }, function (err) { assert.equal(err.message, '[[error:already-flagged]]'); done(); }); @@ -547,8 +540,7 @@ describe('Post\'s', function () { }); function flagPost(next) { - var socketPosts = require('../src/socket.io/posts'); - socketPosts.flag({uid: voteeUid}, {pid: postData.pid, reason: 'reason'}, next); + socketPosts.flag({ uid: voteeUid }, { pid: postData.pid, reason: 'reason' }, next); } describe('get flag data', function () { @@ -578,17 +570,15 @@ describe('Post\'s', function () { }); describe('updating a flag', function () { - var socketPosts = require('../src/socket.io/posts'); - it('should update a flag', function (done) { async.waterfall([ function (next) { - socketPosts.updateFlag({uid: globalModUid}, { + socketPosts.updateFlag({ uid: globalModUid }, { pid: postData.pid, data: [ - {name: 'assignee', value: `${globalModUid}`}, - {name: 'notes', value: 'notes'} - ] + { name: 'assignee', value: `${globalModUid}` }, + { name: 'notes', value: 'notes' }, + ], }, function (err) { assert.ifError(err); posts.getFlags('posts:flagged', cid, globalModUid, 0, -1, function (err, flagData) { @@ -599,19 +589,19 @@ describe('Post\'s', function () { assignee: flagData.posts[0].flagData.assignee, notes: flagData.posts[0].flagData.notes, state: flagData.posts[0].flagData.state, - labelClass: flagData.posts[0].flagData.labelClass + labelClass: flagData.posts[0].flagData.labelClass, }, { assignee: `${globalModUid}`, notes: 'notes', state: 'open', - labelClass: 'info' + labelClass: 'info', }); next(); }); }); }, function (next) { posts.updateFlagData(globalModUid, postData.pid, { - state: 'rejected' + state: 'rejected', }, function (err) { assert.ifError(err); posts.getFlags('posts:flagged', cid, globalModUid, 0, -1, function (err, flagData) { @@ -620,17 +610,17 @@ describe('Post\'s', function () { assert.equal(flagData.posts.length, 1); assert.deepEqual({ state: flagData.posts[0].flagData.state, - labelClass: flagData.posts[0].flagData.labelClass + labelClass: flagData.posts[0].flagData.labelClass, }, { state: 'rejected', - labelClass: 'danger' + labelClass: 'danger', }); next(); }); }); }, function (next) { posts.updateFlagData(globalModUid, postData.pid, { - state: 'wip' + state: 'wip', }, function (err) { assert.ifError(err); posts.getFlags('posts:flagged', cid, globalModUid, 0, -1, function (err, flagData) { @@ -639,17 +629,17 @@ describe('Post\'s', function () { assert.equal(flagData.posts.length, 1); assert.deepEqual({ state: flagData.posts[0].flagData.state, - labelClass: flagData.posts[0].flagData.labelClass + labelClass: flagData.posts[0].flagData.labelClass, }, { state: 'wip', - labelClass: 'warning' + labelClass: 'warning', }); next(); }); }); }, function (next) { posts.updateFlagData(globalModUid, postData.pid, { - state: 'resolved' + state: 'resolved', }, function (err) { assert.ifError(err); posts.getFlags('posts:flagged', cid, globalModUid, 0, -1, function (err, flagData) { @@ -658,24 +648,22 @@ describe('Post\'s', function () { assert.equal(flagData.posts.length, 1); assert.deepEqual({ state: flagData.posts[0].flagData.state, - labelClass: flagData.posts[0].flagData.labelClass + labelClass: flagData.posts[0].flagData.labelClass, }, { state: 'resolved', - labelClass: 'success' + labelClass: 'success', }); next(); }); }); - } + }, ], done); }); }); describe('dismissing a flag', function () { - var socketPosts = require('../src/socket.io/posts'); - it('should dismiss a flag', function (done) { - socketPosts.dismissFlag({uid: globalModUid}, postData.pid, function (err) { + socketPosts.dismissFlag({ uid: globalModUid }, postData.pid, function (err) { assert.ifError(err); posts.isFlaggedByUser(postData.pid, voteeUid, function (err, hasFlagged) { assert.ifError(err); @@ -703,7 +691,7 @@ describe('Post\'s', function () { }); it('should dismiss all flags', function (done) { - socketPosts.dismissAllFlags({uid: globalModUid}, {}, function (err) { + socketPosts.dismissAllFlags({ uid: globalModUid }, {}, function (err) { assert.ifError(err); posts.isFlaggedByUser(postData.pid, voteeUid, function (err, hasFlagged) { assert.ifError(err); @@ -742,7 +730,7 @@ describe('Post\'s', function () { uid: voterUid, tid: topicData.tid, timestamp: Date.now(), - content: 'some content' + content: 'some content', }, function (err) { assert.ifError(err); posts.getRecentPosterUids(0, 1, function (err, uids) { @@ -755,15 +743,58 @@ describe('Post\'s', function () { }); }); - describe('socket methods', function () { + describe('parse', function () { + it('should store post content in cache', function (done) { + var oldValue = global.env; + global.env = 'production'; + var postData = { + pid: 9999, + content: 'some post content', + }; + posts.parsePost(postData, function (err) { + assert.ifError(err); + posts.parsePost(postData, function (err) { + assert.ifError(err); + global.env = oldValue; + done(); + }); + }); + }); + it('should parse signature and remove links and images', function (done) { + var meta = require('../src/meta'); + meta.config['signatures:disableLinks'] = 1; + meta.config['signatures:disableImages'] = 1; + var userData = { + signature: 'test derp', + }; + + posts.parseSignature(userData, 1, function (err, data) { + assert.ifError(err); + assert.equal(data.userData.signature, 'test derp'); + meta.config['signatures:disableLinks'] = 0; + meta.config['signatures:disableImages'] = 0; + done(); + }); + }); + + it('should turn relative links in post body to absolute urls', function (done) { + var nconf = require('nconf'); + var content = 'test youtube'; + var parsedContent = posts.relativeToAbsolute(content); + assert.equal(parsedContent, 'test youtube'); + done(); + }); + }); + + describe('socket methods', function () { var pid; before(function (done) { topics.reply({ uid: voterUid, tid: topicData.tid, timestamp: Date.now(), - content: 'raw content' + content: 'raw content', }, function (err, postData) { assert.ifError(err); pid = postData.pid; @@ -771,23 +802,22 @@ describe('Post\'s', function () { }); }); - var socketPosts = require('../src/socket.io/posts'); it('should error with invalid data', function (done) { - socketPosts.reply({uid: 0}, null, function (err) { + socketPosts.reply({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error with invalid tid', function (done) { - socketPosts.reply({uid: 0}, {tid: 0, content: 'derp'}, function (err) { + socketPosts.reply({ uid: 0 }, { tid: 0, content: 'derp' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should fail to get raw post because of privilege', function (done) { - socketPosts.getRawPost({uid: 0}, pid, function (err) { + socketPosts.getRawPost({ uid: 0 }, pid, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); @@ -796,7 +826,7 @@ describe('Post\'s', function () { it('should fail to get raw post because post is deleted', function (done) { posts.setPostField(pid, 'deleted', 1, function (err) { assert.ifError(err); - socketPosts.getRawPost({uid: voterUid}, pid, function (err) { + socketPosts.getRawPost({ uid: voterUid }, pid, function (err) { assert.equal(err.message, '[[error:no-post]]'); done(); }); @@ -806,7 +836,7 @@ describe('Post\'s', function () { it('should get raw post content', function (done) { posts.setPostField(pid, 'deleted', 0, function (err) { assert.ifError(err); - socketPosts.getRawPost({uid: voterUid}, pid, function (err, postContent) { + socketPosts.getRawPost({ uid: voterUid }, pid, function (err, postContent) { assert.ifError(err); assert.equal(postContent, 'raw content'); done(); @@ -815,7 +845,7 @@ describe('Post\'s', function () { }); it('should get post', function (done) { - socketPosts.getPost({uid: voterUid}, pid, function (err, postData) { + socketPosts.getPost({ uid: voterUid }, pid, function (err, postData) { assert.ifError(err); assert(postData); done(); @@ -823,14 +853,14 @@ describe('Post\'s', function () { }); it('shold error with invalid data', function (done) { - socketPosts.loadMoreBookmarks({uid: voterUid}, {uid: voterUid, after: null}, function (err, postData) { + socketPosts.loadMoreBookmarks({ uid: voterUid }, { uid: voterUid, after: null }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more bookmarks', function (done) { - socketPosts.loadMoreBookmarks({uid: voterUid}, {uid: voterUid, after: 0}, function (err, data) { + socketPosts.loadMoreBookmarks({ uid: voterUid }, { uid: voterUid, after: 0 }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -838,7 +868,7 @@ describe('Post\'s', function () { }); it('should load more user posts', function (done) { - socketPosts.loadMoreUserPosts({uid: voterUid}, {uid: voterUid, after: 0}, function (err, data) { + socketPosts.loadMoreUserPosts({ uid: voterUid }, { uid: voterUid, after: 0 }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -846,7 +876,7 @@ describe('Post\'s', function () { }); it('should load more best posts', function (done) { - socketPosts.loadMoreBestPosts({uid: voterUid}, {uid: voterUid, after: 0}, function (err, data) { + socketPosts.loadMoreBestPosts({ uid: voterUid }, { uid: voterUid, after: 0 }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -854,7 +884,7 @@ describe('Post\'s', function () { }); it('should load more up voted posts', function (done) { - socketPosts.loadMoreUpVotedPosts({uid: voterUid}, {uid: voterUid, after: 0}, function (err, data) { + socketPosts.loadMoreUpVotedPosts({ uid: voterUid }, { uid: voterUid, after: 0 }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -862,7 +892,7 @@ describe('Post\'s', function () { }); it('should load more down voted posts', function (done) { - socketPosts.loadMoreDownVotedPosts({uid: voterUid}, {uid: voterUid, after: 0}, function (err, data) { + socketPosts.loadMoreDownVotedPosts({ uid: voterUid }, { uid: voterUid, after: 0 }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -870,7 +900,7 @@ describe('Post\'s', function () { }); it('should get post category', function (done) { - socketPosts.getCategory({uid: voterUid}, pid, function (err, postCid) { + socketPosts.getCategory({ uid: voterUid }, pid, function (err, postCid) { assert.ifError(err); assert.equal(cid, postCid); done(); @@ -878,14 +908,14 @@ describe('Post\'s', function () { }); it('should error with invalid data', function (done) { - socketPosts.getPidIndex({uid: voterUid}, null, function (err) { + socketPosts.getPidIndex({ uid: voterUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should get pid index', function (done) { - socketPosts.getPidIndex({uid: voterUid}, {pid: pid, tid: topicData.tid, topicPostSort: 'oldest-to-newest'}, function (err, index) { + socketPosts.getPidIndex({ uid: voterUid }, { pid: pid, tid: topicData.tid, topicPostSort: 'oldest-to-newest' }, function (err, index) { assert.ifError(err); assert.equal(index, 2); done(); diff --git a/test/rewards.js b/test/rewards.js index 5804465ef7..965df4770f 100644 --- a/test/rewards.js +++ b/test/rewards.js @@ -19,7 +19,7 @@ describe('rewards', function () { async.series([ async.apply(User.create, { username: 'foo', password: 'barbar' }), async.apply(User.create, { username: 'baz', password: 'quuxquux' }), - async.apply(User.create, { username: 'herp', password: 'derpderp' }) + async.apply(User.create, { username: 'herp', password: 'derpderp' }), ], function (err, uids) { if (err) { return done(err); @@ -31,11 +31,11 @@ describe('rewards', function () { async.series([ function (next) { - Groups.join('administrators', adminUid, done); + Groups.join('administrators', adminUid, next); }, function (next) { - Groups.join('rewardGroup', adminUid, done); - } + Groups.join('rewardGroup', adminUid, next); + }, ], done); }); }); @@ -53,11 +53,11 @@ describe('rewards', function () { rid: 'essentials/add-to-group', claimable: '1', id: '', - disabled: false - } + disabled: false, + }, ]; - socketAdmin.rewards.save({uid: adminUid}, data, function (err) { + socketAdmin.rewards.save({ uid: adminUid }, data, function (err) { assert.ifError(err); done(); }); @@ -72,14 +72,9 @@ describe('rewards', function () { done(); }); }); - }); - - - - after(function (done) { db.emptydb(done); }); diff --git a/test/search-admin.js b/test/search-admin.js index 216d26d35f..0d52c8db75 100644 --- a/test/search-admin.js +++ b/test/search-admin.js @@ -1,63 +1,63 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var search = require('../src/admin/search'); describe('admin search', function () { - describe('filterDirectories', function () { - it('should resolve all paths to relative paths', function (done) { - assert.deepEqual(search.filterDirectories([ - 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', - ]), [ - 'admin/gdhgfsdg/sggag', - ]); - done(); - }); - it('should exclude partials', function (done) { - assert.deepEqual(search.filterDirectories([ - 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', - 'dfahdfsgf/admin/partials/hgkfds/fdhsdfh.tpl', - ]), [ - 'admin/gdhgfsdg/sggag', - ]); - done(); - }); - it('should exclude files in the admin directory', function (done) { - assert.deepEqual(search.filterDirectories([ - 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', - 'dfdasg/admin/hjkdfsk.tpl', - ]), [ - 'admin/gdhgfsdg/sggag', - ]); - done(); - }); - }); + describe('filterDirectories', function () { + it('should resolve all paths to relative paths', function (done) { + assert.deepEqual(search.filterDirectories([ + 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', + ]), [ + 'admin/gdhgfsdg/sggag', + ]); + done(); + }); + it('should exclude partials', function (done) { + assert.deepEqual(search.filterDirectories([ + 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', + 'dfahdfsgf/admin/partials/hgkfds/fdhsdfh.tpl', + ]), [ + 'admin/gdhgfsdg/sggag', + ]); + done(); + }); + it('should exclude files in the admin directory', function (done) { + assert.deepEqual(search.filterDirectories([ + 'hfjksfd/fdsgagag/admin/gdhgfsdg/sggag.tpl', + 'dfdasg/admin/hjkdfsk.tpl', + ]), [ + 'admin/gdhgfsdg/sggag', + ]); + done(); + }); + }); - describe('sanitize', function () { - it('should strip out scripts', function (done) { - assert.equal( + describe('sanitize', function () { + it('should strip out scripts', function (done) { + assert.equal( search.sanitize('Pellentesque tristique senectus' + ' habitant morbi'), 'Pellentesque tristique senectus' + ' habitant morbi' ); - done(); - }); - it('should remove all tags', function (done) { - assert.equal( + done(); + }); + it('should remove all tags', function (done) { + assert.equal( search.sanitize('

    Pellentesque habitant morbi tristique senectus' + 'Aenean vitae est.Mauris eleifend leo.

    '), 'Pellentesque habitant morbi tristique senectus' + 'Aenean vitae est.Mauris eleifend leo.' ); - done(); - }); - }); + done(); + }); + }); - describe('simplify', function () { - it('should remove all mustaches', function (done) { - assert.equal( + describe('simplify', function () { + it('should remove all mustaches', function (done) { + assert.equal( search.simplify( 'Pellentesque tristique {{senectus}}habitant morbi' + 'liquam tincidunt {mauris.eu}risus' @@ -65,10 +65,10 @@ describe('admin search', function () { 'Pellentesque tristique habitant morbi' + 'liquam tincidunt risus' ); - done(); - }); - it('should collapse all whitespace', function (done) { - assert.equal( + done(); + }); + it('should collapse all whitespace', function (done) { + assert.equal( search.simplify( 'Pellentesque tristique habitant morbi' + ' \n\n liquam tincidunt mauris eu risus.' @@ -76,7 +76,7 @@ describe('admin search', function () { 'Pellentesque tristique habitant morbi' + '\nliquam tincidunt mauris eu risus.' ); - done(); - }); - }); -}); \ No newline at end of file + done(); + }); + }); +}); diff --git a/test/search.js b/test/search.js index 7c619d0b6c..a18f6b3b41 100644 --- a/test/search.js +++ b/test/search.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require, before, after*/ + var assert = require('assert'); var async = require('async'); @@ -29,23 +29,23 @@ describe('Search', function () { function (next) { async.series({ phoebe: function (next) { - user.create({username: 'phoebe'}, next); + user.create({ username: 'phoebe' }, next); }, ginger: function (next) { - user.create({username: 'ginger'}, next); + user.create({ username: 'ginger' }, next); }, category1: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, category2: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); - } + }, }, next); }, function (results, next) { @@ -61,7 +61,7 @@ describe('Search', function () { cid: cid1, title: 'nodebb mongodb bugs', content: 'avocado cucumber apple orange fox', - tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'jquery'] + tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'jquery'], }, next); }, function (results, next) { @@ -73,7 +73,7 @@ describe('Search', function () { cid: cid2, title: 'java mongodb redis', content: 'avocado cucumber carrot armadillo', - tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'javascript'] + tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'javascript'], }, next); }, function (results, next) { @@ -82,27 +82,26 @@ describe('Search', function () { topics.reply({ uid: phoebeUid, content: 'reply post apple', - tid: topic2Data.tid + tid: topic2Data.tid, }, next); }, function (_post3Data, next) { post3Data = _post3Data; setTimeout(next, 500); - } + }, ], next); - } + }, ], done); }); it('should search term in titles and posts', function (done) { - var meta = require('../src/meta'); meta.config.allowGuestSearching = 1; var qs = '/api/search?term=cucumber&in=titlesposts&categories[]=' + cid1 + '&by=phoebe&replies=1&repliesFilter=atleast&sortBy=timestamp&sortDirection=desc&showAs=posts'; request({ url: nconf.get('url') + qs, - json: true + json: true, }, function (err, response, body) { assert.ifError(err); assert(body); @@ -118,7 +117,7 @@ describe('Search', function () { it('should search for a user', function (done) { search.search({ query: 'gin', - searchIn: 'users' + searchIn: 'users', }, function (err, data) { assert.ifError(err); assert(data); @@ -133,7 +132,7 @@ describe('Search', function () { it('should search for a tag', function (done) { search.search({ query: 'plug', - searchIn: 'tags' + searchIn: 'tags', }, function (err, data) { assert.ifError(err); assert(data); @@ -148,7 +147,7 @@ describe('Search', function () { it('should fail if searchIn is wrong', function (done) { search.search({ query: 'plug', - searchIn: 'invalidfilter' + searchIn: 'invalidfilter', }, function (err) { assert.equal(err.message, '[[error:unknown-search-filter]]'); done(); @@ -159,7 +158,7 @@ describe('Search', function () { search.search({ query: 'mongodb', searchIn: 'titles', - hasTags: ['nodebb', 'javascript'] + hasTags: ['nodebb', 'javascript'], }, function (err, data) { assert.ifError(err); assert.equal(data.posts[0].tid, topic2Data.tid); diff --git a/test/socket.io.js b/test/socket.io.js index 4182522b2b..497f0ed922 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -2,9 +2,8 @@ // see https://gist.github.com/jfromaniello/4087861#gistcomment-1447029 -/* global process, require, before, after*/ -process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var assert = require('assert'); var async = require('async'); @@ -13,14 +12,15 @@ var request = require('request'); var cookies = request.jar(); var db = require('./mocks/databasemock'); -var myXhr = require('./mocks/newXhr'); var user = require('../src/user'); var groups = require('../src/groups'); var categories = require('../src/categories'); +var helpers = require('./helpers'); +var meta = require('../src/meta'); +var socketAdmin = require('../src/socket.io/admin'); describe('socket.io', function () { - var io; var cid; var tid; @@ -30,11 +30,11 @@ describe('socket.io', function () { before(function (done) { async.series([ async.apply(user.create, { username: 'admin', password: 'adminpwd' }), - async.apply(user.create, { username: 'regular', password: 'regularpwd', email: 'regular@test.com'}), + async.apply(user.create, { username: 'regular', password: 'regularpwd', email: 'regular@test.com' }), async.apply(categories.create, { name: 'Test Category', - description: 'Test category created by testing script' - }) + description: 'Test category created by testing script', + }), ], function (err, data) { if (err) { return done(err); @@ -52,7 +52,7 @@ describe('socket.io', function () { request.get({ url: nconf.get('url') + '/api/config', jar: cookies, - json: true + json: true, }, function (err, res, body) { assert.ifError(err); @@ -60,32 +60,18 @@ describe('socket.io', function () { jar: cookies, form: { username: 'admin', - password: 'adminpwd' + password: 'adminpwd', }, headers: { - 'x-csrf-token': body.csrf_token + 'x-csrf-token': body.csrf_token, }, - json: true - }, function (err, res, body) { + json: true, + }, function (err, res) { assert.ifError(err); - myXhr.callbacks.test2 = function () { - this.setDisableHeaderCheck(true); - var stdOpen = this.open; - this.open = function () { - stdOpen.apply(this, arguments); - this.setRequestHeader('Cookie', res.headers['set-cookie'][0].split(';')[0]); - this.setRequestHeader('Origin', nconf.get('url')); - }; - }; - - io = require('socket.io-client')(nconf.get('url'), {forceNew: true}); - - io.on('connect', function () { - done(); - }); - - io.on('error', function (err) { + helpers.connectSocketIO(res, function (err, _io) { + io = _io; + assert.ifError(err); done(err); }); }); @@ -116,7 +102,7 @@ describe('socket.io', function () { }); it('should post a topic', function (done) { - io.emit('topics.post', {title: 'test topic title', content: 'test topic main post content', uid: adminUid, cid: cid}, function (err, result) { + io.emit('topics.post', { title: 'test topic title', content: 'test topic main post content', uid: adminUid, cid: cid }, function (err, result) { assert.ifError(err); assert.equal(result.user.username, 'admin'); assert.equal(result.category.cid, cid); @@ -127,7 +113,7 @@ describe('socket.io', function () { }); it('should reply to topic', function (done) { - io.emit('posts.reply', {tid: tid, uid: adminUid, content: 'test post content'}, function (err, result) { + io.emit('posts.reply', { tid: tid, uid: adminUid, content: 'test post content' }, function (err, result) { assert.ifError(err); assert.equal(result.uid, adminUid); assert.equal(result.user.username, 'admin'); @@ -138,7 +124,7 @@ describe('socket.io', function () { it('should ban a user', function (done) { var socketUser = require('../src/socket.io/user'); - socketUser.banUsers({uid: adminUid}, {uids: [regularUid], reason: 'spammer'}, function (err) { + socketUser.banUsers({ uid: adminUid }, { uids: [regularUid], reason: 'spammer' }, function (err) { assert.ifError(err); user.getLatestBanInfo(regularUid, function (err, data) { assert.ifError(err); @@ -162,7 +148,7 @@ describe('socket.io', function () { it('should unban a user', function (done) { var socketUser = require('../src/socket.io/user'); - socketUser.unbanUsers({uid: adminUid}, [regularUid], function (err) { + socketUser.unbanUsers({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); user.isBanned(regularUid, function (err, isBanned) { assert.ifError(err); @@ -173,8 +159,7 @@ describe('socket.io', function () { }); it('should make user admin', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.makeAdmins({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.makeAdmins({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); groups.isMember(regularUid, 'administrators', function (err, isMember) { assert.ifError(err); @@ -185,8 +170,7 @@ describe('socket.io', function () { }); it('should make user non-admin', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.removeAdmins({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.removeAdmins({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); groups.isMember(regularUid, 'administrators', function (err, isMember) { assert.ifError(err); @@ -197,10 +181,9 @@ describe('socket.io', function () { }); describe('create/delete', function () { - var socketAdmin = require('../src/socket.io/admin'); var uid; it('should create a user', function (done) { - socketAdmin.user.createUser({uid: adminUid}, {username: 'foo1'}, function (err, _uid) { + socketAdmin.user.createUser({ uid: adminUid }, { username: 'foo1' }, function (err, _uid) { assert.ifError(err); uid = _uid; groups.isMember(uid, 'registered-users', function (err, isMember) { @@ -212,7 +195,7 @@ describe('socket.io', function () { }); it('should delete users', function (done) { - socketAdmin.user.deleteUsers({uid: adminUid}, [uid], function (err) { + socketAdmin.user.deleteUsers({ uid: adminUid }, [uid], function (err) { assert.ifError(err); groups.isMember(uid, 'registered-users', function (err, isMember) { assert.ifError(err); @@ -223,7 +206,7 @@ describe('socket.io', function () { }); it('should delete users and their content', function (done) { - socketAdmin.user.deleteUsersAndContent({uid: adminUid}, [uid], function (err) { + socketAdmin.user.deleteUsersAndContent({ uid: adminUid }, [uid], function (err) { assert.ifError(err); done(); }); @@ -231,37 +214,32 @@ describe('socket.io', function () { }); it('should error with invalid data', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.createUser({uid: adminUid}, null, function (err) { + socketAdmin.user.createUser({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should reset lockouts', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.resetLockouts({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.resetLockouts({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); done(); }); }); it('should reset flags', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.resetFlags({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.resetFlags({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); done(); }); }); - describe('validation emails', function () { - var socketAdmin = require('../src/socket.io/admin'); var meta = require('../src/meta'); it('should validate emails', function (done) { - socketAdmin.user.validateEmail({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.validateEmail({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); user.getUserField(regularUid, 'email:confirmed', function (err, emailConfirmed) { assert.ifError(err); @@ -272,25 +250,22 @@ describe('socket.io', function () { }); it('should error with invalid uids', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.sendValidationEmail({uid: adminUid}, null, function (err) { + socketAdmin.user.sendValidationEmail({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if email validation is not required', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.sendValidationEmail({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.sendValidationEmail({ uid: adminUid }, [regularUid], function (err) { assert.equal(err.message, '[[error:email-confirmations-are-disabled]]'); done(); }); }); it('should send validation email', function (done) { - var socketAdmin = require('../src/socket.io/admin'); meta.config.requireEmailConfirmation = 1; - socketAdmin.user.sendValidationEmail({uid: adminUid}, [regularUid], function (err) { + socketAdmin.user.sendValidationEmail({ uid: adminUid }, [regularUid], function (err) { assert.ifError(err); meta.config.requireEmailConfirmation = 0; done(); @@ -299,8 +274,7 @@ describe('socket.io', function () { }); it('should search users', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.search({uid: adminUid}, {query: 'reg', searchBy: 'username'}, function (err, data) { + socketAdmin.user.search({ uid: adminUid }, { query: 'reg', searchBy: 'username' }, function (err, data) { assert.ifError(err); assert.equal(data.matchCount, 1); assert.equal(data.users[0].username, 'regular'); @@ -310,7 +284,7 @@ describe('socket.io', function () { it('should push unread notifications on reconnect', function (done) { var socketMeta = require('../src/socket.io/meta'); - socketMeta.reconnected({uid: 1}, {}, function (err) { + socketMeta.reconnected({ uid: 1 }, {}, function (err) { assert.ifError(err); done(); }); @@ -326,14 +300,14 @@ describe('socket.io', function () { it('should return if uid is 0', function (done) { var socketMeta = require('../src/socket.io/meta'); - socketMeta.rooms.enter({uid: 0}, null, function (err) { + socketMeta.rooms.enter({ uid: 0 }, null, function (err) { assert.ifError(err); done(); }); }); it('should join a room', function (done) { - io.emit('meta.rooms.enter', {enter: 'recent_topics'}, function (err) { + io.emit('meta.rooms.enter', { enter: 'recent_topics' }, function (err) { assert.ifError(err); done(); }); @@ -348,15 +322,22 @@ describe('socket.io', function () { it('should get server time', function (done) { var socketMeta = require('../src/socket.io/meta'); - socketMeta.getServerTime({uid: 1}, null, function (err, time) { + socketMeta.getServerTime({ uid: 1 }, null, function (err, time) { assert.ifError(err); assert(time); done(); }); }); + it('should error to get daily analytics with invalid data', function (done) { + io.emit('admin.analytics.get', null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + it('should get daily analytics', function (done) { - io.emit('admin.analytics.get', {graph: 'traffic', units: 'days'}, function (err, data) { + io.emit('admin.analytics.get', { graph: 'traffic', units: 'days' }, function (err, data) { assert.ifError(err); assert(data); assert(data.monthlyPageViews); @@ -365,7 +346,7 @@ describe('socket.io', function () { }); it('should get hourly analytics', function (done) { - io.emit('admin.analytics.get', {graph: 'traffic', units: 'hours'}, function (err, data) { + io.emit('admin.analytics.get', { graph: 'traffic', units: 'hours' }, function (err, data) { assert.ifError(err); assert(data); assert(data.monthlyPageViews); @@ -374,22 +355,19 @@ describe('socket.io', function () { }); it('should return error', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.before({uid: 10}, 'someMethod', {}, function (err) { + socketAdmin.before({ uid: 10 }, 'someMethod', {}, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should get room stats', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - - io.emit('meta.rooms.enter', {enter: 'topic_1'}, function (err) { + io.emit('meta.rooms.enter', { enter: 'topic_1' }, function (err) { assert.ifError(err); - socketAdmin.rooms.getAll({uid: 10}, {}, function (err) { + socketAdmin.rooms.getAll({ uid: 10 }, {}, function (err) { assert.ifError(err); setTimeout(function () { - socketAdmin.rooms.getAll({uid: 10}, {}, function (err, data) { + socketAdmin.rooms.getAll({ uid: 10 }, {}, function (err, data) { assert.ifError(err); assert(data.hasOwnProperty('onlineGuestCount')); assert(data.hasOwnProperty('onlineRegisteredCount')); @@ -405,14 +383,12 @@ describe('socket.io', function () { }); it('should get room stats', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - - io.emit('meta.rooms.enter', {enter: 'category_1'}, function (err) { + io.emit('meta.rooms.enter', { enter: 'category_1' }, function (err) { assert.ifError(err); - socketAdmin.rooms.getAll({uid: 10}, {}, function (err) { + socketAdmin.rooms.getAll({ uid: 10 }, {}, function (err) { assert.ifError(err); setTimeout(function () { - socketAdmin.rooms.getAll({uid: 10}, {}, function (err, data) { + socketAdmin.rooms.getAll({ uid: 10 }, {}, function (err, data) { assert.ifError(err); assert.equal(data.users.category, 1); done(); @@ -423,8 +399,7 @@ describe('socket.io', function () { }); it('should get admin search dictionary', function (done) { - var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.getSearchDict({uid: adminUid}, {}, function (err, data) { + socketAdmin.getSearchDict({ uid: adminUid }, {}, function (err, data) { assert.ifError(err); assert(Array.isArray(data)); assert(data[0].namespace); @@ -434,10 +409,181 @@ describe('socket.io', function () { }); }); + it('should fire event', function (done) { + io.on('testEvent', function (data) { + assert.equal(data.foo, 1); + done(); + }); + socketAdmin.fireEvent({ uid: adminUid }, { name: 'testEvent', payload: { foo: 1 } }, function (err) { + assert.ifError(err); + }); + }); + + it('should error with invalid data', function (done) { + socketAdmin.themes.set({ uid: adminUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should set theme to bootswatch', function (done) { + socketAdmin.themes.set({ uid: adminUid }, { + type: 'bootswatch', + src: '//maxcdn.bootstrapcdn.com/bootswatch/latest/darkly/bootstrap.min.css', + id: 'darkly', + }, function (err) { + assert.ifError(err); + meta.configs.getFields(['theme:src', 'bootswatchSkin'], function (err, fields) { + assert.ifError(err); + assert.equal(fields['theme:src'], '//maxcdn.bootstrapcdn.com/bootswatch/latest/darkly/bootstrap.min.css'); + assert.equal(fields.bootswatchSkin, 'darkly'); + done(); + }); + }); + }); + + it('should set theme to local persona', function (done) { + socketAdmin.themes.set({ uid: adminUid }, { type: 'local', id: 'nodebb-theme-persona' }, function (err) { + assert.ifError(err); + meta.configs.get('theme:id', function (err, id) { + assert.ifError(err); + assert.equal(id, 'nodebb-theme-persona'); + done(); + }); + }); + }); + + it('should toggle plugin active', function (done) { + socketAdmin.plugins.toggleActive({ uid: adminUid }, 'nodebb-plugin-location-to-map', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, { id: 'nodebb-plugin-location-to-map', active: true }); + done(); + }); + }); + + it('should toggle plugin install', function (done) { + socketAdmin.plugins.toggleInstall({ uid: adminUid }, { id: 'nodebb-plugin-location-to-map', version: 'latest' }, function (err, data) { + assert.ifError(err); + assert.equal(data.name, 'nodebb-plugin-location-to-map'); + done(); + }); + }); + + it('should get list of active plugins', function (done) { + socketAdmin.plugins.getActive({ uid: adminUid }, {}, function (err, data) { + assert.ifError(err); + assert(Array.isArray(data)); + done(); + }); + }); + + it('should order active plugins', function (done) { + var data = [ + { name: 'nodebb-theme-persona', order: 0 }, + { name: 'nodebb-plugin-dbsearch', order: 1 }, + { ignoreme: 'wrong data' }, + ]; + socketAdmin.plugins.orderActivePlugins({ uid: adminUid }, data, function (err) { + assert.ifError(err); + db.sortedSetRank('plugins:active', 'nodebb-plugin-dbsearch', function (err, rank) { + assert.ifError(err); + assert.equal(rank, 1); + done(); + }); + }); + }); + + it('should upgrade plugin', function (done) { + socketAdmin.plugins.upgrade({ uid: adminUid }, { id: 'nodebb-plugin-location-to-map', version: 'latest' }, function (err) { + assert.ifError(err); + done(); + }); + }); + + it('should error with invalid data', function (done) { + socketAdmin.widgets.set({ uid: adminUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should error with invalid data', function (done) { + var data = { template: 'global', location: 'sidebar', widgets: [{ widget: 'html', data: { html: 'test', title: 'test', container: '' } }] }; + socketAdmin.widgets.set({ uid: adminUid }, data, function (err) { + assert.ifError(err); + db.getObjectField('widgets:global', 'sidebar', function (err, widgetData) { + assert.ifError(err); + + assert.equal(JSON.parse(widgetData)[0].data.html, 'test'); + done(); + }); + }); + }); + + it('should clear sitemap cache', function (done) { + socketAdmin.settings.clearSitemapCache({ uid: adminUid }, {}, function (err) { + assert.ifError(err); + done(); + }); + }); + + it('should send test email', function (done) { + socketAdmin.email.test({ uid: adminUid }, { template: 'digest.tpl' }, function (err) { + assert.ifError(err); + done(); + }); + }); + + it('should get logs', function (done) { + var fs = require('fs'); + var path = require('path'); + meta.logs.path = path.join(nconf.get('base_dir'), 'test/files', 'output.log'); + fs.appendFile(meta.logs.path, 'some logs', function (err) { + assert.ifError(err); + + socketAdmin.logs.get({ uid: adminUid }, {}, function (err, data) { + assert.ifError(err); + assert(data); + done(); + }); + }); + }); + + it('should clear logs', function (done) { + socketAdmin.logs.clear({ uid: adminUid }, {}, function (err) { + assert.ifError(err); + socketAdmin.logs.get({ uid: adminUid }, {}, function (err, data) { + assert.ifError(err); + assert.equal(data.length, 0); + done(); + }); + }); + }); + + it('should clear errors', function (done) { + socketAdmin.errors.clear({ uid: adminUid }, {}, function (err) { + assert.ifError(err); + db.exists('error:404', function (err, exists) { + assert.ifError(err); + assert(!exists); + done(); + }); + }); + }); + + it('shoudl delete all events', function (done) { + socketAdmin.deleteAllEvents({ uid: adminUid }, {}, function (err) { + assert.ifError(err); + db.sortedSetCard('events:time', function (err, count) { + assert.ifError(err); + assert.equal(count, 0); + done(); + }); + }); + }); after(function (done) { db.emptydb(done); }); - }); diff --git a/test/template-helpers.js b/test/template-helpers.js index 87502f9e40..eb145e98a8 100644 --- a/test/template-helpers.js +++ b/test/template-helpers.js @@ -1,28 +1,25 @@ 'use strict'; -var async = require('async'); +var nconf = require('nconf'); var assert = require('assert'); var db = require('./mocks/databasemock'); var helpers = require('../public/src/modules/helpers'); describe('helpers', function () { - - it('should return false if item doesn\'t exist', function (done) { - var flag = helpers.displayMenuItem({navigation: []}, 0); + var flag = helpers.displayMenuItem({ navigation: [] }, 0); assert(!flag); done(); }); - it('should return false if route is /users and privateUserInfo is on and user is not logged in', function (done) { var flag = helpers.displayMenuItem({ - navigation: [{route: '/users'}], + navigation: [{ route: '/users' }], privateUserInfo: true, config: { - loggedIn: false - } + loggedIn: false, + }, }, 0); assert(!flag); done(); @@ -30,18 +27,18 @@ describe('helpers', function () { it('should return false if route is /tags and privateTagListing is on and user is not logged in', function (done) { var flag = helpers.displayMenuItem({ - navigation: [{route: '/tags'}], + navigation: [{ route: '/tags' }], privateTagListing: true, config: { - loggedIn: false - } + loggedIn: false, + }, }, 0); assert(!flag); done(); }); it('should stringify object', function (done) { - var str = helpers.stringify({a: 'herp < derp > and & quote "'}); + var str = helpers.stringify({ a: 'herp < derp > and & quote "' }); assert.equal(str, '{"a":"herp < derp > and & quote \\""}'); done(); }); @@ -52,4 +49,185 @@ describe('helpers', function () { done(); }); + it('should return empty string if category is falsy', function (done) { + assert.equal(helpers.generateCategoryBackground(null), ''); + done(); + }); + + it('should generate category background', function (done) { + var category = { + bgColor: '#ff0000', + color: '#00ff00', + backgroundImage: '/assets/uploads/image.png', + imageClass: 'auto', + }; + var bg = helpers.generateCategoryBackground(category); + assert.equal(bg, 'background-color: #ff0000; color: #00ff00; background-image: url(/assets/uploads/image.png); background-size: auto;'); + done(); + }); + + it('should return empty string if category has no children', function (done) { + var category = { + children: [], + }; + var bg = helpers.generateChildrenCategories(category); + assert.equal(bg, ''); + done(); + }); + + it('should generate html for children', function (done) { + var category = { + children: [ + { + link: '', + bgColor: '#ff0000', + color: '#00ff00', + name: 'children', + }, + ], + }; + var html = helpers.generateChildrenCategories(category); + assert.equal(html, 'children '); + done(); + }); + + it('should generate topic class', function (done) { + var className = helpers.generateTopicClass({ locked: true, pinned: true, deleted: true, unread: true }); + assert.equal(className, 'locked pinned deleted unread'); + done(); + }); + + it('should show leave button if isMember and group is not administrators', function (done) { + var btn = helpers.membershipBtn({ displayName: 'some group', name: 'some group', isMember: true }); + assert.equal(btn, ''); + done(); + }); + + it('should show pending button if isPending and group is not administrators', function (done) { + var btn = helpers.membershipBtn({ displayName: 'some group', name: 'some group', isPending: true }); + assert.equal(btn, ''); + done(); + }); + + it('should show reject invite button if isInvited', function (done) { + var btn = helpers.membershipBtn({ displayName: 'some group', name: 'some group', isInvited: true }); + assert.equal(btn, ''); + done(); + }); + + it('should show join button if join requests are not disabled and group is not administrators', function (done) { + var btn = helpers.membershipBtn({ displayName: 'some group', name: 'some group', disableJoinRequests: false }); + assert.equal(btn, ''); + done(); + }); + + it('should show nothing if group is administrators ', function (done) { + var btn = helpers.membershipBtn({ displayName: 'administrators', name: 'administrators' }); + assert.equal(btn, ''); + done(); + }); + + it('should spawn privilege states', function (done) { + var privs = { + find: true, + read: true, + }; + var html = helpers.spawnPrivilegeStates('guests', privs); + assert.equal(html, ''); + done(); + }); + + it('should spawn privilege states', function (done) { + var privs = { + find: true, + read: true, + }; + var html = helpers.spawnPrivilegeStates('guests', privs); + assert.equal(html, ''); + done(); + }); + + it('should render thumb as topic image', function (done) { + var topicObj = { thumb: '/uploads/1.png', user: { username: 'baris' } }; + var html = helpers.renderTopicImage(topicObj); + assert.equal(html, ''); + done(); + }); + + it('should render user picture as topic image', function (done) { + var topicObj = { thumb: '', user: { uid: 1, username: 'baris', picture: '/uploads/2.png' } }; + var html = helpers.renderTopicImage(topicObj); + assert.equal(html, ''); + done(); + }); + + it('should render digest avatar', function (done) { + var block = { teaser: { user: { username: 'baris', picture: '/uploads/1.png' } } }; + var html = helpers.renderDigestAvatar(block); + assert.equal(html, ''); + done(); + }); + + it('should render digest avatar', function (done) { + var block = { teaser: { user: { username: 'baris', 'icon:text': 'B', 'icon:bgColor': '#ff000' } } }; + var html = helpers.renderDigestAvatar(block); + assert.equal(html, '
    ' + block.teaser.user['icon:text'] + '
    '); + done(); + }); + + it('should render digest avatar', function (done) { + var block = { user: { username: 'baris', picture: '/uploads/1.png' } }; + var html = helpers.renderDigestAvatar(block); + assert.equal(html, ''); + done(); + }); + + it('should render digest avatar', function (done) { + var block = { user: { username: 'baris', 'icon:text': 'B', 'icon:bgColor': '#ff000' } }; + var html = helpers.renderDigestAvatar(block); + assert.equal(html, '
    ' + block.user['icon:text'] + '
    '); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'Linux', browser: 'Chrome' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'Microsoft Windows', browser: 'Firefox' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'Apple Mac', browser: 'Safari' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'Android', browser: 'IE' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'iPad', browser: 'Edge' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'iPhone', browser: 'unknow' }); + assert.equal(html, ''); + done(); + }); + + it('shoud render user agent/browser icons', function (done) { + var html = helpers.userAgentIcons({ platform: 'unknow', browser: 'unknown' }); + assert.equal(html, ''); + done(); + }); }); diff --git a/test/topics.js b/test/topics.js index cfb77ed581..2222395833 100644 --- a/test/topics.js +++ b/test/topics.js @@ -12,6 +12,7 @@ var User = require('../src/user'); var groups = require('../src/groups'); var helpers = require('./helpers'); var socketPosts = require('../src/socket.io/posts'); +var socketTopics = require('../src/socket.io/topics'); describe('Topic\'s', function () { var topic; @@ -20,7 +21,7 @@ describe('Topic\'s', function () { before(function (done) { groups.resetCache(); - User.create({username: 'admin', password: '123456'}, function (err, uid) { + User.create({ username: 'admin', password: '123456' }, function (err, uid) { if (err) { return done(err); } @@ -29,7 +30,7 @@ describe('Topic\'s', function () { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, function (err, category) { if (err) { return done(err); @@ -41,7 +42,7 @@ describe('Topic\'s', function () { userId: uid, categoryId: categoryObj.cid, title: 'Test Topic Title', - content: 'The content of test topic' + content: 'The content of test topic', }; done(); }); @@ -49,39 +50,61 @@ describe('Topic\'s', function () { }); describe('.post', function () { + it('should fail to create topic with invalid data', function (done) { + socketTopics.post({ uid: 0 }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); it('should create a new topic with proper parameters', function (done) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { - assert.equal(err, null, 'was created with error'); - assert.ok(result); + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { + assert.ifError(err); + assert(result); + topic.tid = result.topicData.tid; + done(); + }); + }); + it('should get post count', function (done) { + socketTopics.postcount({ uid: adminUid }, topic.tid, function (err, count) { + assert.ifError(err); + assert.equal(count, 1); + done(); + }); + }); + + it('should load topic', function (done) { + socketTopics.getTopic({ uid: adminUid }, topic.tid, function (err, data) { + assert.ifError(err); + assert.equal(data.tid, topic.tid); done(); }); }); it('should fail to create new topic with invalid user id', function (done) { - topics.post({uid: null, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err) { + topics.post({ uid: null, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should fail to create new topic with empty title', function (done) { - topics.post({uid: topic.userId, title: '', content: topic.content, cid: topic.categoryId}, function (err) { + topics.post({ uid: topic.userId, title: '', content: topic.content, cid: topic.categoryId }, function (err) { assert.ok(err); done(); }); }); it('should fail to create new topic with empty content', function (done) { - topics.post({uid: topic.userId, title: topic.title, content: '', cid: topic.categoryId}, function (err) { + topics.post({ uid: topic.userId, title: topic.title, content: '', cid: topic.categoryId }, function (err) { assert.ok(err); done(); }); }); it('should fail to create new topic with non-existant category id', function (done) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: 99}, function (err) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: 99 }, function (err) { assert.equal(err.message, '[[error:no-category]]', 'received no error'); done(); }); @@ -93,7 +116,7 @@ describe('Topic\'s', function () { var newPost; before(function (done) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { if (err) { return done(err); } @@ -105,7 +128,7 @@ describe('Topic\'s', function () { }); it('should create a new reply with proper parameters', function (done) { - topics.reply({uid: topic.userId, content: 'test post', tid: newTopic.tid}, function (err, result) { + topics.reply({ uid: topic.userId, content: 'test post', tid: newTopic.tid }, function (err, result) { assert.equal(err, null, 'was created with error'); assert.ok(result); @@ -114,11 +137,11 @@ describe('Topic\'s', function () { }); it('should handle direct replies', function (done) { - topics.reply({uid: topic.userId, content: 'test reply', tid: newTopic.tid, toPid: newPost.pid}, function (err, result) { + topics.reply({ uid: topic.userId, content: 'test reply', tid: newTopic.tid, toPid: newPost.pid }, function (err, result) { assert.equal(err, null, 'was created with error'); assert.ok(result); - socketPosts.getReplies({uid: 0}, newPost.pid, function (err, postData) { + socketPosts.getReplies({ uid: 0 }, newPost.pid, function (err, postData) { assert.equal(err, null, 'posts.getReplies returned error'); assert.ok(postData); @@ -132,35 +155,35 @@ describe('Topic\'s', function () { }); it('should error if pid is not a number', function (done) { - socketPosts.getReplies({uid: 0}, 'abc', function (err) { + socketPosts.getReplies({ uid: 0 }, 'abc', function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should fail to create new reply with invalid user id', function (done) { - topics.reply({uid: null, content: 'test post', tid: newTopic.tid}, function (err) { + topics.reply({ uid: null, content: 'test post', tid: newTopic.tid }, function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should fail to create new reply with empty content', function (done) { - topics.reply({uid: topic.userId, content: '', tid: newTopic.tid}, function (err) { + topics.reply({ uid: topic.userId, content: '', tid: newTopic.tid }, function (err) { assert.ok(err); done(); }); }); it('should fail to create new reply with invalid topic id', function (done) { - topics.reply({uid: null, content: 'test post', tid: 99}, function (err) { + topics.reply({ uid: null, content: 'test post', tid: 99 }, function (err) { assert.equal(err.message, '[[error:no-topic]]'); done(); }); }); it('should fail to create new reply with invalid toPid', function (done) { - topics.reply({uid: topic.userId, content: 'test post', tid: newTopic.tid, toPid: '"onmouseover=alert(1);//'}, function (err) { + topics.reply({ uid: topic.userId, content: 'test post', tid: newTopic.tid, toPid: '"onmouseover=alert(1);//' }, function (err) { assert.equal(err.message, '[[error:invalid-pid]]'); done(); }); @@ -172,7 +195,7 @@ describe('Topic\'s', function () { var newPost; before(function (done) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { if (err) { return done(err); } @@ -228,11 +251,10 @@ describe('Topic\'s', function () { }); describe('Title escaping', function () { - it('should properly escape topic title', function (done) { var title = '" new topic test'; var titleEscaped = validator.escape(title); - topics.post({uid: topic.userId, title: title, content: topic.content, cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: title, content: topic.content, cid: topic.categoryId }, function (err, result) { assert.ifError(err); topics.getTopicData(result.topicData.tid, function (err, topicData) { assert.ifError(err); @@ -248,21 +270,21 @@ describe('Topic\'s', function () { var newTopic; var followerUid; var moveCid; - var socketTopics = require('../src/socket.io/topics'); + before(function (done) { async.waterfall([ function (next) { groups.join('administrators', adminUid, next); }, function (next) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { assert.ifError(err); newTopic = result.topicData; next(); }); }, function (next) { - User.create({username: 'topicFollower', password: '123456'}, next); + User.create({ username: 'topicFollower', password: '123456' }, next); }, function (_uid, next) { followerUid = _uid; @@ -271,7 +293,7 @@ describe('Topic\'s', function () { function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, function (err, category) { if (err) { return next(err); @@ -279,12 +301,12 @@ describe('Topic\'s', function () { moveCid = category.cid; next(); }); - } + }, ], done); }); it('should load topic tools', function (done) { - socketTopics.loadTopicTools({uid: 1}, {tid: newTopic.tid}, function (err, data) { + socketTopics.loadTopicTools({ uid: 1 }, { tid: newTopic.tid }, function (err, data) { assert.ifError(err); assert(data); done(); @@ -292,21 +314,21 @@ describe('Topic\'s', function () { }); it('should delete the topic', function (done) { - socketTopics.delete({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.delete({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); done(); }); }); it('should restore the topic', function (done) { - socketTopics.restore({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.restore({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); done(); }); }); it('should lock topic', function (done) { - socketTopics.lock({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.lock({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); topics.isLocked(newTopic.tid, function (err, isLocked) { assert.ifError(err); @@ -317,7 +339,7 @@ describe('Topic\'s', function () { }); it('should unlock topic', function (done) { - socketTopics.unlock({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.unlock({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); topics.isLocked(newTopic.tid, function (err, isLocked) { assert.ifError(err); @@ -328,7 +350,7 @@ describe('Topic\'s', function () { }); it('should pin topic', function (done) { - socketTopics.pin({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.pin({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); db.getObjectField('topic:' + newTopic.tid, 'pinned', function (err, pinned) { assert.ifError(err); @@ -339,7 +361,7 @@ describe('Topic\'s', function () { }); it('should unpin topic', function (done) { - socketTopics.unpin({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.unpin({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); db.getObjectField('topic:' + newTopic.tid, 'pinned', function (err, pinned) { assert.ifError(err); @@ -350,7 +372,7 @@ describe('Topic\'s', function () { }); it('should move all topics', function (done) { - socketTopics.moveAll({uid: 1}, {cid: moveCid, currentCid: categoryObj.cid}, function (err) { + socketTopics.moveAll({ uid: 1 }, { cid: moveCid, currentCid: categoryObj.cid }, function (err) { assert.ifError(err); topics.getTopicField(newTopic.tid, 'cid', function (err, cid) { assert.ifError(err); @@ -361,7 +383,7 @@ describe('Topic\'s', function () { }); it('should move a topic', function (done) { - socketTopics.move({uid: 1}, {cid: categoryObj.cid, tids: [newTopic.tid]}, function (err) { + socketTopics.move({ uid: 1 }, { cid: categoryObj.cid, tids: [newTopic.tid] }, function (err) { assert.ifError(err); topics.getTopicField(newTopic.tid, 'cid', function (err, cid) { assert.ifError(err); @@ -372,7 +394,7 @@ describe('Topic\'s', function () { }); it('should purge the topic', function (done) { - socketTopics.purge({uid: 1}, {tids: [newTopic.tid], cid: categoryObj.cid}, function (err) { + socketTopics.purge({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) { assert.ifError(err); db.isSortedSetMember('uid:' + followerUid + ':followed_tids', newTopic.tid, function (err, isMember) { assert.ifError(err); @@ -393,7 +415,7 @@ describe('Topic\'s', function () { uid: topic.userId, title: 'topic for test', content: 'topic content', - cid: topic.categoryId + cid: topic.categoryId, }, callback); } async.series({ @@ -405,7 +427,7 @@ describe('Topic\'s', function () { }, topic3: function (next) { createTopic(next); - } + }, }, function (err, results) { assert.ifError(err); tid1 = results.topic1.topicData.tid; @@ -417,35 +439,35 @@ describe('Topic\'s', function () { }, function (next) { topics.tools.pin(tid2, adminUid, next); - } + }, ], done); }); }); var socketTopics = require('../src/socket.io/topics'); it('should error with invalid data', function (done) { - socketTopics.orderPinnedTopics({uid: adminUid}, null, function (err) { + socketTopics.orderPinnedTopics({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error with invalid data', function (done) { - socketTopics.orderPinnedTopics({uid: adminUid}, [null, null], function (err) { + socketTopics.orderPinnedTopics({ uid: adminUid }, [null, null], function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error with unprivileged user', function (done) { - socketTopics.orderPinnedTopics({uid: 0}, [{tid: tid1}, {tid: tid2}], function (err) { + socketTopics.orderPinnedTopics({ uid: 0 }, [{ tid: tid1 }, { tid: tid2 }], function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should not do anything if topics are not pinned', function (done) { - socketTopics.orderPinnedTopics({uid: adminUid}, [{tid: tid3}], function (err) { + socketTopics.orderPinnedTopics({ uid: adminUid }, [{ tid: tid3 }], function (err) { assert.ifError(err); db.isSortedSetMember('cid:' + topic.categoryId + ':tids:pinned', tid3, function (err, isMember) { assert.ifError(err); @@ -460,7 +482,7 @@ describe('Topic\'s', function () { assert.ifError(err); assert.equal(pinnedTids[0], tid2); assert.equal(pinnedTids[1], tid1); - socketTopics.orderPinnedTopics({uid: adminUid}, [{tid: tid1, order: 1}, {tid: tid2, order: 0}], function (err) { + socketTopics.orderPinnedTopics({ uid: adminUid }, [{ tid: tid1, order: 1 }, { tid: tid2, order: 0 }], function (err) { assert.ifError(err); db.getSortedSetRevRange('cid:' + topic.categoryId + ':tids:pinned', 0, -1, function (err, pinnedTids) { assert.ifError(err); @@ -471,7 +493,6 @@ describe('Topic\'s', function () { }); }); }); - }); @@ -483,7 +504,7 @@ describe('Topic\'s', function () { uid = topic.userId; async.waterfall([ function (done) { - topics.post({uid: topic.userId, title: 'Topic to be ignored', content: 'Just ignore me, please!', cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: 'Topic to be ignored', content: 'Just ignore me, please!', cid: topic.categoryId }, function (err, result) { if (err) { return done(err); } @@ -494,41 +515,41 @@ describe('Topic\'s', function () { }); }, function (done) { - topics.markUnread( newTid, uid, done ); - } - ],done); + topics.markUnread(newTid, uid, done); + }, + ], done); }); it('should not appear in the unread list', function (done) { async.waterfall([ function (done) { - topics.ignore( newTid, uid, done ); + topics.ignore(newTid, uid, done); }, function (done) { - topics.getUnreadTopics(0, uid, 0, -1, '', done ); + topics.getUnreadTopics(0, uid, 0, -1, '', done); }, function (results, done) { var topics = results.topics; - var tids = topics.map( function (topic) { return topic.tid; } ); + var tids = topics.map(function (topic) { return topic.tid; }); assert.equal(tids.indexOf(newTid), -1, 'The topic appeared in the unread list.'); done(); - } + }, ], done); }); it('should not appear as unread in the recent list', function (done) { async.waterfall([ function (done) { - topics.ignore( newTid, uid, done ); + topics.ignore(newTid, uid, done); }, function (done) { - topics.getLatestTopics( uid, 0, -1, 'year', done ); + topics.getLatestTopics(uid, 0, -1, 'year', done); }, function (results, done) { var topics = results.topics; var topic; var i; - for(i = 0; i < topics.length; ++i) { + for (i = 0; i < topics.length; i += 1) { if (parseInt(topics[i].tid, 10) === parseInt(newTid, 10)) { assert.equal(false, topics[i].unread, 'ignored topic was marked as unread in recent list'); return done(); @@ -536,47 +557,47 @@ describe('Topic\'s', function () { } assert.ok(topic, 'topic didn\'t appear in the recent list'); done(); - } + }, ], done); }); it('should appear as unread again when marked as reading', function (done) { async.waterfall([ function (done) { - topics.ignore( newTid, uid, done ); + topics.ignore(newTid, uid, done); }, function (done) { - topics.follow( newTid, uid, done ); + topics.follow(newTid, uid, done); }, function (done) { - topics.getUnreadTopics(0, uid, 0, -1, '', done ); + topics.getUnreadTopics(0, uid, 0, -1, '', done); }, function (results, done) { var topics = results.topics; - var tids = topics.map( function (topic) { return topic.tid; } ); + var tids = topics.map(function (topic) { return topic.tid; }); assert.notEqual(tids.indexOf(newTid), -1, 'The topic did not appear in the unread list.'); done(); - } + }, ], done); }); it('should appear as unread again when marked as following', function (done) { async.waterfall([ function (done) { - topics.ignore( newTid, uid, done ); + topics.ignore(newTid, uid, done); }, function (done) { - topics.follow( newTid, uid, done ); + topics.follow(newTid, uid, done); }, function (done) { - topics.getUnreadTopics(0, uid, 0, -1, '', done ); + topics.getUnreadTopics(0, uid, 0, -1, '', done); }, function (results, done) { var topics = results.topics; - var tids = topics.map( function (topic) { return topic.tid; } ); + var tids = topics.map(function (topic) { return topic.tid; }); assert.notEqual(tids.indexOf(newTid), -1, 'The topic did not appear in the unread list.'); done(); - } + }, ], done); }); }); @@ -587,13 +608,12 @@ describe('Topic\'s', function () { var topicPids; var originalBookmark = 5; function postReply(next) { - topics.reply({uid: topic.userId, content: 'test post ' + replies.length, tid: newTopic.tid}, function (err, result) { - assert.equal(err, null, 'was created with error'); - assert.ok(result); - replies.push(result); - next(); - } - ); + topics.reply({ uid: topic.userId, content: 'test post ' + replies.length, tid: newTopic.tid }, function (err, result) { + assert.equal(err, null, 'was created with error'); + assert.ok(result); + replies.push(result); + next(); + }); } before(function (done) { @@ -601,55 +621,75 @@ describe('Topic\'s', function () { function (next) { groups.join('administrators', topic.userId, next); }, - function ( next ) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { - assert.ifError( err ); + function (next) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { + assert.ifError(err); newTopic = result.topicData; next(); }); }, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { postReply( next );}, - function ( next ) { - topicPids = replies.map( function ( reply ) { return reply.pid; } ); - topics.setUserBookmark( newTopic.tid, topic.userId, originalBookmark, next ); + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { postReply(next); }, + function (next) { + topicPids = replies.map(function (reply) { return reply.pid; }); + socketTopics.bookmark({ uid: topic.userId }, { tid: newTopic.tid, index: originalBookmark }, next); }], - done ); + done); + }); + + it('should fail with invalid data', function (done) { + socketTopics.bookmark({ uid: topic.userId }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); }); it('should have 12 replies', function (done) { - assert.equal( 12, replies.length ); + assert.equal(12, replies.length); done(); }); + it('should fail with invalid data', function (done) { + socketTopics.createTopicFromPosts({ uid: 0 }, null, function (err) { + assert.equal(err.message, '[[error:not-logged-in]]'); + done(); + }); + }); + + it('should fail with invalid data', function (done) { + socketTopics.createTopicFromPosts({ uid: 1 }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + it('should not update the user\'s bookmark', function (done) { async.waterfall([ function (next) { - topics.createTopicFromPosts( - topic.userId, - 'Fork test, no bookmark update', - topicPids.slice( -2 ), - newTopic.tid, - next ); + socketTopics.createTopicFromPosts({ uid: topic.userId }, { + title: 'Fork test, no bookmark update', + pids: topicPids.slice(-2), + fromTid: newTopic.tid, + }, next); }, - function ( forkedTopicData, next) { - topics.getUserBookmark( newTopic.tid, topic.userId, next ); + function (forkedTopicData, next) { + topics.getUserBookmark(newTopic.tid, topic.userId, next); }, - function ( bookmark, next ) { - assert.equal( originalBookmark, bookmark ); + function (bookmark, next) { + assert.equal(originalBookmark, bookmark); next(); - } - ],done); + }, + ], done); }); it('should update the user\'s bookmark ', function (done) { @@ -658,18 +698,18 @@ describe('Topic\'s', function () { topics.createTopicFromPosts( topic.userId, 'Fork test, no bookmark update', - topicPids.slice( 1, 3 ), + topicPids.slice(1, 3), newTopic.tid, - next ); + next); }, - function ( forkedTopicData, next) { - topics.getUserBookmark( newTopic.tid, topic.userId, next ); + function (forkedTopicData, next) { + topics.getUserBookmark(newTopic.tid, topic.userId, next); }, - function ( bookmark, next ) { - assert.equal( originalBookmark - 2, bookmark ); + function (bookmark, next) { + assert.equal(originalBookmark - 2, bookmark); next(); - } - ],done); + }, + ], done); }); }); @@ -683,7 +723,7 @@ describe('Topic\'s', function () { title: 'topic for controller test', content: 'topic content', cid: topic.categoryId, - thumb: 'http://i.imgur.com/64iBdBD.jpg' + thumb: 'http://i.imgur.com/64iBdBD.jpg', }, function (err, result) { assert.ifError(err); assert.ok(result); @@ -762,7 +802,7 @@ describe('Topic\'s', function () { helpers.loginUser('admin', '123456', function (err, jar) { assert.ifError(err); request(nconf.get('url') + '/topic/' + topicData.slug, { - jar: jar + jar: jar, }, function (err, res) { assert.ifError(err); assert.equal(res.statusCode, 200); @@ -776,7 +816,7 @@ describe('Topic\'s', function () { }); it('should 404 if tid is not a number', function (done) { - request(nconf.get('url') + '/api/topic/teaser/nan', {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/teaser/nan', { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 404); done(); @@ -784,7 +824,7 @@ describe('Topic\'s', function () { }); it('should 403 if cant read', function (done) { - request(nconf.get('url') + '/api/topic/teaser/' + 123123, {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/teaser/' + 123123, { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 403); assert.equal(body, '[[error:no-privileges]]'); @@ -794,7 +834,7 @@ describe('Topic\'s', function () { }); it('should load topic teaser', function (done) { - request(nconf.get('url') + '/api/topic/teaser/' + topicData.tid, {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/teaser/' + topicData.tid, { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 200); assert(body); @@ -809,7 +849,7 @@ describe('Topic\'s', function () { it('should 404 if tid is not a number', function (done) { - request(nconf.get('url') + '/api/topic/pagination/nan', {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/pagination/nan', { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 404); done(); @@ -817,7 +857,7 @@ describe('Topic\'s', function () { }); it('should 404 if tid does not exist', function (done) { - request(nconf.get('url') + '/api/topic/pagination/1231231', {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/pagination/1231231', { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 404); done(); @@ -825,7 +865,7 @@ describe('Topic\'s', function () { }); it('should load pagination', function (done) { - request(nconf.get('url') + '/api/topic/pagination/' + topicData.tid, {json: true}, function (err, response, body) { + request(nconf.get('url') + '/api/topic/pagination/' + topicData.tid, { json: true }, function (err, response, body) { assert.ifError(err); assert.equal(response.statusCode, 200); assert(body); @@ -835,12 +875,11 @@ describe('Topic\'s', function () { rel: [], pages: [], currentPage: 1, - pageCount: 1 + pageCount: 1, }); done(); }); }); - }); @@ -848,7 +887,7 @@ describe('Topic\'s', function () { var socketTopics = require('../src/socket.io/topics'); var tid; before(function (done) { - topics.post({uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId}, function (err, result) { + topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, function (err, result) { assert.ifError(err); tid = result.topicData.tid; done(); @@ -856,14 +895,14 @@ describe('Topic\'s', function () { }); it('should error with invalid data', function (done) { - socketTopics.loadMore({uid: adminUid}, {}, function (err) { + socketTopics.loadMore({ uid: adminUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should infinite load topic posts', function (done) { - socketTopics.loadMore({uid: adminUid}, {tid: tid, after: 0}, function (err, data) { + socketTopics.loadMore({ uid: adminUid }, { tid: tid, after: 0 }, function (err, data) { assert.ifError(err); assert(data.mainPost); assert(data.posts); @@ -873,16 +912,16 @@ describe('Topic\'s', function () { }); it('should error with invalid data', function (done) { - socketTopics.loadMoreUnreadTopics({uid: adminUid}, {after: 'invalid'}, function (err) { + socketTopics.loadMoreUnreadTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more unread topics', function (done) { - socketTopics.markUnread({uid: adminUid}, tid, function (err) { + socketTopics.markUnread({ uid: adminUid }, tid, function (err) { assert.ifError(err); - socketTopics.loadMoreUnreadTopics({uid: adminUid}, {cid: topic.categoryId, after: 0}, function (err, data) { + socketTopics.loadMoreUnreadTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0 }, function (err, data) { assert.ifError(err); assert(data); assert(Array.isArray(data.topics)); @@ -892,7 +931,7 @@ describe('Topic\'s', function () { }); it('should error with invalid data', function (done) { - socketTopics.loadMoreRecentTopics({uid: adminUid}, {after: 'invalid'}, function (err) { + socketTopics.loadMoreRecentTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -900,7 +939,7 @@ describe('Topic\'s', function () { it('should load more recent topics', function (done) { - socketTopics.loadMoreRecentTopics({uid: adminUid}, {cid: topic.categoryId, after: 0}, function (err, data) { + socketTopics.loadMoreRecentTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0 }, function (err, data) { assert.ifError(err); assert(data); assert(Array.isArray(data.topics)); @@ -909,21 +948,20 @@ describe('Topic\'s', function () { }); it('should error with invalid data', function (done) { - socketTopics.loadMoreFromSet({uid: adminUid}, {after: 'invalid'}, function (err) { + socketTopics.loadMoreFromSet({ uid: adminUid }, { after: 'invalid' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more from custom set', function (done) { - socketTopics.loadMoreFromSet({uid: adminUid}, {set: 'uid:' + adminUid + ':topics', after: 0}, function (err, data) { + socketTopics.loadMoreFromSet({ uid: adminUid }, { set: 'uid:' + adminUid + ':topics', after: 0 }, function (err, data) { assert.ifError(err); assert(data); assert(Array.isArray(data.topics)); done(); }); }); - }); describe('suggested topics', function () { @@ -932,11 +970,11 @@ describe('Topic\'s', function () { before(function (done) { async.parallel({ topic1: function (next) { - topics.post({uid: adminUid, tags: ['nodebb'], title: 'topic title 1', content: 'topic 1 content', cid: topic.categoryId}, next); + topics.post({ uid: adminUid, tags: ['nodebb'], title: 'topic title 1', content: 'topic 1 content', cid: topic.categoryId }, next); }, topic2: function (next) { - topics.post({uid: adminUid, tags: ['nodebb'], title: 'topic title 2', content: 'topic 2 content', cid: topic.categoryId}, next); - } + topics.post({ uid: adminUid, tags: ['nodebb'], title: 'topic title 2', content: 'topic 2 content', cid: topic.categoryId }, next); + }, }, function (err, results) { assert.ifError(err); tid1 = results.topic1.topicData.tid; @@ -962,11 +1000,11 @@ describe('Topic\'s', function () { before(function (done) { async.parallel({ topic: function (next) { - topics.post({uid: topic.userId, title: 'unread topic', content: 'unread topic content', cid: topic.categoryId}, next); + topics.post({ uid: topic.userId, title: 'unread topic', content: 'unread topic content', cid: topic.categoryId }, next); }, user: function (next) { - User.create({username: 'regularJoe'}, next); - } + User.create({ username: 'regularJoe' }, next); + }, }, function (err, results) { assert.ifError(err); tid = results.topic.topicData.tid; @@ -977,21 +1015,21 @@ describe('Topic\'s', function () { }); it('should fail with invalid data', function (done) { - socketTopics.markUnread({uid: adminUid}, null, function (err) { + socketTopics.markUnread({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should fail if topic does not exist', function (done) { - socketTopics.markUnread({uid: adminUid}, 1231082, function (err) { + socketTopics.markUnread({ uid: adminUid }, 1231082, function (err) { assert.equal(err.message, '[[error:no-topic]]'); done(); }); }); it('should mark topic unread', function (done) { - socketTopics.markUnread({uid: adminUid}, tid, function (err) { + socketTopics.markUnread({ uid: adminUid }, tid, function (err) { assert.ifError(err); topics.hasReadTopic(tid, adminUid, function (err, hasRead) { assert.ifError(err); @@ -1003,7 +1041,7 @@ describe('Topic\'s', function () { it('should fail with invalid data', function (done) { - socketTopics.markAsRead({uid: 0}, null, function (err) { + socketTopics.markAsRead({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -1011,7 +1049,7 @@ describe('Topic\'s', function () { it('should mark topic read', function (done) { - socketTopics.markAsRead({uid: adminUid}, [tid], function (err) { + socketTopics.markAsRead({ uid: adminUid }, [tid], function (err) { assert.ifError(err); topics.hasReadTopic(tid, adminUid, function (err, hasRead) { assert.ifError(err); @@ -1022,7 +1060,7 @@ describe('Topic\'s', function () { }); it('should fail with invalid data', function (done) { - socketTopics.markTopicNotificationsRead({uid: 0}, null, function (err) { + socketTopics.markTopicNotificationsRead({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -1033,10 +1071,10 @@ describe('Topic\'s', function () { async.waterfall([ function (next) { - socketTopics.follow({uid: adminUid}, tid, next); + socketTopics.follow({ uid: adminUid }, tid, next); }, function (next) { - socketPosts.reply({uid: uid}, {content: 'some content', tid: tid}, next); + socketPosts.reply({ uid: uid }, { content: 'some content', tid: tid }, next); }, function (data, next) { setTimeout(next, 2500); @@ -1046,7 +1084,7 @@ describe('Topic\'s', function () { }, function (count, next) { assert.equal(count, 1); - socketTopics.markTopicNotificationsRead({uid: adminUid}, [tid], next); + socketTopics.markTopicNotificationsRead({ uid: adminUid }, [tid], next); }, function (next) { User.notifications.getUnreadCount(adminUid, next); @@ -1054,7 +1092,7 @@ describe('Topic\'s', function () { function (count, next) { assert.equal(count, 0); next(); - } + }, ], function (err) { assert.ifError(err); done(); @@ -1062,16 +1100,16 @@ describe('Topic\'s', function () { }); it('should fail with invalid data', function (done) { - socketTopics.markAllRead({uid: 0}, null, function (err) { + socketTopics.markAllRead({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:invalid-uid]]'); done(); }); }); it('should mark all read', function (done) { - socketTopics.markUnread({uid: adminUid}, tid, function (err) { + socketTopics.markUnread({ uid: adminUid }, tid, function (err) { assert.ifError(err); - socketTopics.markAllRead({uid: adminUid}, {}, function (err) { + socketTopics.markAllRead({ uid: adminUid }, {}, function (err) { assert.ifError(err); topics.hasReadTopic(tid, adminUid, function (err, hasRead) { assert.ifError(err); @@ -1083,9 +1121,9 @@ describe('Topic\'s', function () { }); it('should mark all read', function (done) { - socketTopics.markUnread({uid: adminUid}, tid, function (err) { + socketTopics.markUnread({ uid: adminUid }, tid, function (err) { assert.ifError(err); - socketTopics.markCategoryTopicsRead({uid: adminUid}, topic.categoryId, function (err) { + socketTopics.markCategoryTopicsRead({ uid: adminUid }, topic.categoryId, function (err) { assert.ifError(err); topics.hasReadTopic(tid, adminUid, function (err, hasRead) { assert.ifError(err); @@ -1098,35 +1136,35 @@ describe('Topic\'s', function () { it('should fail with invalid data', function (done) { - socketTopics.markAsUnreadForAll({uid: adminUid}, null, function (err) { + socketTopics.markAsUnreadForAll({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-tid]]'); done(); }); }); it('should fail with invalid data', function (done) { - socketTopics.markAsUnreadForAll({uid: 0}, [tid], function (err) { + socketTopics.markAsUnreadForAll({ uid: 0 }, [tid], function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should fail if user is not admin', function (done) { - socketTopics.markAsUnreadForAll({uid: uid}, [tid], function (err) { + socketTopics.markAsUnreadForAll({ uid: uid }, [tid], function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); }); it('should fail if topic does not exist', function (done) { - socketTopics.markAsUnreadForAll({uid: uid}, [12312313], function (err) { + socketTopics.markAsUnreadForAll({ uid: uid }, [12312313], function (err) { assert.equal(err.message, '[[error:no-topic]]'); done(); }); }); it('should mark topic unread for everyone', function (done) { - socketTopics.markAsUnreadForAll({uid: adminUid}, [tid], function (err) { + socketTopics.markAsUnreadForAll({ uid: adminUid }, [tid], function (err) { assert.ifError(err); async.parallel({ adminRead: function (next) { @@ -1134,7 +1172,7 @@ describe('Topic\'s', function () { }, regularRead: function (next) { topics.hasReadTopic(tid, uid, next); - } + }, }, function (err, results) { assert.ifError(err); assert.equal(results.adminRead, false); @@ -1143,6 +1181,14 @@ describe('Topic\'s', function () { }); }); }); + + it('should not do anything if tids is empty array', function (done) { + socketTopics.markAsRead({ uid: adminUid }, [], function (err, markedRead) { + assert.ifError(err); + assert(!markedRead); + done(); + }); + }); }); describe('tags', function () { @@ -1152,11 +1198,11 @@ describe('Topic\'s', function () { before(function (done) { async.parallel({ topic1: function (next) { - topics.post({uid: adminUid, tags: ['php', 'nosql', 'psql', 'nodebb'], title: 'topic title 1', content: 'topic 1 content', cid: topic.categoryId}, next); + topics.post({ uid: adminUid, tags: ['php', 'nosql', 'psql', 'nodebb'], title: 'topic title 1', content: 'topic 1 content', cid: topic.categoryId }, next); }, topic2: function (next) { - topics.post({uid: adminUid, tags: ['javascript', 'mysql', 'python', 'nodejs'], title: 'topic title 2', content: 'topic 2 content', cid: topic.categoryId}, next); - } + topics.post({ uid: adminUid, tags: ['javascript', 'mysql', 'python', 'nodejs'], title: 'topic title 2', content: 'topic 2 content', cid: topic.categoryId }, next); + }, }, function (err) { assert.ifError(err); done(); @@ -1164,7 +1210,7 @@ describe('Topic\'s', function () { }); it('should return empty array if query is falsy', function (done) { - socketTopics.autocompleteTags({uid: adminUid}, {query: ''}, function (err, data) { + socketTopics.autocompleteTags({ uid: adminUid }, { query: '' }, function (err, data) { assert.ifError(err); assert.deepEqual([], data); done(); @@ -1172,7 +1218,7 @@ describe('Topic\'s', function () { }); it('should autocomplete tags', function (done) { - socketTopics.autocompleteTags({uid: adminUid}, {query: 'p'}, function (err, data) { + socketTopics.autocompleteTags({ uid: adminUid }, { query: 'p' }, function (err, data) { assert.ifError(err); ['php', 'psql', 'python'].forEach(function (tag) { assert.notEqual(data.indexOf(tag), -1); @@ -1182,7 +1228,7 @@ describe('Topic\'s', function () { }); it('should return empty array if query is falsy', function (done) { - socketTopics.searchTags({uid: adminUid}, {query: ''}, function (err, data) { + socketTopics.searchTags({ uid: adminUid }, { query: '' }, function (err, data) { assert.ifError(err); assert.deepEqual([], data); done(); @@ -1190,7 +1236,7 @@ describe('Topic\'s', function () { }); it('should search tags', function (done) { - socketTopics.searchTags({uid: adminUid}, {query: 'no'}, function (err, data) { + socketTopics.searchTags({ uid: adminUid }, { query: 'no' }, function (err, data) { assert.ifError(err); ['nodebb', 'nodejs', 'nosql'].forEach(function (tag) { assert.notEqual(data.indexOf(tag), -1); @@ -1200,7 +1246,7 @@ describe('Topic\'s', function () { }); it('should return empty array if query is falsy', function (done) { - socketTopics.searchAndLoadTags({uid: adminUid}, {query: ''}, function (err, data) { + socketTopics.searchAndLoadTags({ uid: adminUid }, { query: '' }, function (err, data) { assert.ifError(err); assert.equal(data.matchCount, 0); assert.equal(data.pageCount, 1); @@ -1210,14 +1256,14 @@ describe('Topic\'s', function () { }); it('should search and load tags', function (done) { - socketTopics.searchAndLoadTags({uid: adminUid}, {query: 'no'}, function (err, data) { + socketTopics.searchAndLoadTags({ uid: adminUid }, { query: 'no' }, function (err, data) { assert.ifError(err); assert.equal(data.matchCount, 3); assert.equal(data.pageCount, 1); var tagData = [ { value: 'nodebb', color: '', bgColor: '', score: 3 }, { value: 'nodejs', color: '', bgColor: '', score: 1 }, - { value: 'nosql', color: '', bgColor: '', score: 1 } + { value: 'nosql', color: '', bgColor: '', score: 1 }, ]; assert.deepEqual(data.tags, tagData); @@ -1226,14 +1272,14 @@ describe('Topic\'s', function () { }); it('should return error if data is invalid', function (done) { - socketTopics.loadMoreTags({uid: adminUid}, {after: 'asd'}, function (err) { + socketTopics.loadMoreTags({ uid: adminUid }, { after: 'asd' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should load more tags', function (done) { - socketTopics.loadMoreTags({uid: adminUid}, {after: 0}, function (err, data) { + socketTopics.loadMoreTags({ uid: adminUid }, { after: 0 }, function (err, data) { assert.ifError(err); assert(Array.isArray(data.tags)); assert.equal(data.nextStart, 100); @@ -1242,28 +1288,28 @@ describe('Topic\'s', function () { }); it('should error if data is invalid', function (done) { - socketAdmin.tags.create({uid: adminUid}, null, function (err) { + socketAdmin.tags.create({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if tag is invalid', function (done) { - socketAdmin.tags.create({uid: adminUid}, {tag: ''}, function (err) { + socketAdmin.tags.create({ uid: adminUid }, { tag: '' }, function (err) { assert.equal(err.message, '[[error:invalid-tag]]'); done(); }); }); it('should error if tag is too short', function (done) { - socketAdmin.tags.create({uid: adminUid}, {tag: 'as'}, function (err) { + socketAdmin.tags.create({ uid: adminUid }, { tag: 'as' }, function (err) { assert.equal(err.message, '[[error:tag-too-short]]'); done(); }); }); it('should create empty tag', function (done) { - socketAdmin.tags.create({uid: adminUid}, {tag: 'emptytag'}, function (err) { + socketAdmin.tags.create({ uid: adminUid }, { tag: 'emptytag' }, function (err) { assert.ifError(err); db.sortedSetScore('tags:topic:count', 'emptytag', function (err, score) { assert.ifError(err); @@ -1274,7 +1320,7 @@ describe('Topic\'s', function () { }); it('should do nothing if tag exists', function (done) { - socketAdmin.tags.create({uid: adminUid}, {tag: 'emptytag'}, function (err) { + socketAdmin.tags.create({ uid: adminUid }, { tag: 'emptytag' }, function (err) { assert.ifError(err); db.sortedSetScore('tags:topic:count', 'emptytag', function (err, score) { assert.ifError(err); @@ -1285,16 +1331,16 @@ describe('Topic\'s', function () { }); it('should error if data is invalid', function (done) { - socketAdmin.tags.update({uid: adminUid}, null, function (err) { + socketAdmin.tags.update({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error if data.tag is invalid', function (done) { - socketAdmin.tags.update({uid: adminUid}, { + socketAdmin.tags.update({ uid: adminUid }, { bgColor: '#ff0000', - color: '#00ff00' + color: '#00ff00', }, function (err) { assert.equal(err.message, '[[error:invalid-tag]]'); done(); @@ -1302,10 +1348,10 @@ describe('Topic\'s', function () { }); it('should update tag', function (done) { - socketAdmin.tags.update({uid: adminUid}, { + socketAdmin.tags.update({ uid: adminUid }, { tag: 'emptytag', bgColor: '#ff0000', - color: '#00ff00' + color: '#00ff00', }, function (err) { assert.ifError(err); db.getObject('tag:emptytag', function (err, data) { @@ -1321,7 +1367,7 @@ describe('Topic\'s', function () { var meta = require('../src/meta'); meta.config.maximumRelatedTopics = 2; var topicData = { - tags: [{value: 'javascript'}] + tags: [{ value: 'javascript' }], }; topics.getRelatedTopics(topicData, 0, function (err, data) { assert.ifError(err); @@ -1333,23 +1379,23 @@ describe('Topic\'s', function () { }); it('should return error with invalid data', function (done) { - socketAdmin.tags.deleteTags({uid: adminUid}, null, function (err) { + socketAdmin.tags.deleteTags({ uid: adminUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should do nothing if arrays is empty', function (done) { - socketAdmin.tags.deleteTags({uid: adminUid}, {tags: []}, function (err) { + socketAdmin.tags.deleteTags({ uid: adminUid }, { tags: [] }, function (err) { assert.ifError(err); done(); }); }); it('should delete tags', function (done) { - socketAdmin.tags.create({uid: adminUid}, {tag: 'emptytag2'}, function (err) { + socketAdmin.tags.create({ uid: adminUid }, { tag: 'emptytag2' }, function (err) { assert.ifError(err); - socketAdmin.tags.deleteTags({uid: adminUid}, {tags: ['emptytag', 'emptytag2', 'nodebb', 'nodejs']}, function (err) { + socketAdmin.tags.deleteTags({ uid: adminUid }, { tags: ['emptytag', 'emptytag2', 'nodebb', 'nodejs'] }, function (err) { assert.ifError(err); db.getObjects(['tag:emptytag', 'tag:emptytag2'], function (err, data) { assert.ifError(err); @@ -1378,12 +1424,12 @@ describe('Topic\'s', function () { var tid; var followerUid; before(function (done) { - User.create({username: 'follower'}, function (err, uid) { + User.create({ username: 'follower' }, function (err, uid) { if (err) { return done(err); } followerUid = uid; - topics.post({uid: adminUid, title: 'topic title', content: 'some content', cid: topic.categoryId}, function (err, result) { + topics.post({ uid: adminUid, title: 'topic title', content: 'some content', cid: topic.categoryId }, function (err, result) { if (err) { return done(err); } @@ -1393,8 +1439,15 @@ describe('Topic\'s', function () { }); }); + it('should error if not logged in', function (done) { + socketTopics.changeWatching({ uid: 0 }, { tid: tid, type: 'ignore' }, function (err) { + assert.equal(err.message, '[[error:not-logged-in]]'); + done(); + }); + }); + it('should filter ignoring uids', function (done) { - socketTopics.changeWatching({uid: followerUid}, {tid: tid, type: 'ignore'}, function (err) { + socketTopics.changeWatching({ uid: followerUid }, { tid: tid, type: 'ignore' }, function (err) { assert.ifError(err); topics.filterIgnoringUids(tid, [adminUid, followerUid], function (err, uids) { assert.ifError(err); @@ -1406,14 +1459,14 @@ describe('Topic\'s', function () { }); it('should error with invalid data', function (done) { - socketTopics.changeWatching({uid: followerUid}, {}, function (err) { + socketTopics.changeWatching({ uid: followerUid }, {}, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should error with invalid type', function (done) { - socketTopics.changeWatching({uid: followerUid}, {tid: tid, type: 'derp'}, function (err) { + socketTopics.changeWatching({ uid: followerUid }, { tid: tid, type: 'derp' }, function (err) { assert.equal(err.message, '[[error:invalid-command]]'); done(); }); @@ -1423,7 +1476,7 @@ describe('Topic\'s', function () { topics.toggleFollow(tid, followerUid, function (err, isFollowing) { assert.ifError(err); assert(isFollowing); - topics.isFollowing([tid], followerUid, function (err, isFollowing) { + socketTopics.isFollowed({ uid: followerUid }, tid, function (err, isFollowing) { assert.ifError(err); assert(isFollowing); done(); @@ -1432,6 +1485,44 @@ describe('Topic\'s', function () { }); }); + describe('topics search', function () { + it('should error with invalid data', function (done) { + socketTopics.search({ uid: adminUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should error if no search plugin', function (done) { + socketTopics.search({ uid: adminUid }, { tid: topic.tid, term: 'test' }, function (err) { + assert.equal(err.message, '[[error:no-plugins-available]]'); + done(); + }); + }); + + it('should return results', function (done) { + var plugins = require('../src/plugins'); + plugins.registerHook('myTestPlugin', { + hook: 'filter:topic.search', + method: function (data, callback) { + callback(null, [1, 2, 3]); + }, + }); + socketTopics.search({ uid: adminUid }, { tid: topic.tid, term: 'test' }, function (err, results) { + assert.ifError(err); + assert.deepEqual(results, [1, 2, 3]); + done(); + }); + }); + }); + + it('should check if user is moderator', function (done) { + socketTopics.isModerator({ uid: adminUid }, topic.tid, function (err, isModerator) { + assert.ifError(err); + assert(!isModerator); + done(); + }); + }); after(function (done) { db.emptydb(done); diff --git a/test/translator.js b/test/translator.js index 8198814164..196d5ce56f 100644 --- a/test/translator.js +++ b/test/translator.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var shim = require('../public/src/modules/translator.js'); @@ -119,7 +119,7 @@ describe('new Translator(language)', function () { var translator = Translator.create('en-GB'); var title = 'Test 1\\, 2\\, 3 % salmon'; - var key = "[[topic:composer.replying_to, " + title + "]]"; + var key = '[[topic:composer.replying_to, ' + title + ']]'; return translator.translate(key).then(function (translated) { assert.strictEqual(translated, 'Replying to Test 1, 2, 3 % salmon'); }); @@ -173,7 +173,7 @@ describe('Translator.create()', function () { describe('Translator modules', function () { it('should work before registered', function () { var translator = Translator.create(); - + Translator.registerModule('test-custom-integer-format', function (lang) { return function (key, args) { var num = parseInt(args[0], 10) || 0; diff --git a/test/uploads.js b/test/uploads.js index 7ac1b595a2..0daf0407b9 100644 --- a/test/uploads.js +++ b/test/uploads.js @@ -16,7 +16,6 @@ var helpers = require('./helpers'); describe('Upload Controllers', function () { - var tid; var cid; var pid; @@ -28,15 +27,15 @@ describe('Upload Controllers', function () { category: function (next) { categories.create({ name: 'Test Category', - description: 'Test category created by testing script' + description: 'Test category created by testing script', }, next); }, adminUid: function (next) { - user.create({username: 'admin', password: 'barbar'}, next); + user.create({ username: 'admin', password: 'barbar' }, next); }, regularUid: function (next) { - user.create({username: 'regular', password: 'zugzug'}, next); - } + user.create({ username: 'regular', password: 'zugzug' }, next); + }, }, function (err, results) { if (err) { return done(err); @@ -45,7 +44,7 @@ describe('Upload Controllers', function () { regularUid = results.regularUid; cid = results.category.cid; - topics.post({uid: adminUid, title: 'test topic title', content: 'test topic content', cid: results.category.cid}, function (err, result) { + topics.post({ uid: adminUid, title: 'test topic title', content: 'test topic content', cid: results.category.cid }, function (err, result) { tid = result.topicData.tid; pid = result.postData.pid; done(err); @@ -78,7 +77,7 @@ describe('Upload Controllers', function () { }); it('should upload an image to a post', function (done) { - helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), {cid: cid}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), { cid: cid }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body)); @@ -91,7 +90,7 @@ describe('Upload Controllers', function () { it('should resize and upload an image to a post', function (done) { var oldValue = meta.config.maximumImageWidth; meta.config.maximumImageWidth = 10; - helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), {cid: cid}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), { cid: cid }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body)); @@ -105,7 +104,7 @@ describe('Upload Controllers', function () { it('should upload a file to a post', function (done) { meta.config.allowFileUploads = 1; - helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/503.html'), {cid: cid}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/503.html'), { cid: cid }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body)); @@ -145,7 +144,6 @@ describe('Upload Controllers', function () { done(); }); }); - }); @@ -167,17 +165,17 @@ describe('Upload Controllers', function () { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body)); - assert.equal(body[0].url, '/assets/uploads/system/site-logo.png'); + assert.equal(body[0].url, nconf.get('relative_path') + '/assets/uploads/system/site-logo.png'); done(); }); }); it('should upload category image', function (done) { - helpers.uploadFile(nconf.get('url') + '/api/admin/category/uploadpicture', path.join(__dirname, '../test/files/test.png'), {params: JSON.stringify({cid: cid})}, jar, csrf_token, function (err, res, body) { + helpers.uploadFile(nconf.get('url') + '/api/admin/category/uploadpicture', path.join(__dirname, '../test/files/test.png'), { params: JSON.stringify({ cid: cid }) }, jar, csrf_token, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body)); - assert.equal(body[0].url, '/assets/uploads/category/category-1.png'); + assert.equal(body[0].url, nconf.get('relative_path') + '/assets/uploads/category/category-1.png'); done(); }); }); @@ -204,8 +202,6 @@ describe('Upload Controllers', function () { }); - - after(function (done) { db.emptydb(done); }); diff --git a/test/user.js b/test/user.js index 70334d04e1..776dbf28de 100644 --- a/test/user.js +++ b/test/user.js @@ -23,13 +23,12 @@ describe('User', function () { var testCid; before(function (done) { - groups.resetCache(); Categories.create({ name: 'Test Category', description: 'A test', - order: 1 + order: 1, }, function (err, categoryObj) { if (err) { return done(err); @@ -46,14 +45,14 @@ describe('User', function () { fullname: 'John Smith McNamara', password: 'swordfish', email: 'john@example.com', - callback: undefined + callback: undefined, }; }); describe('.create(), when created', function () { it('should be created properly', function (done) { - User.create({username: userData.username, password: userData.password, email: userData.email}, function (error,userId) { + User.create({ username: userData.username, password: userData.password, email: userData.email }, function (error, userId) { assert.equal(error, null, 'was created with error'); assert.ok(userId); @@ -63,7 +62,7 @@ describe('User', function () { }); it('should have a valid email, if using an email', function (done) { - User.create({username: userData.username, password: userData.password, email: 'fakeMail'},function (err) { + User.create({ username: userData.username, password: userData.password, email: 'fakeMail' }, function (err) { assert(err); assert.equal(err.message, '[[error:invalid-email]]'); done(); @@ -109,14 +108,14 @@ describe('User', function () { uid: testUid, title: 'Topic 1', content: 'lorem ipsum', - cid: testCid + cid: testCid, }), async.apply(Topics.post, { uid: testUid, title: 'Topic 2', content: 'lorem ipsum', - cid: testCid - }) + cid: testCid, + }), ], function (err) { assert(err); done(); @@ -129,7 +128,7 @@ describe('User', function () { uid: testUid, title: 'Topic 3', content: 'lorem ipsum', - cid: testCid + cid: testCid, }, function (err) { assert.ifError(err); done(); @@ -146,7 +145,7 @@ describe('User', function () { uid: testUid, title: 'Topic 4', content: 'lorem ipsum', - cid: testCid + cid: testCid, }, function (err) { assert(err); done(); @@ -156,14 +155,14 @@ describe('User', function () { it('should not error if a non-newbie user posts if the last post time is 10 < 30 seconds', function (done) { User.setUserFields(testUid, { - lastposttime: +new Date() - (20 * 1000), - reputation: 10 + lastposttime: +new Date() - (20 * 1000), + reputation: 10, }, function () { Topics.post({ uid: testUid, title: 'Topic 5', content: 'lorem ipsum', - cid: testCid + cid: testCid, }, function (err) { assert.ifError(err); done(); @@ -175,7 +174,7 @@ describe('User', function () { describe('.search()', function () { var socketUser = require('../src/socket.io/user'); it('should return an object containing an array of matching users', function (done) { - User.search({query: 'john'}, function (err, searchData) { + User.search({ query: 'john' }, function (err, searchData) { assert.ifError(err); assert.equal(Array.isArray(searchData.users) && searchData.users.length > 0, true); assert.equal(searchData.users[0].username, 'John Smith'); @@ -184,7 +183,7 @@ describe('User', function () { }); it('should search user', function (done) { - socketUser.search({uid: testUid}, {query: 'john'}, function (err, searchData) { + socketUser.search({ uid: testUid }, { query: 'john' }, function (err, searchData) { assert.ifError(err); assert.equal(searchData.users[0].username, 'John Smith'); done(); @@ -193,7 +192,7 @@ describe('User', function () { it('should error for guest', function (done) { Meta.config.allowGuestUserSearching = 0; - socketUser.search({uid: 0}, {query: 'john'}, function (err) { + socketUser.search({ uid: 0 }, { query: 'john' }, function (err) { assert.equal(err.message, '[[error:not-logged-in]]'); Meta.config.allowGuestUserSearching = 1; done(); @@ -201,7 +200,7 @@ describe('User', function () { }); it('should error with invalid data', function (done) { - socketUser.search({uid: testUid}, null, function (err) { + socketUser.search({ uid: testUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -211,7 +210,7 @@ describe('User', function () { describe('.delete()', function () { var uid; before(function (done) { - User.create({username: 'usertodelete', password: '123456', email: 'delete@me.com'}, function (err, newUid) { + User.create({ username: 'usertodelete', password: '123456', email: 'delete@me.com' }, function (err, newUid) { assert.ifError(err); uid = newUid; done(); @@ -231,10 +230,10 @@ describe('User', function () { }); describe('passwordReset', function () { - var uid, - code; + var uid; + var code; before(function (done) { - User.create({username: 'resetuser', password: '123456', email: 'reset@me.com'}, function (err, newUid) { + User.create({ username: 'resetuser', password: '123456', email: 'reset@me.com' }, function (err, newUid) { assert.ifError(err); uid = newUid; done(); @@ -293,7 +292,6 @@ describe('User', function () { }); describe('hash methods', function () { - it('should return uid from email', function (done) { User.getUidByEmail('john@example.com', function (err, uid) { assert.ifError(err); @@ -345,7 +343,7 @@ describe('User', function () { var io; before(function (done) { - User.create({username: 'updateprofile', email: 'update@me.com', password: '123456'}, function (err, newUid) { + User.create({ username: 'updateprofile', email: 'update@me.com', password: '123456' }, function (err, newUid) { assert.ifError(err); uid = newUid; helpers.loginUser('updateprofile', '123456', function (err, _jar, _io) { @@ -365,7 +363,7 @@ describe('User', function () { }); it('should return error if data is missing uid', function (done) { - io.emit('user.updateProfile', {username: 'bip', email: 'bop'}, function (err) { + io.emit('user.updateProfile', { username: 'bip', email: 'bop' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -381,14 +379,14 @@ describe('User', function () { location: 'izmir', groupTitle: 'testGroup', birthday: '01/01/1980', - signature: 'nodebb is good' + signature: 'nodebb is good', }; io.emit('user.updateProfile', data, function (err, result) { assert.ifError(err); - assert.equal(result.username, 'updatedUserName'); - assert.equal(result.userslug, 'updatedusername'); - assert.equal(result.email, 'updatedEmail@me.com'); + assert.equal(result.username, 'updatedUserName'); + assert.equal(result.userslug, 'updatedusername'); + assert.equal(result.email, 'updatedEmail@me.com'); db.getObject('user:' + uid, function (err, userData) { assert.ifError(err); @@ -401,19 +399,22 @@ describe('User', function () { }); it('should change a user\'s password', function (done) { - this.timeout(20000); - io.emit('user.changePassword', {uid: uid, newPassword: '654321', currentPassword: '123456'}, function (err) { + var socketUser = require('../src/socket.io/user'); + User.create({ username: 'changepassword', password: '123456' }, function (err, uid) { assert.ifError(err); - User.isPasswordCorrect(uid, '654321', function (err, correct) { + socketUser.changePassword({ uid: uid }, { uid: uid, newPassword: '654321', currentPassword: '123456' }, function (err) { assert.ifError(err); - assert(correct); - done(); + User.isPasswordCorrect(uid, '654321', function (err, correct) { + assert.ifError(err); + assert(correct); + done(); + }); }); }); }); it('should change username', function (done) { - io.emit('user.changeUsernameEmail', {uid: uid, username: 'updatedAgain', password: '654321'}, function (err) { + io.emit('user.changeUsernameEmail', { uid: uid, username: 'updatedAgain', password: '123456' }, function (err) { assert.ifError(err); db.getObjectField('user:' + uid, 'username', function (err, username) { assert.ifError(err); @@ -424,7 +425,7 @@ describe('User', function () { }); it('should change email', function (done) { - io.emit('user.changeUsernameEmail', {uid: uid, email: 'updatedAgain@me.com', password: '654321'}, function (err) { + io.emit('user.changeUsernameEmail', { uid: uid, email: 'updatedAgain@me.com', password: '123456' }, function (err) { assert.ifError(err); db.getObjectField('user:' + uid, 'email', function (err, email) { assert.ifError(err); @@ -437,7 +438,7 @@ describe('User', function () { it('should update cover image', function (done) { var imageData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAAACXBIWXMAAC4jAAAuIwF4pT92AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAACcJJREFUeNqMl9tvnNV6xn/f+s5z8DCeg88Zj+NYdhJH4KShFoJAIkzVphLVJnsDaiV6gUKaC2qQUFVATbnoValAakuQYKMqBKUUJCgI9XBBSmOROMqGoCStHbA9sWM7nrFn/I3n9B17kcwoabfarj9gvet53+d9nmdJAwMDAAgh8DyPtbU1XNfFMAwkScK2bTzPw/M8dF1/SAhxKAiCxxVF2aeqqqTr+q+Af+7o6Ch0d3f/69TU1KwkSRiGwbFjx3jmmWd47rnn+OGHH1BVFYX/5QRBkPQ87xeSJP22YRi/oapqStM0PM/D931kWSYIgnHf98cXFxepVqtomjZt2/Zf2bb990EQ4Pv+PXfeU1CSpGYhfN9/TgjxQTQaJQgCwuEwQRBQKpUwDAPTNPF9n0ajAYDv+8zPzzM+Pr6/Wq2eqdVqfxOJRA6Zpnn57hrivyEC0IQQZ4Mg+MAwDCKRCJIkUa/XEUIQi8XQNI1QKIQkSQghUBQFIQSmaTI7OwtAuVxOTE9Pfzc9Pf27lUqlBUgulUoUi0VKpRKqqg4EQfAfiqLsDIfDAC0E4XCYaDSKEALXdalUKvfM1/d9hBBYlkUul2N4eJi3335bcl33mW+++aaUz+cvSJKE8uKLL6JpGo7j8Omnn/7d+vp6sr+/HyEEjuMgyzKu6yJJEsViEVVV8TyPjY2NVisV5fZkTNMkkUhw8+ZN6vU6Kysr7Nmzh9OnT7/12GOPDS8sLByT7rQR4A9XV1d/+cILLzA9PU0kEmF4eBhFUTh//jyWZaHrOkII0uk0jUaDWq1GJpOhWCyysrLC1tYWnuehqir79+9H13W6urp48803+f7773n++ef/4G7S/H4ikUCSJNbX11trcuvWLcrlMrIs4zgODzzwABMTE/i+T7lcpq2tjUqlwubmJrZts7y8jBCCkZERGo0G2WyWkydPkkql6Onp+eMmwihwc3JyMvrWW2+RTCYBcF0XWZbRdZ3l5WX27NnD008/TSwWQ1VVyuVy63GhUIhEIkEqlcJxHCzLIhaLMTQ0xJkzZ7Btm3379lmS53kIIczZ2dnFsbGxRK1Wo729HQDP8zAMg5WVFXp7e5mcnKSzs5N8Po/rutTrdVzXbQmHrutEo1FM00RVVXp7e0kkEgRBwMWLF9F1vaxUq1UikUjtlVdeuV6pVBJ9fX3Ytn2bwrLMysoKXV1dTE5OkslksCwLTdMwDANVVdnY2CAIApLJJJFIBMdxiMfj7Nq1C1VViUajLQCvvvrqkhKJRJiZmfmdb7/99jeTySSyLLfWodFoEAqFOH78OLt37yaXy2GaJoqisLy8zNTUFFevXiUIAtrb29m5cyePPPJIa+cymQz1eh2A0dFRCoXCsgIwNTW1J5/P093dTbFYRJZlJEmiWq1y4MABxsbGqNVqhEIh6vU6QRBQLpcxDIPh4WE8z2NxcZFTp05x7tw5Xn755ZY6dXZ2tliZzWa/EwD1ev3RsbExxsfHSafTVCoVGo0Gqqqya9cuIpEIQgh832dtbY3FxUUA+vr62LZtG2NjYxw5coTDhw+ztLTEyZMnuXr1KoVC4R4d3bt375R84sQJEY/H/2Jubq7N9326urqwbZt6vY5pmhw5coS+vr4W9YvFIrdu3WJqagohBFeuXOHcuXOtue7evRtN01rtfO+991haWmJkZGQrkUi8JIC9iqL0BkFAIpFACMETTzxBV1cXiUSC7u5uHMfB8zyCIMA0TeLxONlsFlmW8X2fwcFBHMdhfn6eer1Oe3s7Dz30EBMTE1y6dImjR49y6tSppR07dqwrjuM8+OWXXzI0NMTly5e5du0aQ0NDTExMkMvlCIKAIAhaIh2LxQiHw0QiEfL5POl0mlqtRq1Wo6OjA8uykGWZdDrN0tISvb29vPPOOzz++OPk83lELpf7rXfffRfDMOjo6MBxHEqlEocOHWLHjh00Gg0kSULTNIS4bS6qqhKPxxkaGmJ4eJjR0VH279/PwMAA27dvJ5vN4vs+X331FR9//DGzs7OEQiE++eQTlPb29keuX7/OtWvXOH78ONVqlZs3b9LW1kYmk8F13dZeCiGQJAnXdRFCYBgGsiwjhMC2bQqFAkEQoOs6P/74Iw8++CCDg4Pous6xY8f47LPPkIIguDo2Nrbzxo0bfPjhh9i2zczMTHNvcF2XpsZalkWj0cB1Xe4o1O3YoCisra3x008/EY/H6erqAuDAgQNEIhGCIODQoUP/ubCwMCKAjx599FHW19f56KOP6OjooFgsks/niUajKIqCbds4joMQAiFESxxs226xd2Zmhng8Tl9fH67r0mg0sG2bbDZLpVIhl8vd5gHwtysrKy8Dcdd1mZubo6enh1gsRrVabZlrk6VND/R9n3q9TqVSQdd1QqEQi4uLnD9/nlKpxODgIHv37gXAcRyCICiFQiHEzp07i1988cUfKYpCIpHANE22b9/eUhNFUVotDIKghc7zPCzLolKpsLW1RVtbG0EQ4DgOmqbR09NDM1qUSiWAPwdQ7ujjmf7+/kQymfxrSZJQVZWtra2WG+i63iKH53m4rku1WqVcLmNZFu3t7S2x7+/vJ51O89prr7VYfenSpcPAP1UqFeSHH36YeDxOKpW6eP/9988Bv9d09nw+T7VapVKptJjZnE2tVmNtbY1cLke5XGZra4vNzU16enp49tlnGRgYaD7iTxqNxgexWIzDhw+jNEPQHV87NT8/f+PChQtnR0ZGqFarrUVuOsDds2u2b2FhgVQqRSQSYWFhgStXrtDf308ymcwBf3nw4EEOHjx4O5c2lURVVRzHYXp6+t8uX7785IULFz7LZDLous59991HOBy+h31N9xgdHSWTyVCtVhkaGmLfvn1MT08zPz/PzMzM6c8//9xr+uE9QViWZer1OhsbGxiG8fns7OzPc7ncx729vXR3d1OpVNi2bRuhUAhZljEMA9/3sW0bVVVZWlri4sWLjI+P8/rrr/P111/z5JNPXrIs69cn76ZeGoaBpmm0tbX9Q6FQeHhubu7fC4UCkUiE1dVVstks8Xgc0zSRZZlGo9ESAdM02djYoNFo8MYbb2BZ1mYoFOKuZPjr/xZBEHCHred83x/b3Nz8l/X19aRlWWxsbNDZ2cnw8DDhcBjf96lWq/T09HD06FGeeuopXnrpJc6ePUs6nb4hhPi/C959ZFn+TtO0lG3bJ0ql0p85jsPW1haFQoG2tjYkSWpF/Uwmw9raGu+//z7A977vX2+GrP93wSZiTdNOGIbxy3K5/DPHcfYXCoVe27Yzpmm2m6bppVKp/Orqqnv69OmoZVn/mEwm/9TzvP9x138NAMpJ4VFTBr6SAAAAAElFTkSuQmCC'; var position = '50.0301% 19.2464%'; - io.emit('user.updateCover', {uid: uid, imageData: imageData, position: position}, function (err, result) { + io.emit('user.updateCover', { uid: uid, imageData: imageData, position: position }, function (err, result) { assert.ifError(err); assert(result.url); db.getObjectFields('user:' + uid, ['cover:url', 'cover:position'], function (err, data) { @@ -452,7 +453,7 @@ describe('User', function () { it('should upload cropped profile picture', function (done) { var imageData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAAACXBIWXMAAC4jAAAuIwF4pT92AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAACcJJREFUeNqMl9tvnNV6xn/f+s5z8DCeg88Zj+NYdhJH4KShFoJAIkzVphLVJnsDaiV6gUKaC2qQUFVATbnoValAakuQYKMqBKUUJCgI9XBBSmOROMqGoCStHbA9sWM7nrFn/I3n9B17kcwoabfarj9gvet53+d9nmdJAwMDAAgh8DyPtbU1XNfFMAwkScK2bTzPw/M8dF1/SAhxKAiCxxVF2aeqqqTr+q+Af+7o6Ch0d3f/69TU1KwkSRiGwbFjx3jmmWd47rnn+OGHH1BVFYX/5QRBkPQ87xeSJP22YRi/oapqStM0PM/D931kWSYIgnHf98cXFxepVqtomjZt2/Zf2bb990EQ4Pv+PXfeU1CSpGYhfN9/TgjxQTQaJQgCwuEwQRBQKpUwDAPTNPF9n0ajAYDv+8zPzzM+Pr6/Wq2eqdVqfxOJRA6Zpnn57hrivyEC0IQQZ4Mg+MAwDCKRCJIkUa/XEUIQi8XQNI1QKIQkSQghUBQFIQSmaTI7OwtAuVxOTE9Pfzc9Pf27lUqlBUgulUoUi0VKpRKqqg4EQfAfiqLsDIfDAC0E4XCYaDSKEALXdalUKvfM1/d9hBBYlkUul2N4eJi3335bcl33mW+++aaUz+cvSJKE8uKLL6JpGo7j8Omnn/7d+vp6sr+/HyEEjuMgyzKu6yJJEsViEVVV8TyPjY2NVisV5fZkTNMkkUhw8+ZN6vU6Kysr7Nmzh9OnT7/12GOPDS8sLByT7rQR4A9XV1d/+cILLzA9PU0kEmF4eBhFUTh//jyWZaHrOkII0uk0jUaDWq1GJpOhWCyysrLC1tYWnuehqir79+9H13W6urp48803+f7773n++ef/4G7S/H4ikUCSJNbX11trcuvWLcrlMrIs4zgODzzwABMTE/i+T7lcpq2tjUqlwubmJrZts7y8jBCCkZERGo0G2WyWkydPkkql6Onp+eMmwihwc3JyMvrWW2+RTCYBcF0XWZbRdZ3l5WX27NnD008/TSwWQ1VVyuVy63GhUIhEIkEqlcJxHCzLIhaLMTQ0xJkzZ7Btm3379lmS53kIIczZ2dnFsbGxRK1Wo729HQDP8zAMg5WVFXp7e5mcnKSzs5N8Po/rutTrdVzXbQmHrutEo1FM00RVVXp7e0kkEgRBwMWLF9F1vaxUq1UikUjtlVdeuV6pVBJ9fX3Ytn2bwrLMysoKXV1dTE5OkslksCwLTdMwDANVVdnY2CAIApLJJJFIBMdxiMfj7Nq1C1VViUajLQCvvvrqkhKJRJiZmfmdb7/99jeTySSyLLfWodFoEAqFOH78OLt37yaXy2GaJoqisLy8zNTUFFevXiUIAtrb29m5cyePPPJIa+cymQz1eh2A0dFRCoXCsgIwNTW1J5/P093dTbFYRJZlJEmiWq1y4MABxsbGqNVqhEIh6vU6QRBQLpcxDIPh4WE8z2NxcZFTp05x7tw5Xn755ZY6dXZ2tliZzWa/EwD1ev3RsbExxsfHSafTVCoVGo0Gqqqya9cuIpEIQgh832dtbY3FxUUA+vr62LZtG2NjYxw5coTDhw+ztLTEyZMnuXr1KoVC4R4d3bt375R84sQJEY/H/2Jubq7N9326urqwbZt6vY5pmhw5coS+vr4W9YvFIrdu3WJqagohBFeuXOHcuXOtue7evRtN01rtfO+991haWmJkZGQrkUi8JIC9iqL0BkFAIpFACMETTzxBV1cXiUSC7u5uHMfB8zyCIMA0TeLxONlsFlmW8X2fwcFBHMdhfn6eer1Oe3s7Dz30EBMTE1y6dImjR49y6tSppR07dqwrjuM8+OWXXzI0NMTly5e5du0aQ0NDTExMkMvlCIKAIAhaIh2LxQiHw0QiEfL5POl0mlqtRq1Wo6OjA8uykGWZdDrN0tISvb29vPPOOzz++OPk83lELpf7rXfffRfDMOjo6MBxHEqlEocOHWLHjh00Gg0kSULTNIS4bS6qqhKPxxkaGmJ4eJjR0VH279/PwMAA27dvJ5vN4vs+X331FR9//DGzs7OEQiE++eQTlPb29keuX7/OtWvXOH78ONVqlZs3b9LW1kYmk8F13dZeCiGQJAnXdRFCYBgGsiwjhMC2bQqFAkEQoOs6P/74Iw8++CCDg4Pous6xY8f47LPPkIIguDo2Nrbzxo0bfPjhh9i2zczMTHNvcF2XpsZalkWj0cB1Xe4o1O3YoCisra3x008/EY/H6erqAuDAgQNEIhGCIODQoUP/ubCwMCKAjx599FHW19f56KOP6OjooFgsks/niUajKIqCbds4joMQAiFESxxs226xd2Zmhng8Tl9fH67r0mg0sG2bbDZLpVIhl8vd5gHwtysrKy8Dcdd1mZubo6enh1gsRrVabZlrk6VND/R9n3q9TqVSQdd1QqEQi4uLnD9/nlKpxODgIHv37gXAcRyCICiFQiHEzp07i1988cUfKYpCIpHANE22b9/eUhNFUVotDIKghc7zPCzLolKpsLW1RVtbG0EQ4DgOmqbR09NDM1qUSiWAPwdQ7ujjmf7+/kQymfxrSZJQVZWtra2WG+i63iKH53m4rku1WqVcLmNZFu3t7S2x7+/vJ51O89prr7VYfenSpcPAP1UqFeSHH36YeDxOKpW6eP/9988Bv9d09nw+T7VapVKptJjZnE2tVmNtbY1cLke5XGZra4vNzU16enp49tlnGRgYaD7iTxqNxgexWIzDhw+jNEPQHV87NT8/f+PChQtnR0ZGqFarrUVuOsDds2u2b2FhgVQqRSQSYWFhgStXrtDf308ymcwBf3nw4EEOHjx4O5c2lURVVRzHYXp6+t8uX7785IULFz7LZDLous59991HOBy+h31N9xgdHSWTyVCtVhkaGmLfvn1MT08zPz/PzMzM6c8//9xr+uE9QViWZer1OhsbGxiG8fns7OzPc7ncx729vXR3d1OpVNi2bRuhUAhZljEMA9/3sW0bVVVZWlri4sWLjI+P8/rrr/P111/z5JNPXrIs69cn76ZeGoaBpmm0tbX9Q6FQeHhubu7fC4UCkUiE1dVVstks8Xgc0zSRZZlGo9ESAdM02djYoNFo8MYbb2BZ1mYoFOKuZPjr/xZBEHCHred83x/b3Nz8l/X19aRlWWxsbNDZ2cnw8DDhcBjf96lWq/T09HD06FGeeuopXnrpJc6ePUs6nb4hhPi/C959ZFn+TtO0lG3bJ0ql0p85jsPW1haFQoG2tjYkSWpF/Uwmw9raGu+//z7A977vX2+GrP93wSZiTdNOGIbxy3K5/DPHcfYXCoVe27Yzpmm2m6bppVKp/Orqqnv69OmoZVn/mEwm/9TzvP9x138NAMpJ4VFTBr6SAAAAAElFTkSuQmCC'; var socketUser = require('../src/socket.io/user'); - socketUser.uploadCroppedPicture({uid: uid}, {uid: uid, imageData: imageData}, function (err, result) { + socketUser.uploadCroppedPicture({ uid: uid }, { uid: uid, imageData: imageData }, function (err, result) { assert.ifError(err); assert(result.url); db.getObjectFields('user:' + uid, ['uploadedpicture', 'picture'], function (err, data) { @@ -465,7 +466,7 @@ describe('User', function () { }); it('should remove cover image', function (done) { - io.emit('user.removeCover', {uid: uid}, function (err) { + io.emit('user.removeCover', { uid: uid }, function (err) { assert.ifError(err); db.getObjectField('user:' + uid, 'cover:url', function (err, url) { assert.ifError(err); @@ -500,7 +501,7 @@ describe('User', function () { }); it('should change user picture', function (done) { - io.emit('user.changePicture', {type: 'default', uid: uid}, function (err) { + io.emit('user.changePicture', { type: 'default', uid: uid }, function (err) { assert.ifError(err); User.getUserField(uid, 'picture', function (err, picture) { assert.ifError(err); @@ -513,21 +514,23 @@ describe('User', function () { it('should upload profile picture', function (done) { helpers.copyFile( path.join(nconf.get('base_dir'), 'test/files/test.png'), - path.join(nconf.get('base_dir'), 'test/files/test_copy.png'), function (err) { - assert.ifError(err); - var picture = { - path: path.join(nconf.get('base_dir'), 'test/files/test_copy.png'), - size: 7189, - name: 'test_copy.png', - type: 'image/png' - }; - User.uploadPicture(uid, picture, function (err, uploadedPicture) { + path.join(nconf.get('base_dir'), 'test/files/test_copy.png'), + function (err) { assert.ifError(err); - assert.equal(uploadedPicture.url, '/assets/uploads/profile/' + uid + '-profileavatar.png'); - assert.equal(uploadedPicture.path, path.join(nconf.get('base_dir'), 'public', 'uploads', 'profile', uid + '-profileavatar.png')); - done(); - }); - }); + var picture = { + path: path.join(nconf.get('base_dir'), 'test/files/test_copy.png'), + size: 7189, + name: 'test_copy.png', + type: 'image/png', + }; + User.uploadPicture(uid, picture, function (err, uploadedPicture) { + assert.ifError(err); + assert.equal(uploadedPicture.url, '/assets/uploads/profile/' + uid + '-profileavatar.png'); + assert.equal(uploadedPicture.path, path.join(nconf.get('base_dir'), 'public', 'uploads', 'profile', uid + '-profileavatar.png')); + done(); + }); + } + ); }); it('should return error if profile image uploads disabled', function (done) { @@ -536,7 +539,7 @@ describe('User', function () { path: path.join(nconf.get('base_dir'), 'test/files/test.png'), size: 7189, name: 'test.png', - type: 'image/png' + type: 'image/png', }; User.uploadPicture(uid, picture, function (err) { assert.equal(err.message, '[[error:profile-image-uploads-disabled]]'); @@ -550,7 +553,7 @@ describe('User', function () { path: path.join(nconf.get('base_dir'), 'test/files/test.png'), size: 265000, name: 'test.png', - type: 'image/png' + type: 'image/png', }; User.uploadPicture(uid, picture, function (err) { assert.equal(err.message, '[[error:file-too-big, 256]]'); @@ -562,7 +565,7 @@ describe('User', function () { var picture = { path: path.join(nconf.get('base_dir'), 'test/files/test.png'), size: 7189, - name: 'test' + name: 'test', }; User.uploadPicture(uid, picture, function (err) { assert.equal(err.message, '[[error:invalid-image-extension]]'); @@ -585,7 +588,7 @@ describe('User', function () { callback(null, data); } - plugins.registerHook('test-plugin', {hook: 'filter:uploadImage', method: filterMethod}); + plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); User.uploadFromUrl(uid, url, function (err) { assert.equal(err.message, '[[error:invalid-image-extension]]'); @@ -601,7 +604,7 @@ describe('User', function () { callback(null, data); } - plugins.registerHook('test-plugin', {hook: 'filter:uploadImage', method: filterMethod}); + plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); User.uploadFromUrl(uid, url, function (err) { assert.equal(err.message, '[[error:file-too-big, ' + meta.config.maximumProfileImageSize + ']]'); @@ -612,7 +615,7 @@ describe('User', function () { it('should error with invalid data', function (done) { var socketUser = require('../src/socket.io/user'); - socketUser.uploadProfileImageFromUrl({uid: uid}, {uid: uid, url: ''}, function (err) { + socketUser.uploadProfileImageFromUrl({ uid: uid }, { uid: uid, url: '' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -624,12 +627,12 @@ describe('User', function () { meta.config.maximumProfileImageSize = ''; function filterMethod(data, callback) { - callback(null, {url: url}); + callback(null, { url: url }); } - plugins.registerHook('test-plugin', {hook: 'filter:uploadImage', method: filterMethod}); + plugins.registerHook('test-plugin', { hook: 'filter:uploadImage', method: filterMethod }); - socketUser.uploadProfileImageFromUrl({uid: uid}, {uid: uid, url: url}, function (err, uploadedPicture) { + socketUser.uploadProfileImageFromUrl({ uid: uid }, { uid: uid, url: url }, function (err, uploadedPicture) { assert.ifError(err); assert.equal(uploadedPicture, url); done(); @@ -637,7 +640,7 @@ describe('User', function () { }); it('should get profile pictures', function (done) { - io.emit('user.getProfilePictures', {uid: uid}, function (err, data) { + io.emit('user.getProfilePictures', { uid: uid }, function (err, data) { assert.ifError(err); assert(data); assert(Array.isArray(data)); @@ -648,7 +651,7 @@ describe('User', function () { }); it('should remove uploaded picture', function (done) { - io.emit('user.removeUploadedPicture', {uid: uid}, function (err) { + io.emit('user.removeUploadedPicture', { uid: uid }, function (err) { assert.ifError(err); User.getUserField(uid, 'uploadedpicture', function (err, uploadedpicture) { assert.ifError(err); @@ -659,7 +662,7 @@ describe('User', function () { }); it('should load profile page', function (done) { - request(nconf.get('url') + '/api/user/updatedagain', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/updatedagain', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -668,7 +671,7 @@ describe('User', function () { }); it('should load settings page', function (done) { - request(nconf.get('url') + '/api/user/updatedagain/settings', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/updatedagain/settings', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body.settings); @@ -679,7 +682,7 @@ describe('User', function () { }); it('should load edit page', function (done) { - request(nconf.get('url') + '/api/user/updatedagain/edit', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/updatedagain/edit', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -688,7 +691,7 @@ describe('User', function () { }); it('should load edit/email page', function (done) { - request(nconf.get('url') + '/api/user/updatedagain/edit/email', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/updatedagain/edit/email', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(body); @@ -699,12 +702,12 @@ describe('User', function () { it('should load user\'s groups page', function (done) { groups.create({ name: 'Test', - description: 'Foobar!' + description: 'Foobar!', }, function (err) { assert.ifError(err); groups.join('Test', uid, function (err) { assert.ifError(err); - request(nconf.get('url') + '/api/user/updatedagain/groups', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/user/updatedagain/groups', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 200); assert(Array.isArray(body.groups)); @@ -713,7 +716,6 @@ describe('User', function () { }); }); }); - }); }); @@ -734,7 +736,7 @@ describe('User', function () { next(err); }); - } + }, ], function (err) { assert.ifError(err); User.unban(testUid, function (err) { @@ -748,7 +750,7 @@ describe('User', function () { describe('digests', function () { var uid; before(function (done) { - User.create({username: 'digestuser', email: 'test@example.com'}, function (err, _uid) { + User.create({ username: 'digestuser', email: 'test@example.com' }, function (err, _uid) { assert.ifError(err); uid = _uid; done(); @@ -758,7 +760,7 @@ describe('User', function () { it('should send digests', function (done) { User.updateDigestSetting(uid, 'day', function (err) { assert.ifError(err); - User.digest.execute('day', function (err) { + User.digest.execute('day', function (err) { assert.ifError(err); done(); }); @@ -770,14 +772,14 @@ describe('User', function () { var socketUser = require('../src/socket.io/user'); it('should fail with invalid data', function (done) { - socketUser.exists({uid: testUid}, null, function (err) { + socketUser.exists({ uid: testUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should return true if user/group exists', function (done) { - socketUser.exists({uid: testUid}, {username: 'registered-users'}, function (err, exists) { + socketUser.exists({ uid: testUid }, { username: 'registered-users' }, function (err, exists) { assert.ifError(err); assert(exists); done(); @@ -785,7 +787,7 @@ describe('User', function () { }); it('should return true if user/group exists', function (done) { - socketUser.exists({uid: testUid}, {username: 'John Smith'}, function (err, exists) { + socketUser.exists({ uid: testUid }, { username: 'John Smith' }, function (err, exists) { assert.ifError(err); assert(exists); done(); @@ -793,7 +795,7 @@ describe('User', function () { }); it('should return false if user/group does not exists', function (done) { - socketUser.exists({uid: testUid}, {username: 'doesnot exist'}, function (err, exists) { + socketUser.exists({ uid: testUid }, { username: 'doesnot exist' }, function (err, exists) { assert.ifError(err); assert(!exists); done(); @@ -801,11 +803,11 @@ describe('User', function () { }); it('should delete user', function (done) { - User.create({username: 'tobedeleted'}, function (err, _uid) { + User.create({ username: 'tobedeleted' }, function (err, _uid) { assert.ifError(err); - socketUser.deleteAccount({uid: _uid}, {}, function (err) { + socketUser.deleteAccount({ uid: _uid }, {}, function (err) { assert.ifError(err); - socketUser.exists({uid: testUid}, {username: 'doesnot exist'}, function (err, exists) { + socketUser.exists({ uid: testUid }, { username: 'doesnot exist' }, function (err, exists) { assert.ifError(err); assert(!exists); done(); @@ -815,14 +817,14 @@ describe('User', function () { }); it('should fail if data is invalid', function (done) { - socketUser.emailExists({uid: testUid}, null, function (err) { + socketUser.emailExists({ uid: testUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should return true if email exists', function (done) { - socketUser.emailExists({uid: testUid}, {email: 'john@example.com'}, function (err, exists) { + socketUser.emailExists({ uid: testUid }, { email: 'john@example.com' }, function (err, exists) { assert.ifError(err); assert(exists); done(); @@ -830,7 +832,7 @@ describe('User', function () { }); it('should return false if email does not exist', function (done) { - socketUser.emailExists({uid: testUid}, {email: 'does@not.exist'}, function (err, exists) { + socketUser.emailExists({ uid: testUid }, { email: 'does@not.exist' }, function (err, exists) { assert.ifError(err); assert(!exists); done(); @@ -838,7 +840,7 @@ describe('User', function () { }); it('should error if requireEmailConfirmation is disabled', function (done) { - socketUser.emailConfirm({uid: testUid}, {}, function (err) { + socketUser.emailConfirm({ uid: testUid }, {}, function (err) { assert.equal(err.message, '[[error:email-confirmations-are-disabled]]'); done(); }); @@ -846,7 +848,7 @@ describe('User', function () { it('should send email confirm', function (done) { Meta.config.requireEmailConfirmation = 1; - socketUser.emailConfirm({uid: testUid}, {}, function (err) { + socketUser.emailConfirm({ uid: testUid }, {}, function (err) { assert.ifError(err); Meta.config.requireEmailConfirmation = 0; done(); @@ -854,21 +856,21 @@ describe('User', function () { }); it('should send reset email', function (done) { - socketUser.reset.send({uid: 0}, 'john@example.com', function (err) { + socketUser.reset.send({ uid: 0 }, 'john@example.com', function (err) { assert.ifError(err); done(); }); }); it('should return invalid-data error', function (done) { - socketUser.reset.send({uid: 0}, null, function (err) { + socketUser.reset.send({ uid: 0 }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should not error', function (done) { - socketUser.reset.send({uid: 0}, 'doestnot@exist.com', function (err) { + socketUser.reset.send({ uid: 0 }, 'doestnot@exist.com', function (err) { assert.ifError(err); done(); }); @@ -878,7 +880,7 @@ describe('User', function () { db.getObject('reset:uid', function (err, data) { assert.ifError(err); var code = Object.keys(data)[0]; - socketUser.reset.commit({uid: 0}, {code: code, password: 'swordfish'}, function (err) { + socketUser.reset.commit({ uid: 0 }, { code: code, password: 'swordfish' }, function (err) { assert.ifError(err); done(); }); @@ -906,21 +908,21 @@ describe('User', function () { followTopicsOnReply: 1, notificationSound: '', incomingChatSound: '', - outgoingChatSound: '' - } + outgoingChatSound: '', + }, }; - socketUser.saveSettings({uid: testUid}, data, function (err) { + socketUser.saveSettings({ uid: testUid }, data, function (err) { assert.ifError(err); done(); }); }); it('should set moderation note', function (done) { - User.create({username: 'noteadmin'}, function (err, adminUid) { + User.create({ username: 'noteadmin' }, function (err, adminUid) { assert.ifError(err); groups.join('administrators', adminUid, function (err) { assert.ifError(err); - socketUser.setModerationNote({uid: adminUid}, {uid: testUid, note: 'this is a test user'}, function (err) { + socketUser.setModerationNote({ uid: adminUid }, { uid: testUid, note: 'this is a test user' }, function (err) { assert.ifError(err); User.getUserField(testUid, 'moderationNote', function (err, note) { assert.ifError(err); @@ -930,7 +932,6 @@ describe('User', function () { }); }); }); - }); }); @@ -942,7 +943,7 @@ describe('User', function () { before(function (done) { oldRegistrationType = Meta.config.registrationType; Meta.config.registrationType = 'admin-approval'; - User.create({username: 'admin', password: '123456'}, function (err, uid) { + User.create({ username: 'admin', password: '123456' }, function (err, uid) { assert.ifError(err); adminUid = uid; groups.join('administrators', uid, done); @@ -958,12 +959,12 @@ describe('User', function () { helpers.registerUser({ username: 'rejectme', password: '123456', - email: 'reject@me.com' + email: 'reject@me.com', }, function (err) { assert.ifError(err); helpers.loginUser('admin', '123456', function (err, jar) { assert.ifError(err); - request(nconf.get('url') + '/api/admin/manage/registration', {jar: jar, json: true}, function (err, res, body) { + request(nconf.get('url') + '/api/admin/manage/registration', { jar: jar, json: true }, function (err, res, body) { assert.ifError(err); assert.equal(body.users[0].username, 'rejectme'); assert.equal(body.users[0].email, 'reject@me.com'); @@ -974,7 +975,7 @@ describe('User', function () { }); it('should reject user registration', function (done) { - socketAdmin.user.rejectRegistration({uid: adminUid}, {username: 'rejectme'}, function (err) { + socketAdmin.user.rejectRegistration({ uid: adminUid }, { username: 'rejectme' }, function (err) { assert.ifError(err); User.getRegistrationQueue(0, -1, function (err, users) { assert.ifError(err); @@ -988,10 +989,10 @@ describe('User', function () { helpers.registerUser({ username: 'acceptme', password: '123456', - email: 'accept@me.com' + email: 'accept@me.com', }, function (err) { assert.ifError(err); - socketAdmin.user.acceptRegistration({uid: adminUid}, {username: 'acceptme'}, function (err, uid) { + socketAdmin.user.acceptRegistration({ uid: adminUid }, { username: 'acceptme' }, function (err, uid) { assert.ifError(err); User.exists(uid, function (err, exists) { assert.ifError(err); @@ -1014,7 +1015,7 @@ describe('User', function () { before(function (done) { User.create({ username: 'inviter', - email: 'inviter@nodebb.org' + email: 'inviter@nodebb.org', }, function (err, uid) { assert.ifError(err); inviterUid = uid; @@ -1023,14 +1024,14 @@ describe('User', function () { }); it('should error with invalid data', function (done) { - socketUser.invite({uid: inviterUid}, null, function (err) { + socketUser.invite({ uid: inviterUid }, null, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should eror if forum is not invite only', function (done) { - socketUser.invite({uid: inviterUid}, 'invite1@test.com', function (err) { + socketUser.invite({ uid: inviterUid }, 'invite1@test.com', function (err) { assert.equal(err.message, '[[error:forum-not-invite-only]]'); done(); }); @@ -1038,7 +1039,7 @@ describe('User', function () { it('should error if user is not admin and type is admin-invite-only', function (done) { meta.config.registrationType = 'admin-invite-only'; - socketUser.invite({uid: inviterUid}, 'invite1@test.com', function (err) { + socketUser.invite({ uid: inviterUid }, 'invite1@test.com', function (err) { assert.equal(err.message, '[[error:no-privileges]]'); done(); }); @@ -1046,7 +1047,7 @@ describe('User', function () { it('should send invitation email', function (done) { meta.config.registrationType = 'invite-only'; - socketUser.invite({uid: inviterUid}, 'invite1@test.com', function (err) { + socketUser.invite({ uid: inviterUid }, 'invite1@test.com', function (err) { assert.ifError(err); done(); }); @@ -1054,7 +1055,7 @@ describe('User', function () { it('should error if ouf of invitations', function (done) { meta.config.maximumInvites = 1; - socketUser.invite({uid: inviterUid}, 'invite2@test.com', function (err) { + socketUser.invite({ uid: inviterUid }, 'invite2@test.com', function (err) { assert.equal(err.message, '[[error:invite-maximum-met, ' + 1 + ', ' + 1 + ']]'); meta.config.maximumInvites = 5; done(); @@ -1062,14 +1063,14 @@ describe('User', function () { }); it('should error if email exists', function (done) { - socketUser.invite({uid: inviterUid}, 'inviter@nodebb.org', function (err) { + socketUser.invite({ uid: inviterUid }, 'inviter@nodebb.org', function (err) { assert.equal(err.message, '[[error:email-taken]]'); done(); }); }); it('should send invitation email', function (done) { - socketUser.invite({uid: inviterUid}, 'invite2@test.com', function (err) { + socketUser.invite({ uid: inviterUid }, 'invite2@test.com', function (err) { assert.ifError(err); done(); }); @@ -1095,23 +1096,24 @@ describe('User', function () { }); it('should fail to verify invitation with invalid data', function (done) { - User.verifyInvitation({token: '', email: ''}, function (err) { + User.verifyInvitation({ token: '', email: '' }, function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); it('should fail to verify invitation with invalid email', function (done) { - User.verifyInvitation({token: 'test', email: 'doesnotexist@test.com'}, function (err) { + User.verifyInvitation({ token: 'test', email: 'doesnotexist@test.com' }, function (err) { assert.equal(err.message, '[[error:invalid-token]]'); done(); }); }); it('should verify installation with no errors', function (done) { - db.get('invitation:email:' + 'invite1@test.com', function (err, token) { + var email = 'invite1@test.com'; + db.get('invitation:email:' + email, function (err, token) { assert.ifError(err); - User.verifyInvitation({token: token, email: 'invite1@test.com'}, function (err) { + User.verifyInvitation({ token: token, email: 'invite1@test.com' }, function (err) { assert.ifError(err); done(); }); @@ -1127,7 +1129,7 @@ describe('User', function () { it('should delete invitation', function (done) { var socketAdmin = require('../src/socket.io/admin'); - socketAdmin.user.deleteInvitation({uid: inviterUid}, {invitedBy: 'inviter', email: 'invite1@test.com'}, function (err) { + socketAdmin.user.deleteInvitation({ uid: inviterUid }, { invitedBy: 'inviter', email: 'invite1@test.com' }, function (err) { assert.ifError(err); db.isSetMember('invitation:uid:' + inviterUid, 'invite1@test.com', function (err, isMember) { assert.ifError(err); @@ -1151,7 +1153,45 @@ describe('User', function () { }); }); }); + }); + describe('email confirm', function () { + it('should error with invalid code', function (done) { + User.email.confirm('asdasda', function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should confirm email of user', function (done) { + var email = 'confirm@me.com'; + User.create({ + username: 'confirme', + email: email, + }, function (err, uid) { + assert.ifError(err); + User.email.sendValidationEmail(uid, email, function (err, code) { + assert.ifError(err); + User.email.confirm(code, function (err) { + assert.ifError(err); + + async.parallel({ + confirmed: function (next) { + db.getObjectField('user:' + uid, 'email:confirmed', next); + }, + isMember: function (next) { + db.isSortedSetMember('users:notvalidated', uid, next); + }, + }, function (err, results) { + assert.ifError(err); + assert.equal(results.confirmed, 1); + assert.equal(results.isMember, false); + done(); + }); + }); + }); + }); + }); }); diff --git a/test/utils.js b/test/utils.js index 95f3040df4..2beedcf3eb 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,5 +1,5 @@ 'use strict'; -/*global require*/ + var assert = require('assert'); var utils = require('./../public/src/utils.js'); @@ -30,15 +30,15 @@ describe('Utility Methods', function () { describe('UUID generation', function () { it('return unique random value every time', function () { - var uuid1 = utils.generateUUID(), - uuid2 = utils.generateUUID(); + var uuid1 = utils.generateUUID(); + var uuid2 = utils.generateUUID(); assert.notEqual(uuid1, uuid2, 'matches'); }); }); describe('cleanUpTag', function () { it('should cleanUp a tag', function (done) { - var cleanedTag = utils.cleanUpTag(',\/#!$%\^\*;TaG1:{}=_`<>\'"~()?\|'); + var cleanedTag = utils.cleanUpTag(',/#!$%^*;TaG1:{}=_`<>\'"~()?|'); assert.equal(cleanedTag, 'tag1'); done(); }); @@ -70,8 +70,8 @@ describe('Utility Methods', function () { }); it('should shallow merge two objects', function (done) { - var a = {foo: 1, cat1: 'ginger'}; - var b = {baz: 2, cat2: 'phoebe'}; + var a = { foo: 1, cat1: 'ginger' }; + var b = { baz: 2, cat2: 'phoebe' }; var obj = utils.merge(a, b); assert.strictEqual(obj.foo, 1); assert.strictEqual(obj.baz, 2); @@ -151,10 +151,10 @@ describe('Utility Methods', function () { var currentHour = new Date().getHours(); var hours = utils.getHoursArray(); var index = hours.length - 1; - for (var i = currentHour, ii = currentHour - 24; i > ii; i--) { + for (var i = currentHour, ii = currentHour - 24; i > ii; i -= 1) { var hour = i < 0 ? 24 + i : i; assert.equal(hours[index], hour + ':00'); - -- index; + index -= 1; } done(); }); @@ -164,12 +164,11 @@ describe('Utility Methods', function () { var days = utils.getDaysArray(); var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; var index = 0; - for(var x = 29; x >= 0; x--) { + for (var x = 29; x >= 0; x -= 1) { var tmpDate = new Date(currentDay - (1000 * 60 * 60 * 24 * x)); - assert.equal(months[tmpDate.getMonth()] + ' ' + tmpDate.getDate(), days[index]); - ++ index; + assert.equal(months[tmpDate.getMonth()] + ' ' + tmpDate.getDate(), days[index]); + index += 1; } done(); }); - });