From 890c2eff70baa591554c2b5945cf8316b9c5fd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 27 May 2017 01:44:26 -0400 Subject: [PATCH] style changes --- src/database/redis/hash.js | 2 +- src/groups/ownership.js | 2 +- src/install.js | 8 +- src/languages.js | 2 +- src/meta/css.js | 2 +- src/meta/themes.js | 4 +- src/password.js | 53 ++-- src/plugins.js | 600 +++++++++++++++++------------------ src/posts/cache.js | 2 +- src/routes/authentication.js | 16 +- src/routes/feeds.js | 4 +- src/socket.io/plugins.js | 2 +- src/topics.js | 600 ++++++++++++++++++----------------- src/user.js | 2 +- src/user/email.js | 190 +++++------ src/user/reset.js | 308 +++++++++--------- 16 files changed, 899 insertions(+), 898 deletions(-) diff --git a/src/database/redis/hash.js b/src/database/redis/hash.js index 9dcb005528..9cf320fb3d 100644 --- a/src/database/redis/hash.js +++ b/src/database/redis/hash.js @@ -55,7 +55,7 @@ module.exports = function (redisClient, module) { if (!Array.isArray(fields) || !fields.length) { return callback(null, keys.map(function () { return {}; })); } - var multi = redisClient.multi(); + var multi = redisClient.multi(); for (var x = 0; x < keys.length; x += 1) { multi.hmget.apply(multi, [keys[x]].concat(fields)); diff --git a/src/groups/ownership.js b/src/groups/ownership.js index 0b386bbe35..e2a82d3f93 100644 --- a/src/groups/ownership.js +++ b/src/groups/ownership.js @@ -1,6 +1,6 @@ 'use strict'; -var async = require('async'); +var async = require('async'); var db = require('../database'); var plugins = require('../plugins'); diff --git a/src/install.js b/src/install.js index 7ba5e6ccdb..40065adbc6 100644 --- a/src/install.js +++ b/src/install.js @@ -84,7 +84,7 @@ function checkSetupFlag(next) { } function checkCIFlag(next) { - var ciVals; + var ciVals; try { ciVals = JSON.parse(nconf.get('ci')); } catch (e) { @@ -188,7 +188,7 @@ function setupDefaultConfigs(next) { } function enableDefaultTheme(next) { - var meta = require('./meta'); + var meta = require('./meta'); meta.configs.get('theme:id', function (err, id) { if (err || id) { @@ -470,7 +470,7 @@ function enableDefaultPlugins(next) { } function setCopyrightWidget(next) { - var db = require('./database'); + var db = require('./database'); async.parallel({ footerJSON: function (next) { fs.readFile(path.join(__dirname, '../', 'install/data/footer.json'), next); @@ -534,7 +534,7 @@ install.setup = function (callback) { }; install.save = function (server_conf, callback) { - var serverConfigPath = path.join(__dirname, '../config.json'); + var serverConfigPath = path.join(__dirname, '../config.json'); if (nconf.get('config')) { serverConfigPath = path.resolve(__dirname, '../', nconf.get('config')); diff --git a/src/languages.js b/src/languages.js index 4414562e11..5d49e60f53 100644 --- a/src/languages.js +++ b/src/languages.js @@ -5,7 +5,7 @@ var path = require('path'); var async = require('async'); var Languages = module.exports; -var languagesPath = path.join(__dirname, '../build/public/language'); +var languagesPath = path.join(__dirname, '../build/public/language'); Languages.init = function (next) { next(); diff --git a/src/meta/css.js b/src/meta/css.js index 127191437c..f2abe608ac 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -59,7 +59,7 @@ module.exports = function (Meta) { } function getImports(files, prefix, extension, callback) { - var pluginDirectories = []; + var pluginDirectories = []; var source = ''; files.forEach(function (styleFile) { diff --git a/src/meta/themes.js b/src/meta/themes.js index a41bf52e59..9bca68c431 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -74,7 +74,7 @@ module.exports = function (Meta) { }; Meta.themes.set = function (data, callback) { - var themeData = { + var themeData = { 'theme:type': data.type, 'theme:id': data.id, 'theme:staticDir': '', @@ -141,7 +141,7 @@ module.exports = function (Meta) { function (data, next) { var themeId = data.currentThemeId || 'nodebb-theme-persona'; - var themeObj = data.themesData.filter(function (themeObj) { + var themeObj = data.themesData.filter(function (themeObj) { return themeObj.id === themeId; })[0]; diff --git a/src/password.js b/src/password.js index 5405941fff..76123ed974 100644 --- a/src/password.js +++ b/src/password.js @@ -1,37 +1,34 @@ 'use strict'; -(function (module) { - var fork = require('child_process').fork; - var path = require('path'); - module.hash = function (rounds, password, callback) { - forkChild({ type: 'hash', rounds: rounds, password: password }, callback); - }; +var fork = require('child_process').fork; +var path = require('path'); - module.compare = function (password, hash, callback) { - if (!hash || !password) { - return setImmediate(callback, null, false); - } - forkChild({ type: 'compare', password: password, hash: hash }, callback); - }; +exports.hash = function (rounds, password, callback) { + forkChild({ type: 'hash', rounds: rounds, password: password }, callback); +}; - function forkChild(message, callback) { - var forkProcessParams = {}; - if (global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { - forkProcessParams = { execArgv: ['--debug=' + (5859), '--nolazy'] }; - } - var child = fork(path.join(__dirname, 'bcrypt'), [], forkProcessParams); +exports.compare = function (password, hash, callback) { + if (!hash || !password) { + return setImmediate(callback, null, false); + } + forkChild({ type: 'compare', password: password, hash: hash }, callback); +}; - child.on('message', function (msg) { - if (msg.err) { - return callback(new Error(msg.err)); - } +function forkChild(message, callback) { + var forkProcessParams = {}; + if (global.v8debug || parseInt(process.execArgv.indexOf('--debug'), 10) !== -1) { + forkProcessParams = { execArgv: ['--debug=' + (5859), '--nolazy'] }; + } + var child = fork(path.join(__dirname, 'bcrypt'), [], forkProcessParams); - callback(null, msg.result); - }); + child.on('message', function (msg) { + if (msg.err) { + return callback(new Error(msg.err)); + } - child.send(message); - } + callback(null, msg.result); + }); - return module; -}(exports)); + child.send(message); +} diff --git a/src/plugins.js b/src/plugins.js index e3752bbb0c..7c758c517a 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -14,351 +14,351 @@ var file = require('./file'); var app; var middleware; -(function (Plugins) { - require('./plugins/install')(Plugins); - require('./plugins/load')(Plugins); - require('./plugins/hooks')(Plugins); - Plugins.data = require('./plugins/data'); - - Plugins.getPluginPaths = Plugins.data.getPluginPaths; - Plugins.loadPluginInfo = Plugins.data.loadPluginInfo; - - Plugins.pluginsData = {}; - Plugins.libraries = {}; - Plugins.loadedHooks = {}; - Plugins.staticDirs = {}; - Plugins.cssFiles = []; - Plugins.lessFiles = []; - Plugins.clientScripts = []; - Plugins.acpScripts = []; - Plugins.libraryPaths = []; - Plugins.versionWarning = []; - Plugins.soundpacks = []; - Plugins.languageData = {}; - - Plugins.initialized = false; - - Plugins.requireLibrary = function (pluginID, libraryPath) { - Plugins.libraries[pluginID] = require(libraryPath); - Plugins.libraryPaths.push(libraryPath); - }; - - Plugins.init = function (nbbApp, nbbMiddleware, callback) { - callback = callback || function () {}; - if (Plugins.initialized) { - return callback(); - } - - if (nbbApp) { - app = nbbApp; - middleware = nbbMiddleware; - hotswap.prepare(nbbApp); +var Plugins = module.exports; + +require('./plugins/install')(Plugins); +require('./plugins/load')(Plugins); +require('./plugins/hooks')(Plugins); +Plugins.data = require('./plugins/data'); + +Plugins.getPluginPaths = Plugins.data.getPluginPaths; +Plugins.loadPluginInfo = Plugins.data.loadPluginInfo; + +Plugins.pluginsData = {}; +Plugins.libraries = {}; +Plugins.loadedHooks = {}; +Plugins.staticDirs = {}; +Plugins.cssFiles = []; +Plugins.lessFiles = []; +Plugins.clientScripts = []; +Plugins.acpScripts = []; +Plugins.libraryPaths = []; +Plugins.versionWarning = []; +Plugins.soundpacks = []; +Plugins.languageData = {}; + +Plugins.initialized = false; + +Plugins.requireLibrary = function (pluginID, libraryPath) { + Plugins.libraries[pluginID] = require(libraryPath); + Plugins.libraryPaths.push(libraryPath); +}; + +Plugins.init = function (nbbApp, nbbMiddleware, callback) { + callback = callback || function () {}; + if (Plugins.initialized) { + return callback(); + } + + if (nbbApp) { + app = nbbApp; + middleware = nbbMiddleware; + hotswap.prepare(nbbApp); + } + + if (global.env === 'development') { + winston.verbose('[plugins] Initializing plugins system'); + } + + Plugins.reload(function (err) { + if (err) { + winston.error('[plugins] NodeBB encountered a problem while loading plugins', err.message); + return callback(err); } if (global.env === 'development') { - winston.verbose('[plugins] Initializing plugins system'); + winston.info('[plugins] Plugins OK'); } - Plugins.reload(function (err) { - if (err) { - winston.error('[plugins] NodeBB encountered a problem while loading plugins', err.message); - return callback(err); - } - - if (global.env === 'development') { - winston.info('[plugins] Plugins OK'); - } - - Plugins.initialized = true; - callback(); - }); - }; + Plugins.initialized = true; + callback(); + }); +}; - Plugins.reload = function (callback) { - // Resetting all local plugin data - Plugins.libraries = {}; - Plugins.loadedHooks = {}; - Plugins.staticDirs = {}; - Plugins.versionWarning = []; - Plugins.cssFiles.length = 0; - Plugins.lessFiles.length = 0; - Plugins.clientScripts.length = 0; - Plugins.acpScripts.length = 0; - Plugins.libraryPaths.length = 0; - - async.waterfall([ - Plugins.getPluginPaths, - function (paths, next) { - async.eachSeries(paths, Plugins.loadPlugin, next); - }, - function (next) { - // If some plugins are incompatible, throw the warning here - 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 += 1) { - process.stdout.write(' * '.yellow + Plugins.versionWarning[x] + '\n'); - } - process.stdout.write('\n'); +Plugins.reload = function (callback) { + // Resetting all local plugin data + Plugins.libraries = {}; + Plugins.loadedHooks = {}; + Plugins.staticDirs = {}; + Plugins.versionWarning = []; + Plugins.cssFiles.length = 0; + Plugins.lessFiles.length = 0; + Plugins.clientScripts.length = 0; + Plugins.acpScripts.length = 0; + Plugins.libraryPaths.length = 0; + + async.waterfall([ + Plugins.getPluginPaths, + function (paths, next) { + async.eachSeries(paths, Plugins.loadPlugin, next); + }, + function (next) { + // If some plugins are incompatible, throw the warning here + 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 += 1) { + process.stdout.write(' * '.yellow + Plugins.versionWarning[x] + '\n'); } + process.stdout.write('\n'); + } - Object.keys(Plugins.loadedHooks).forEach(function (hook) { - var hooks = Plugins.loadedHooks[hook]; - hooks.sort(function (a, b) { - return a.priority - b.priority; - }); + Object.keys(Plugins.loadedHooks).forEach(function (hook) { + var hooks = Plugins.loadedHooks[hook]; + hooks.sort(function (a, b) { + return a.priority - b.priority; }); + }); - next(); - }, - ], callback); - }; + next(); + }, + ], callback); +}; - Plugins.reloadRoutes = function (callback) { - var router = express.Router(); +Plugins.reloadRoutes = function (callback) { + var router = express.Router(); - router.hotswapId = 'plugins'; - router.render = function () { - app.render.apply(app, arguments); - }; + router.hotswapId = 'plugins'; + router.render = function () { + app.render.apply(app, arguments); + }; - var controllers = require('./controllers'); - Plugins.fireHook('static:app.load', { app: app, router: router, middleware: middleware, controllers: controllers }, function (err) { - if (err) { - winston.error('[plugins] Encountered error while executing post-router plugins hooks: ' + err.message); - return callback(err); - } + var controllers = require('./controllers'); + Plugins.fireHook('static:app.load', { app: app, router: router, middleware: middleware, controllers: controllers }, function (err) { + if (err) { + winston.error('[plugins] Encountered error while executing post-router plugins hooks: ' + err.message); + return callback(err); + } - hotswap.replace('plugins', router); - winston.verbose('[plugins] All plugins reloaded and rerouted'); - callback(); - }); - }; + hotswap.replace('plugins', router); + winston.verbose('[plugins] All plugins reloaded and rerouted'); + callback(); + }); +}; - Plugins.getTemplates = function (callback) { - var templates = {}; - var tplName; +Plugins.getTemplates = function (callback) { + var templates = {}; + var tplName; - Plugins.data.getActive(function (err, plugins) { - if (err) { - return callback(err); - } + Plugins.data.getActive(function (err, plugins) { + if (err) { + return callback(err); + } - async.eachSeries(plugins, function (plugin, next) { - if (plugin.templates || plugin.id.startsWith('nodebb-theme-')) { - winston.verbose('[plugins] Loading templates (' + plugin.id + ')'); - var templatesPath = path.join(__dirname, '../node_modules', plugin.id, plugin.templates || 'templates'); - file.walk(templatesPath, function (err, pluginTemplates) { - if (pluginTemplates) { - pluginTemplates.forEach(function (pluginTemplate) { - if (pluginTemplate.endsWith('.tpl')) { - tplName = '/' + pluginTemplate.replace(templatesPath, '').substring(1); - - if (templates.hasOwnProperty(tplName)) { - winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); - } - - templates[tplName] = pluginTemplate; - } else { - winston.warn('[plugins] Skipping ' + pluginTemplate + ' by plugin ' + plugin.id); + async.eachSeries(plugins, function (plugin, next) { + if (plugin.templates || plugin.id.startsWith('nodebb-theme-')) { + winston.verbose('[plugins] Loading templates (' + plugin.id + ')'); + var templatesPath = path.join(__dirname, '../node_modules', plugin.id, plugin.templates || 'templates'); + file.walk(templatesPath, function (err, pluginTemplates) { + if (pluginTemplates) { + pluginTemplates.forEach(function (pluginTemplate) { + if (pluginTemplate.endsWith('.tpl')) { + tplName = '/' + pluginTemplate.replace(templatesPath, '').substring(1); + + if (templates.hasOwnProperty(tplName)) { + winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); } - }); - } else if (err) { - winston.error(err); - } else { - winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); - } - next(false); - }); - } else { + templates[tplName] = pluginTemplate; + } else { + winston.warn('[plugins] Skipping ' + pluginTemplate + ' by plugin ' + plugin.id); + } + }); + } else if (err) { + winston.error(err); + } else { + winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); + } + next(false); - } - }, function (err) { - callback(err, templates); - }); + }); + } else { + next(false); + } + }, function (err) { + callback(err, templates); }); - }; + }); +}; - Plugins.get = function (id, callback) { - var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; +Plugins.get = function (id, callback) { + var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; - require('request')(url, { - json: true, - }, function (err, res, body) { - if (res.statusCode === 404 || !body.payload) { - return callback(err, {}); - } + require('request')(url, { + json: true, + }, function (err, res, body) { + if (res.statusCode === 404 || !body.payload) { + return callback(err, {}); + } - Plugins.normalise([body.payload], function (err, normalised) { - normalised = normalised.filter(function (plugin) { - return plugin.id === id; - }); - return callback(err, !err ? normalised[0] : undefined); + Plugins.normalise([body.payload], function (err, normalised) { + normalised = normalised.filter(function (plugin) { + return plugin.id === id; }); + return callback(err, !err ? normalised[0] : undefined); }); - }; - - Plugins.list = function (matching, callback) { - if (arguments.length === 1 && typeof matching === 'function') { - callback = matching; - matching = true; + }); +}; + +Plugins.list = function (matching, callback) { + if (arguments.length === 1 && typeof matching === 'function') { + callback = matching; + matching = true; + } + var version = require(path.join(nconf.get('base_dir'), 'package.json')).version; + var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins' + (matching !== false ? '?version=' + version : ''); + + require('request')(url, { + json: true, + }, function (err, res, body) { + if (err) { + winston.error('Error parsing plugins : ' + err.message); + return callback(err); } - var version = require(path.join(nconf.get('base_dir'), 'package.json')).version; - var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins' + (matching !== false ? '?version=' + version : ''); - require('request')(url, { - json: true, - }, function (err, res, body) { - if (err) { - winston.error('Error parsing plugins : ' + err.message); - return callback(err); - } + Plugins.normalise(body, callback); + }); +}; + +Plugins.normalise = function (apiReturn, callback) { + var pluginMap = {}; + var dependencies = require(path.join(nconf.get('base_dir'), 'package.json')).dependencies; + apiReturn = apiReturn || []; + 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].repository ? apiReturn[i].repository.url : ''); + pluginMap[apiReturn[i].name] = apiReturn[i]; + } + + Plugins.showInstalled(function (err, installedPlugins) { + if (err) { + return callback(err); + } - Plugins.normalise(body, callback); + installedPlugins = installedPlugins.filter(function (plugin) { + return plugin && !plugin.system; }); - }; - Plugins.normalise = function (apiReturn, callback) { - var pluginMap = {}; - var dependencies = require(path.join(nconf.get('base_dir'), 'package.json')).dependencies; - apiReturn = apiReturn || []; - 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].repository ? apiReturn[i].repository.url : ''); - pluginMap[apiReturn[i].name] = apiReturn[i]; - } + async.each(installedPlugins, function (plugin, next) { + // If it errored out because a package.json or plugin.json couldn't be read, no need to do this stuff + if (plugin.error) { + pluginMap[plugin.id] = pluginMap[plugin.id] || {}; + pluginMap[plugin.id].installed = true; + pluginMap[plugin.id].error = true; + return next(); + } - Plugins.showInstalled(function (err, installedPlugins) { + pluginMap[plugin.id] = pluginMap[plugin.id] || {}; + pluginMap[plugin.id].id = pluginMap[plugin.id].id || plugin.id; + pluginMap[plugin.id].name = plugin.name || pluginMap[plugin.id].name; + pluginMap[plugin.id].description = plugin.description; + pluginMap[plugin.id].url = pluginMap[plugin.id].url || plugin.url; + pluginMap[plugin.id].installed = true; + pluginMap[plugin.id].isTheme = !!plugin.id.match('nodebb-theme-'); + pluginMap[plugin.id].error = plugin.error || false; + pluginMap[plugin.id].active = plugin.active; + pluginMap[plugin.id].version = plugin.version; + pluginMap[plugin.id].settingsRoute = plugin.settingsRoute; + + // If package.json defines a version to use, stick to that + if (dependencies.hasOwnProperty(plugin.id) && semver.valid(dependencies[plugin.id])) { + pluginMap[plugin.id].latest = dependencies[plugin.id]; + } else { + pluginMap[plugin.id].latest = pluginMap[plugin.id].latest || plugin.version; + } + pluginMap[plugin.id].outdated = semver.gt(pluginMap[plugin.id].latest, pluginMap[plugin.id].version); + next(); + }, function (err) { if (err) { return callback(err); } - installedPlugins = installedPlugins.filter(function (plugin) { - return plugin && !plugin.system; - }); + var pluginArray = []; - async.each(installedPlugins, function (plugin, next) { - // If it errored out because a package.json or plugin.json couldn't be read, no need to do this stuff - if (plugin.error) { - pluginMap[plugin.id] = pluginMap[plugin.id] || {}; - pluginMap[plugin.id].installed = true; - pluginMap[plugin.id].error = true; - return next(); - } - - pluginMap[plugin.id] = pluginMap[plugin.id] || {}; - pluginMap[plugin.id].id = pluginMap[plugin.id].id || plugin.id; - pluginMap[plugin.id].name = plugin.name || pluginMap[plugin.id].name; - pluginMap[plugin.id].description = plugin.description; - pluginMap[plugin.id].url = pluginMap[plugin.id].url || plugin.url; - pluginMap[plugin.id].installed = true; - pluginMap[plugin.id].isTheme = !!plugin.id.match('nodebb-theme-'); - pluginMap[plugin.id].error = plugin.error || false; - pluginMap[plugin.id].active = plugin.active; - pluginMap[plugin.id].version = plugin.version; - pluginMap[plugin.id].settingsRoute = plugin.settingsRoute; - - // If package.json defines a version to use, stick to that - if (dependencies.hasOwnProperty(plugin.id) && semver.valid(dependencies[plugin.id])) { - pluginMap[plugin.id].latest = dependencies[plugin.id]; - } else { - pluginMap[plugin.id].latest = pluginMap[plugin.id].latest || plugin.version; - } - pluginMap[plugin.id].outdated = semver.gt(pluginMap[plugin.id].latest, pluginMap[plugin.id].version); - next(); - }, function (err) { - if (err) { - return callback(err); + for (var key in pluginMap) { + if (pluginMap.hasOwnProperty(key)) { + pluginArray.push(pluginMap[key]); } + } - var pluginArray = []; - - for (var key in pluginMap) { - if (pluginMap.hasOwnProperty(key)) { - pluginArray.push(pluginMap[key]); - } + pluginArray.sort(function (a, b) { + if (a.name > b.name) { + return 1; + } else if (a.name < b.name) { + return -1; } - - pluginArray.sort(function (a, b) { - if (a.name > b.name) { - return 1; - } else if (a.name < b.name) { - return -1; - } - return 0; - }); - - callback(null, pluginArray); + return 0; }); - }); - }; - - Plugins.showInstalled = function (callback) { - var npmPluginPath = path.join(__dirname, '../node_modules'); - async.waterfall([ - async.apply(fs.readdir, npmPluginPath), + callback(null, pluginArray); + }); + }); +}; + +Plugins.showInstalled = function (callback) { + var npmPluginPath = path.join(__dirname, '../node_modules'); + + async.waterfall([ + async.apply(fs.readdir, npmPluginPath), + + function (dirs, next) { + dirs = dirs.filter(function (dir) { + return dir.startsWith('nodebb-plugin-') || + dir.startsWith('nodebb-widget-') || + dir.startsWith('nodebb-rewards-') || + dir.startsWith('nodebb-theme-'); + }).map(function (dir) { + return path.join(npmPluginPath, dir); + }); - function (dirs, next) { - dirs = dirs.filter(function (dir) { - return dir.startsWith('nodebb-plugin-') || - dir.startsWith('nodebb-widget-') || - dir.startsWith('nodebb-rewards-') || - dir.startsWith('nodebb-theme-'); - }).map(function (dir) { - return path.join(npmPluginPath, dir); + async.filter(dirs, function (dir, callback) { + fs.stat(dir, function (err, stats) { + if (err) { + if (err.code === 'ENOENT') { + return callback(null, false); + } + return callback(err); + } + callback(null, stats.isDirectory()); }); - - async.filter(dirs, function (dir, callback) { - fs.stat(dir, function (err, stats) { - if (err) { - if (err.code === 'ENOENT') { - return callback(null, false); + }, next); + }, + + function (files, next) { + var plugins = []; + + async.each(files, function (file, next) { + async.waterfall([ + function (next) { + Plugins.loadPluginInfo(file, next); + }, + function (pluginData, next) { + Plugins.isActive(pluginData.name, function (err, active) { + if (err) { + return next(new Error('no-active-state')); } - return callback(err); - } - callback(null, stats.isDirectory()); - }); - }, next); - }, - - function (files, next) { - var plugins = []; - - async.each(files, function (file, next) { - async.waterfall([ - function (next) { - Plugins.loadPluginInfo(file, next); - }, - function (pluginData, next) { - Plugins.isActive(pluginData.name, function (err, active) { - if (err) { - return next(new Error('no-active-state')); - } - delete pluginData.hooks; - delete pluginData.library; - pluginData.active = active; - pluginData.installed = true; - pluginData.error = false; - next(null, pluginData); - }); - }, - ], function (err, pluginData) { - if (err) { - return next(); // Silently fail - } + delete pluginData.hooks; + delete pluginData.library; + pluginData.active = active; + pluginData.installed = true; + pluginData.error = false; + next(null, pluginData); + }); + }, + ], function (err, pluginData) { + if (err) { + return next(); // Silently fail + } - plugins.push(pluginData); - next(); - }); - }, function (err) { - next(err, plugins); + plugins.push(pluginData); + next(); }); - }, - ], callback); - }; -}(exports)); + }, function (err) { + next(err, plugins); + }); + }, + ], callback); +}; diff --git a/src/posts/cache.js b/src/posts/cache.js index c73e1c8d92..ae4f1948a6 100644 --- a/src/posts/cache.js +++ b/src/posts/cache.js @@ -1,6 +1,6 @@ 'use strict'; -var LRU = require('lru-cache'); +var LRU = require('lru-cache'); var meta = require('../meta'); var cache = LRU({ diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 61ea8e3f28..c85e03fe27 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -2,16 +2,16 @@ var async = require('async'); var passport = require('passport'); -var passportLocal = require('passport-local').Strategy; -var nconf = require('nconf'); -var winston = require('winston'); -var express = require('express'); +var passportLocal = require('passport-local').Strategy; +var nconf = require('nconf'); +var winston = require('winston'); +var express = require('express'); -var controllers = require('../controllers'); -var plugins = require('../plugins'); -var hotswap = require('../hotswap'); +var controllers = require('../controllers'); +var plugins = require('../plugins'); +var hotswap = require('../hotswap'); -var loginStrategies = []; +var loginStrategies = []; var Auth = module.exports; diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 3171babbf6..e1fd92cd59 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -233,7 +233,7 @@ function generateTopicsFeed(feedOptions, feedTopics, callback) { feedTopics = feedTopics.filter(Boolean); - var feed = new rss(feedOptions); + var feed = new rss(feedOptions); if (feedTopics.length > 0) { feed.pubDate = new Date(parseInt(feedTopics[0].lastposttime, 10)).toUTCString(); @@ -338,7 +338,7 @@ function generateForPostsFeed(feedOptions, posts) { feedOptions.feed_url = nconf.get('url') + feedOptions.feed_url; feedOptions.site_url = nconf.get('url') + feedOptions.site_url; - var feed = new rss(feedOptions); + var feed = new rss(feedOptions); if (posts.length > 0) { feed.pubDate = new Date(parseInt(posts[0].timestamp, 10)).toUTCString(); diff --git a/src/socket.io/plugins.js b/src/socket.io/plugins.js index 32f1e7f00f..923c31e437 100644 --- a/src/socket.io/plugins.js +++ b/src/socket.io/plugins.js @@ -1,6 +1,6 @@ 'use strict'; -var SocketPlugins = {}; +var SocketPlugins = {}; /* This file is provided exclusively so that plugins can require it and add their own socket listeners. diff --git a/src/topics.js b/src/topics.js index b96c76f5de..ca80686bd4 100644 --- a/src/topics.js +++ b/src/topics.js @@ -12,322 +12,326 @@ var categories = require('./categories'); var privileges = require('./privileges'); var social = require('./social'); -(function (Topics) { - require('./topics/data')(Topics); - require('./topics/create')(Topics); - require('./topics/delete')(Topics); - require('./topics/unread')(Topics); - require('./topics/recent')(Topics); - require('./topics/popular')(Topics); - require('./topics/user')(Topics); - require('./topics/fork')(Topics); - require('./topics/posts')(Topics); - require('./topics/follow')(Topics); - require('./topics/tags')(Topics); - require('./topics/teaser')(Topics); - require('./topics/suggested')(Topics); - require('./topics/tools')(Topics); - require('./topics/thumb')(Topics); - require('./topics/bookmarks')(Topics); - - Topics.exists = function (tid, callback) { - db.isSortedSetMember('topics:tid', tid, callback); - }; - - Topics.getPageCount = function (tid, uid, callback) { - var postCount; - async.waterfall([ - function (next) { - Topics.getTopicField(tid, 'postcount', next); - }, - function (_postCount, next) { - if (!parseInt(_postCount, 10)) { - return callback(null, 1); - } - postCount = _postCount; - user.getSettings(uid, next); - }, - function (settings, next) { - next(null, Math.ceil((parseInt(postCount, 10) - 1) / settings.postsPerPage)); - }, - ], callback); - }; - - Topics.getTidPage = function (tid, uid, callback) { - console.warn('[Topics.getTidPage] deprecated!'); - callback(null, 1); - }; - - Topics.getTopicsFromSet = function (set, uid, start, stop, callback) { - async.waterfall([ - function (next) { - db.getSortedSetRevRange(set, start, stop, next); - }, - function (tids, next) { - Topics.getTopics(tids, uid, next); - }, - function (topics, next) { - next(null, { topics: topics, nextStart: stop + 1 }); - }, - ], callback); - }; - - Topics.getTopics = function (tids, uid, callback) { - async.waterfall([ - function (next) { - privileges.topics.filterTids('read', tids, uid, next); - }, - function (tids, next) { - Topics.getTopicsByTids(tids, uid, next); - }, - ], callback); - }; - - Topics.getTopicsByTids = function (tids, uid, callback) { - if (!Array.isArray(tids) || !tids.length) { - return callback(null, []); - } - - var uids; - var cids; - var topics; - - async.waterfall([ - function (next) { - Topics.getTopicsData(tids, next); - }, - function (_topics, next) { - function mapFilter(array, field) { - return array.map(function (topic) { - return topic && topic[field] && topic[field].toString(); - }).filter(function (value, index, array) { - return utils.isNumber(value) && array.indexOf(value) === index; - }); - } - - topics = _topics; - uids = mapFilter(topics, 'uid'); - cids = mapFilter(topics, 'cid'); - - async.parallel({ - users: function (next) { - user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next); - }, - categories: function (next) { - categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'image', 'bgColor', 'color', 'disabled'], next); - }, - hasRead: function (next) { - Topics.hasReadTopics(tids, uid, next); - }, - isIgnored: function (next) { - Topics.isIgnoring(tids, uid, next); - }, - bookmarks: function (next) { - Topics.getUserBookmarks(tids, uid, next); - }, - teasers: function (next) { - Topics.getTeasers(topics, uid, next); - }, - 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 += 1) { - if (topics[i]) { - topics[i].category = categories[topics[i].cid]; - topics[i].user = users[topics[i].uid]; - topics[i].teaser = results.teasers[i]; - topics[i].tags = results.tags[i]; - - topics[i].isOwner = parseInt(topics[i].uid, 10) === parseInt(uid, 10); - topics[i].pinned = parseInt(topics[i].pinned, 10) === 1; - topics[i].locked = parseInt(topics[i].locked, 10) === 1; - topics[i].deleted = parseInt(topics[i].deleted, 10) === 1; - topics[i].ignored = results.isIgnored[i]; - topics[i].unread = !results.hasRead[i] && !results.isIgnored[i]; - topics[i].bookmark = results.bookmarks[i]; - topics[i].unreplied = !topics[i].teaser; - - topics[i].icons = []; - } - } +var Topics = module.exports; + +require('./topics/data')(Topics); +require('./topics/create')(Topics); +require('./topics/delete')(Topics); +require('./topics/unread')(Topics); +require('./topics/recent')(Topics); +require('./topics/popular')(Topics); +require('./topics/user')(Topics); +require('./topics/fork')(Topics); +require('./topics/posts')(Topics); +require('./topics/follow')(Topics); +require('./topics/tags')(Topics); +require('./topics/teaser')(Topics); +require('./topics/suggested')(Topics); +require('./topics/tools')(Topics); +require('./topics/thumb')(Topics); +require('./topics/bookmarks')(Topics); + +Topics.exists = function (tid, callback) { + db.isSortedSetMember('topics:tid', tid, callback); +}; + +Topics.getPageCount = function (tid, uid, callback) { + var postCount; + async.waterfall([ + function (next) { + Topics.getTopicField(tid, 'postcount', next); + }, + function (_postCount, next) { + if (!parseInt(_postCount, 10)) { + return callback(null, 1); + } + postCount = _postCount; + user.getSettings(uid, next); + }, + function (settings, next) { + next(null, Math.ceil((parseInt(postCount, 10) - 1) / settings.postsPerPage)); + }, + ], callback); +}; + +Topics.getTidPage = function (tid, uid, callback) { + console.warn('[Topics.getTidPage] deprecated!'); + callback(null, 1); +}; + +Topics.getTopicsFromSet = function (set, uid, start, stop, callback) { + async.waterfall([ + function (next) { + db.getSortedSetRevRange(set, start, stop, next); + }, + function (tids, next) { + Topics.getTopics(tids, uid, next); + }, + function (topics, next) { + next(null, { topics: topics, nextStart: stop + 1 }); + }, + ], callback); +}; + +Topics.getTopics = function (tids, uid, callback) { + async.waterfall([ + function (next) { + privileges.topics.filterTids('read', tids, uid, next); + }, + function (tids, next) { + Topics.getTopicsByTids(tids, uid, next); + }, + ], callback); +}; + +Topics.getTopicsByTids = function (tids, uid, callback) { + if (!Array.isArray(tids) || !tids.length) { + return callback(null, []); + } - topics = topics.filter(function (topic) { - return topic && topic.category && !topic.category.disabled; + var uids; + var cids; + var topics; + + async.waterfall([ + function (next) { + Topics.getTopicsData(tids, next); + }, + function (_topics, next) { + function mapFilter(array, field) { + return array.map(function (topic) { + return topic && topic[field] && topic[field].toString(); + }).filter(function (value, index, array) { + return utils.isNumber(value) && array.indexOf(value) === index; }); + } - plugins.fireHook('filter:topics.get', { topics: topics, uid: uid }, next); - }, - function (data, next) { - next(null, data.topics); - }, - ], callback); - }; - - Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, callback) { - async.waterfall([ - function (next) { - 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: [] }), - 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) { - Topics.getTopicTagsObjects(topicData.tid, next); - }, - function (tags, next) { - topicData.tags = tags; - Topics.getRelatedTopics(topicData, uid, next); - }, - ], next); - }, - }, next); - }, - function (results, next) { - topicData.posts = results.posts; - topicData.category = results.category; - topicData.thread_tools = results.threadTools.tools; - topicData.isFollowing = results.isFollowing[0]; - topicData.isNotFollowing = !results.isFollowing[0] && !results.isIgnoring[0]; - 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; - topicData.deleted = parseInt(topicData.deleted, 10) === 1; - topicData.locked = parseInt(topicData.locked, 10) === 1; - topicData.pinned = parseInt(topicData.pinned, 10) === 1; - - topicData.icons = []; - - plugins.fireHook('filter:topic.get', { topic: topicData, uid: uid }, next); - }, - function (data, next) { - next(null, data.topic); - }, - ], callback); - }; - - function getMainPostAndReplies(topic, set, uid, start, stop, reverse, callback) { - async.waterfall([ - function (next) { - if (stop > 0) { - stop -= 1; - if (start > 0) { - start -= 1; - } + topics = _topics; + uids = mapFilter(topics, 'uid'); + cids = mapFilter(topics, 'cid'); + + async.parallel({ + users: function (next) { + user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next); + }, + categories: function (next) { + categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'image', 'bgColor', 'color', 'disabled'], next); + }, + hasRead: function (next) { + Topics.hasReadTopics(tids, uid, next); + }, + isIgnored: function (next) { + Topics.isIgnoring(tids, uid, next); + }, + bookmarks: function (next) { + Topics.getUserBookmarks(tids, uid, next); + }, + teasers: function (next) { + Topics.getTeasers(topics, uid, next); + }, + 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 += 1) { + if (topics[i]) { + topics[i].category = categories[topics[i].cid]; + topics[i].user = users[topics[i].uid]; + topics[i].teaser = results.teasers[i]; + topics[i].tags = results.tags[i]; + + topics[i].isOwner = parseInt(topics[i].uid, 10) === parseInt(uid, 10); + topics[i].pinned = parseInt(topics[i].pinned, 10) === 1; + topics[i].locked = parseInt(topics[i].locked, 10) === 1; + topics[i].deleted = parseInt(topics[i].deleted, 10) === 1; + topics[i].ignored = results.isIgnored[i]; + topics[i].unread = !results.hasRead[i] && !results.isIgnored[i]; + topics[i].bookmark = results.bookmarks[i]; + topics[i].unreplied = !topics[i].teaser; + + topics[i].icons = []; } + } - posts.getPidsFromSet(set, start, stop, reverse, next); - }, - function (pids, next) { - if (!pids.length && !topic.mainPid) { - return callback(null, []); - } + topics = topics.filter(function (topic) { + return topic && topic.category && !topic.category.disabled; + }); - if (topic.mainPid && start === 0) { - pids.unshift(topic.mainPid); - } - posts.getPostsByPids(pids, uid, next); - }, - function (posts, next) { - if (!posts.length) { - return next(null, []); + plugins.fireHook('filter:topics.get', { topics: topics, uid: uid }, next); + }, + function (data, next) { + next(null, data.topics); + }, + ], callback); +}; + +Topics.getTopicWithPosts = function (topicData, set, uid, start, stop, reverse, callback) { + async.waterfall([ + function (next) { + 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: [] }), + 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) { + Topics.getTopicTagsObjects(topicData.tid, next); + }, + function (tags, next) { + topicData.tags = tags; + Topics.getRelatedTopics(topicData, uid, next); + }, + ], next); + }, + }, next); + }, + function (results, next) { + topicData.posts = results.posts; + topicData.category = results.category; + topicData.thread_tools = results.threadTools.tools; + topicData.isFollowing = results.isFollowing[0]; + topicData.isNotFollowing = !results.isFollowing[0] && !results.isIgnoring[0]; + 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; + topicData.deleted = parseInt(topicData.deleted, 10) === 1; + topicData.locked = parseInt(topicData.locked, 10) === 1; + topicData.pinned = parseInt(topicData.pinned, 10) === 1; + + topicData.icons = []; + + plugins.fireHook('filter:topic.get', { topic: topicData, uid: uid }, next); + }, + function (data, next) { + next(null, data.topic); + }, + ], callback); +}; + +function getMainPostAndReplies(topic, set, uid, start, stop, reverse, callback) { + async.waterfall([ + function (next) { + if (stop > 0) { + stop -= 1; + if (start > 0) { + start -= 1; } - var replies = posts; - if (topic.mainPid && start === 0) { - posts[0].index = 0; - replies = posts.slice(1); - } - - 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); - } + posts.getPidsFromSet(set, start, stop, reverse, next); + }, + function (pids, next) { + if (!pids.length && !topic.mainPid) { + return callback(null, []); + } - Topics.getMainPost = function (tid, uid, callback) { - Topics.getMainPosts([tid], uid, function (err, mainPosts) { - callback(err, Array.isArray(mainPosts) && mainPosts.length ? mainPosts[0] : null); - }); - }; + if (topic.mainPid && start === 0) { + pids.unshift(topic.mainPid); + } + posts.getPostsByPids(pids, uid, next); + }, + function (posts, next) { + if (!posts.length) { + return next(null, []); + } + var replies = posts; + if (topic.mainPid && start === 0) { + posts[0].index = 0; + replies = posts.slice(1); + } - Topics.getMainPids = function (tids, callback) { - if (!Array.isArray(tids) || !tids.length) { - return callback(null, []); - } + Topics.calculatePostIndices(replies, start, stop, topic.postcount, reverse); - Topics.getTopicsFields(tids, ['mainPid'], function (err, topicData) { - if (err) { - return callback(err); - } + 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); + }); +}; + +Topics.getMainPids = function (tids, callback) { + if (!Array.isArray(tids) || !tids.length) { + return callback(null, []); + } + async.waterfall([ + function (next) { + Topics.getTopicsFields(tids, ['mainPid'], next); + }, + function (topicData, next) { var mainPids = topicData.map(function (topic) { return topic && topic.mainPid; }); - callback(null, mainPids); - }); - }; - - Topics.getMainPosts = function (tids, uid, callback) { - Topics.getMainPids(tids, function (err, mainPids) { - if (err) { - return callback(err); - } - getMainPosts(mainPids, uid, callback); - }); - }; - - function getMainPosts(mainPids, uid, callback) { - posts.getPostsByPids(mainPids, uid, function (err, postData) { - if (err) { - return callback(err); - } + next(null, mainPids); + }, + ], callback); +}; + +Topics.getMainPosts = function (tids, uid, callback) { + async.waterfall([ + function (next) { + Topics.getMainPids(tids, next); + }, + function (mainPids, next) { + getMainPosts(mainPids, uid, next); + }, + ], callback); +}; + +function getMainPosts(mainPids, uid, callback) { + async.waterfall([ + function (next) { + posts.getPostsByPids(mainPids, uid, next); + }, + function (postData, next) { postData.forEach(function (post) { if (post) { post.index = 0; } }); - Topics.addPostData(postData, uid, callback); - }); + Topics.addPostData(postData, uid, next); + }, + ], callback); +} + +Topics.isLocked = function (tid, callback) { + Topics.getTopicField(tid, 'locked', function (err, locked) { + callback(err, parseInt(locked, 10) === 1); + }); +}; + +Topics.search = function (tid, term, callback) { + if (plugins.hasListeners('filter:topic.search')) { + plugins.fireHook('filter:topic.search', { + tid: tid, + term: term, + }, callback); + } else { + callback(new Error('[[error:no-plugins-available]]'), []); } - - Topics.isLocked = function (tid, callback) { - Topics.getTopicField(tid, 'locked', function (err, locked) { - callback(err, parseInt(locked, 10) === 1); - }); - }; - - Topics.search = function (tid, term, callback) { - if (plugins.hasListeners('filter:topic.search')) { - plugins.fireHook('filter:topic.search', { - tid: tid, - term: term, - }, callback); - } else { - callback(new Error('[[error:no-plugins-available]]'), []); - } - }; -}(exports)); +}; diff --git a/src/user.js b/src/user.js index 6e32a973c5..d319e930cf 100644 --- a/src/user.js +++ b/src/user.js @@ -1,6 +1,6 @@ 'use strict'; -var async = require('async'); +var async = require('async'); var _ = require('underscore'); var groups = require('./groups'); diff --git a/src/user/email.js b/src/user/email.js index d0cdbbed3c..30d8340e8a 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -12,106 +12,106 @@ var db = require('../database'); 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); - }); - }; +var UserEmail = module.exports; - UserEmail.available = function (email, callback) { - db.isSortedSetMember('email:uid', email.toLowerCase(), function (err, exists) { - callback(err, !exists); - }); - }; +UserEmail.exists = function (email, callback) { + user.getUidByEmail(email.toLowerCase(), function (err, exists) { + callback(err, !!exists); + }); +}; - UserEmail.sendValidationEmail = function (uid, email, callback) { - callback = callback || function () {}; - var confirm_code = utils.generateUUID(); - var confirm_link = nconf.get('url') + '/confirm/' + confirm_code; +UserEmail.available = function (email, callback) { + db.isSortedSetMember('email:uid', email.toLowerCase(), function (err, exists) { + callback(err, !exists); + }); +}; - var emailInterval = meta.config.hasOwnProperty('emailConfirmInterval') ? parseInt(meta.config.emailConfirmInterval, 10) : 10; +UserEmail.sendValidationEmail = function (uid, email, callback) { + callback = callback || function () {}; + var confirm_code = utils.generateUUID(); + var confirm_link = nconf.get('url') + '/confirm/' + confirm_code; - async.waterfall([ - function (next) { - db.get('uid:' + uid + ':confirm:email:sent', next); - }, - function (sent, next) { - if (sent) { - return next(new Error('[[error:confirm-email-already-sent, ' + emailInterval + ']]')); - } - db.set('uid:' + uid + ':confirm:email:sent', 1, next); - }, - function (next) { - db.pexpireAt('uid:' + uid + ':confirm:email:sent', Date.now() + (emailInterval * 60 * 1000), next); - }, - function (next) { - plugins.fireHook('filter:user.verify.code', confirm_code, next); - }, - function (_confirm_code, next) { - confirm_code = _confirm_code; - db.setObject('confirm:' + confirm_code, { - email: email.toLowerCase(), - uid: uid, - }, next); - }, - function (next) { - db.expireAt('confirm:' + confirm_code, Math.floor((Date.now() / 1000) + (60 * 60 * 24)), next); - }, - function (next) { - user.getUserField(uid, 'username', next); - }, - function (username, next) { - var title = meta.config.title || meta.config.browserTitle || 'NodeBB'; - translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) { - var data = { - site_title: title, - username: username, - confirm_link: confirm_link, - confirm_code: confirm_code, + var emailInterval = meta.config.hasOwnProperty('emailConfirmInterval') ? parseInt(meta.config.emailConfirmInterval, 10) : 10; - subject: subject, - template: 'welcome', - uid: uid, - }; + async.waterfall([ + function (next) { + db.get('uid:' + uid + ':confirm:email:sent', next); + }, + function (sent, next) { + if (sent) { + return next(new Error('[[error:confirm-email-already-sent, ' + emailInterval + ']]')); + } + db.set('uid:' + uid + ':confirm:email:sent', 1, next); + }, + function (next) { + db.pexpireAt('uid:' + uid + ':confirm:email:sent', Date.now() + (emailInterval * 60 * 1000), next); + }, + function (next) { + plugins.fireHook('filter:user.verify.code', confirm_code, next); + }, + function (_confirm_code, next) { + confirm_code = _confirm_code; + db.setObject('confirm:' + confirm_code, { + email: email.toLowerCase(), + uid: uid, + }, next); + }, + function (next) { + db.expireAt('confirm:' + confirm_code, Math.floor((Date.now() / 1000) + (60 * 60 * 24)), next); + }, + function (next) { + user.getUserField(uid, 'username', next); + }, + function (username, next) { + var title = meta.config.title || meta.config.browserTitle || 'NodeBB'; + translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) { + var data = { + site_title: title, + username: username, + confirm_link: confirm_link, + confirm_code: confirm_code, - if (plugins.hasListeners('action:user.verify')) { - plugins.fireHook('action:user.verify', { uid: uid, data: data }); - next(); - } else { - emailer.send('welcome', uid, data, next); - } - }); - }, - function (next) { - next(null, confirm_code); - }, - ], callback); - }; + subject: subject, + template: 'welcome', + uid: uid, + }; - UserEmail.confirm = function (code, callback) { - 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]]')); + if (plugins.hasListeners('action:user.verify')) { + plugins.fireHook('action:user.verify', { uid: uid, data: data }); + next(); + } else { + emailer.send('welcome', uid, data, next); } - async.series([ - async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1), - async.apply(db.delete, 'confirm:' + code), - async.apply(db.delete, 'uid:' + confirmObj.uid + ':confirm:email:sent'), - function (next) { - db.sortedSetRemove('users:notvalidated', confirmObj.uid, next); - }, - function (next) { - plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next); - }, - ], next); - }, - ], function (err) { - callback(err); - }); - }; -}(exports)); + }); + }, + function (next) { + next(null, confirm_code); + }, + ], callback); +}; + +UserEmail.confirm = function (code, callback) { + 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), + async.apply(db.delete, 'uid:' + confirmObj.uid + ':confirm:email:sent'), + function (next) { + db.sortedSetRemove('users:notvalidated', confirmObj.uid, next); + }, + function (next) { + plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next); + }, + ], next); + }, + ], function (err) { + callback(err); + }); +}; diff --git a/src/user/reset.js b/src/user/reset.js index 25bd4118f9..438d629225 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -12,157 +12,157 @@ var db = require('../database'); var meta = require('../meta'); var emailer = require('../emailer'); -(function (UserReset) { - var twoHours = 7200000; - - UserReset.validate = function (code, callback) { - async.waterfall([ - function (next) { - db.getObjectField('reset:uid', code, next); - }, - function (uid, next) { - if (!uid) { - return callback(null, false); - } - db.sortedSetScore('reset:issueDate', code, next); - }, - function (issueDate, next) { - next(null, parseInt(issueDate, 10) > Date.now() - twoHours); - }, - ], callback); - }; - - UserReset.generate = function (uid, callback) { - var code = utils.generateUUID(); - async.parallel([ - async.apply(db.setObjectField, 'reset:uid', code, uid), - async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), - ], function (err) { - callback(err, code); - }); - }; - - function canGenerate(uid, callback) { - async.waterfall([ - function (next) { - db.sortedSetScore('reset:issueDate:uid', uid, next); - }, - function (score, next) { - if (score > Date.now() - (1000 * 60)) { - return next(new Error('[[error:cant-reset-password-more-than-once-a-minute]]')); - } - next(); - }, - ], callback); - } - - UserReset.send = function (email, callback) { - var uid; - async.waterfall([ - function (next) { - user.getUidByEmail(email, next); - }, - function (_uid, next) { - if (!_uid) { - return next(new Error('[[error:invalid-email]]')); - } - - uid = _uid; - canGenerate(uid, next); - }, - function (next) { - db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid, next); - }, - function (next) { - UserReset.generate(uid, next); - }, - function (code, next) { - translator.translate('[[email:password-reset-requested, ' + (meta.config.title || 'NodeBB') + ']]', meta.config.defaultLang, function (subject) { - next(null, subject, code); - }); - }, - function (subject, code, next) { - var reset_link = nconf.get('url') + '/reset/' + code; - emailer.send('reset', uid, { - site_title: (meta.config.title || 'NodeBB'), - reset_link: reset_link, - subject: subject, - template: 'reset', - uid: uid, - }, next); - }, - ], callback); - }; - - UserReset.commit = function (code, password, callback) { - var uid; - async.waterfall([ - function (next) { - user.isPasswordValid(password, next); - }, - function (next) { - UserReset.validate(code, next); - }, - function (validated, next) { - if (!validated) { - return next(new Error('[[error:reset-code-not-valid]]')); - } - db.getObjectField('reset:uid', code, next); - }, - function (_uid, next) { - uid = _uid; - if (!uid) { - return next(new Error('[[error:reset-code-not-valid]]')); - } - - user.hashPassword(password, next); - }, - function (hash, next) { - async.parallel([ - async.apply(user.setUserField, uid, 'password', hash), - async.apply(db.deleteObjectField, 'reset:uid', code), - 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), - ], next); - }, - ], callback); - }; - - UserReset.updateExpiry = function (uid, callback) { - var oneDay = 1000 * 60 * 60 * 24; - var expireDays = parseInt(meta.config.passwordExpiryDays || 0, 10); - var expiry = Date.now() + (oneDay * expireDays); - - callback = callback || function () {}; - user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0, callback); - }; - - UserReset.clean = function (callback) { - async.waterfall([ - function (next) { - async.parallel({ - tokens: function (next) { - db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours, next); - }, - uids: function (next) { - db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours, next); - }, - }, next); - }, - function (results, next) { - if (!results.tokens.length && !results.uids.length) { - return next(); - } - - winston.verbose('[UserReset.clean] Removing ' + results.tokens.length + ' reset tokens from database'); - 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), - ], next); - }, - ], callback); - }; -}(exports)); +var UserReset = module.exports; + +var twoHours = 7200000; + +UserReset.validate = function (code, callback) { + async.waterfall([ + function (next) { + db.getObjectField('reset:uid', code, next); + }, + function (uid, next) { + if (!uid) { + return callback(null, false); + } + db.sortedSetScore('reset:issueDate', code, next); + }, + function (issueDate, next) { + next(null, parseInt(issueDate, 10) > Date.now() - twoHours); + }, + ], callback); +}; + +UserReset.generate = function (uid, callback) { + var code = utils.generateUUID(); + async.parallel([ + async.apply(db.setObjectField, 'reset:uid', code, uid), + async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), + ], function (err) { + callback(err, code); + }); +}; + +function canGenerate(uid, callback) { + async.waterfall([ + function (next) { + db.sortedSetScore('reset:issueDate:uid', uid, next); + }, + function (score, next) { + if (score > Date.now() - (1000 * 60)) { + return next(new Error('[[error:cant-reset-password-more-than-once-a-minute]]')); + } + next(); + }, + ], callback); +} + +UserReset.send = function (email, callback) { + var uid; + async.waterfall([ + function (next) { + user.getUidByEmail(email, next); + }, + function (_uid, next) { + if (!_uid) { + return next(new Error('[[error:invalid-email]]')); + } + + uid = _uid; + canGenerate(uid, next); + }, + function (next) { + db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid, next); + }, + function (next) { + UserReset.generate(uid, next); + }, + function (code, next) { + translator.translate('[[email:password-reset-requested, ' + (meta.config.title || 'NodeBB') + ']]', meta.config.defaultLang, function (subject) { + next(null, subject, code); + }); + }, + function (subject, code, next) { + var reset_link = nconf.get('url') + '/reset/' + code; + emailer.send('reset', uid, { + site_title: (meta.config.title || 'NodeBB'), + reset_link: reset_link, + subject: subject, + template: 'reset', + uid: uid, + }, next); + }, + ], callback); +}; + +UserReset.commit = function (code, password, callback) { + var uid; + async.waterfall([ + function (next) { + user.isPasswordValid(password, next); + }, + function (next) { + UserReset.validate(code, next); + }, + function (validated, next) { + if (!validated) { + return next(new Error('[[error:reset-code-not-valid]]')); + } + db.getObjectField('reset:uid', code, next); + }, + function (_uid, next) { + uid = _uid; + if (!uid) { + return next(new Error('[[error:reset-code-not-valid]]')); + } + + user.hashPassword(password, next); + }, + function (hash, next) { + async.parallel([ + async.apply(user.setUserField, uid, 'password', hash), + async.apply(db.deleteObjectField, 'reset:uid', code), + 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), + ], next); + }, + ], callback); +}; + +UserReset.updateExpiry = function (uid, callback) { + var oneDay = 1000 * 60 * 60 * 24; + var expireDays = parseInt(meta.config.passwordExpiryDays || 0, 10); + var expiry = Date.now() + (oneDay * expireDays); + + callback = callback || function () {}; + user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0, callback); +}; + +UserReset.clean = function (callback) { + async.waterfall([ + function (next) { + async.parallel({ + tokens: function (next) { + db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours, next); + }, + uids: function (next) { + db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours, next); + }, + }, next); + }, + function (results, next) { + if (!results.tokens.length && !results.uids.length) { + return next(); + } + + winston.verbose('[UserReset.clean] Removing ' + results.tokens.length + ' reset tokens from database'); + 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), + ], next); + }, + ], callback); +};