From b60dbe7d1e9ac5b1df5a36a0194e747742da7c41 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Mon, 29 May 2017 12:14:55 -0600
Subject: [PATCH] Unwrap meta modules
---
src/meta.js | 20 +-
src/meta/configs.js | 250 ++++++++---------
src/meta/css.js | 286 ++++++++++---------
src/meta/dependencies.js | 117 ++++----
src/meta/errors.js | 94 ++++---
src/meta/js.js | 580 +++++++++++++++++++--------------------
src/meta/logs.js | 22 +-
src/meta/settings.js | 99 ++++---
src/meta/sounds.js | 201 +++++++-------
src/meta/tags.js | 272 +++++++++---------
src/meta/themes.js | 293 ++++++++++----------
11 files changed, 1111 insertions(+), 1123 deletions(-)
diff --git a/src/meta.js b/src/meta.js
index 59c3447cf4..cb2a381d6d 100644
--- a/src/meta.js
+++ b/src/meta.js
@@ -12,16 +12,16 @@ var Meta = module.exports;
Meta.reloadRequired = false;
-require('./meta/configs')(Meta);
-require('./meta/themes')(Meta);
-require('./meta/js')(Meta);
-require('./meta/css')(Meta);
-require('./meta/sounds')(Meta);
-require('./meta/settings')(Meta);
-require('./meta/logs')(Meta);
-require('./meta/errors')(Meta);
-require('./meta/tags')(Meta);
-require('./meta/dependencies')(Meta);
+Meta.configs = require('./meta/configs');
+Meta.themes = require('./meta/themes');
+Meta.js = require('./meta/js');
+Meta.css = require('./meta/css');
+Meta.sounds = require('./meta/sounds');
+Meta.settings = require('./meta/settings');
+Meta.logs = require('./meta/logs');
+Meta.errors = require('./meta/errors');
+Meta.tags = require('./meta/tags');
+Meta.dependencies = require('./meta/dependencies');
Meta.templates = require('./meta/templates');
Meta.blacklist = require('./meta/blacklist');
Meta.languages = require('./meta/languages');
diff --git a/src/meta/configs.js b/src/meta/configs.js
index daaa807d19..925ff61255 100644
--- a/src/meta/configs.js
+++ b/src/meta/configs.js
@@ -6,142 +6,142 @@ var nconf = require('nconf');
var db = require('../database');
var pubsub = require('../pubsub');
+var Meta = require('../meta');
var cacheBuster = require('./cacheBuster');
-module.exports = function (Meta) {
- Meta.config = {};
- Meta.configs = {};
-
- Meta.configs.init = function (callback) {
- delete Meta.config;
-
- async.waterfall([
- function (next) {
- Meta.configs.list(next);
- },
- function (config, next) {
- cacheBuster.read(function (err, buster) {
- if (err) {
- return next(err);
- }
-
- config['cache-buster'] = 'v=' + (buster || Date.now());
-
- Meta.config = config;
- next();
- });
- },
- ], callback);
- };
-
- Meta.configs.list = function (callback) {
- db.getObject('config', function (err, config) {
- config = config || {};
- config.version = nconf.get('version');
- config.registry = nconf.get('registry');
- callback(err, config);
- });
- };
-
- Meta.configs.get = function (field, callback) {
- db.getObjectField('config', field, callback);
- };
-
- Meta.configs.getFields = function (fields, callback) {
- db.getObjectFields('config', fields, callback);
- };
-
- Meta.configs.set = function (field, value, callback) {
- callback = callback || function () {};
- if (!field) {
- return callback(new Error('[[error:invalid-data]]'));
- }
+var Configs = module.exports;
- var data = {};
- data[field] = value;
- Meta.configs.setMultiple(data, callback);
- };
-
-
- Meta.configs.setMultiple = function (data, callback) {
- async.waterfall([
- function (next) {
- processConfig(data, next);
- },
- function (next) {
- db.setObject('config', data, next);
- },
- function (next) {
- updateConfig(data);
- setImmediate(next);
- },
- ], callback);
- };
+Meta.config = {};
- function processConfig(data, callback) {
- if (data.customCSS) {
- return saveRenderedCss(data, callback);
- }
- setImmediate(callback);
- }
+Configs.init = function (callback) {
+ Meta.config = null;
- function saveRenderedCss(data, callback) {
- var less = require('less');
- async.waterfall([
- function (next) {
- less.render(data.customCSS, {
- compress: true,
- }, next);
- },
- function (lessObject, next) {
- data.renderedCustomCSS = lessObject.css;
- setImmediate(next);
- },
- ], callback);
- }
+ async.waterfall([
+ function (next) {
+ Configs.list(next);
+ },
+ function (config, next) {
+ cacheBuster.read(function (err, buster) {
+ if (err) {
+ return next(err);
+ }
- function updateConfig(config) {
- updateLocalConfig(config);
- pubsub.publish('config:update', config);
- }
+ config['cache-buster'] = 'v=' + (buster || Date.now());
- function updateLocalConfig(config) {
- for (var field in config) {
- if (config.hasOwnProperty(field)) {
- Meta.config[field] = config[field];
- }
- }
+ Meta.config = config;
+ next();
+ });
+ },
+ ], callback);
+};
+
+Configs.list = function (callback) {
+ db.getObject('config', function (err, config) {
+ config = config || {};
+ config.version = nconf.get('version');
+ config.registry = nconf.get('registry');
+ callback(err, config);
+ });
+};
+
+Configs.get = function (field, callback) {
+ db.getObjectField('config', field, callback);
+};
+
+Configs.getFields = function (fields, callback) {
+ db.getObjectFields('config', fields, callback);
+};
+
+Configs.set = function (field, value, callback) {
+ callback = callback || function () {};
+ if (!field) {
+ return callback(new Error('[[error:invalid-data]]'));
}
- pubsub.on('config:update', function onConfigReceived(config) {
- if (typeof config === 'object' && Meta.config) {
- updateLocalConfig(config);
+ var data = {};
+ data[field] = value;
+ Configs.setMultiple(data, callback);
+};
+
+
+Configs.setMultiple = function (data, callback) {
+ async.waterfall([
+ function (next) {
+ processConfig(data, next);
+ },
+ function (next) {
+ db.setObject('config', data, next);
+ },
+ function (next) {
+ updateConfig(data);
+ setImmediate(next);
+ },
+ ], callback);
+};
+
+function processConfig(data, callback) {
+ if (data.customCSS) {
+ return saveRenderedCss(data, callback);
+ }
+ setImmediate(callback);
+}
+
+function saveRenderedCss(data, callback) {
+ var less = require('less');
+ async.waterfall([
+ function (next) {
+ less.render(data.customCSS, {
+ compress: true,
+ }, next);
+ },
+ function (lessObject, next) {
+ data.renderedCustomCSS = lessObject.css;
+ setImmediate(next);
+ },
+ ], callback);
+}
+
+function updateConfig(config) {
+ updateLocalConfig(config);
+ pubsub.publish('config:update', config);
+}
+
+function updateLocalConfig(config) {
+ for (var field in config) {
+ if (config.hasOwnProperty(field)) {
+ Meta.config[field] = config[field];
}
- });
+ }
+}
- Meta.configs.setOnEmpty = function (values, callback) {
- async.waterfall([
- function (next) {
- db.getObject('config', next);
- },
- function (data, next) {
- data = data || {};
- var empty = {};
- Object.keys(values).forEach(function (key) {
- if (!data.hasOwnProperty(key)) {
- empty[key] = values[key];
- }
- });
- if (Object.keys(empty).length) {
- db.setObject('config', empty, next);
- } else {
- setImmediate(next);
+pubsub.on('config:update', function onConfigReceived(config) {
+ if (typeof config === 'object' && Meta.config) {
+ updateLocalConfig(config);
+ }
+});
+
+Configs.setOnEmpty = function (values, callback) {
+ async.waterfall([
+ function (next) {
+ db.getObject('config', next);
+ },
+ function (data, next) {
+ data = data || {};
+ var empty = {};
+ Object.keys(values).forEach(function (key) {
+ if (!data.hasOwnProperty(key)) {
+ empty[key] = values[key];
}
- },
- ], callback);
- };
+ });
+ if (Object.keys(empty).length) {
+ db.setObject('config', empty, next);
+ } else {
+ setImmediate(next);
+ }
+ },
+ ], callback);
+};
- Meta.configs.remove = function (field, callback) {
- db.deleteObjectField('config', field, callback);
- };
+Configs.remove = function (field, callback) {
+ db.deleteObjectField('config', field, callback);
};
diff --git a/src/meta/css.js b/src/meta/css.js
index f2abe608ac..3db85a50f3 100644
--- a/src/meta/css.js
+++ b/src/meta/css.js
@@ -11,158 +11,156 @@ var db = require('../database');
var file = require('../file');
var minifier = require('./minifier');
-module.exports = function (Meta) {
- Meta.css = {};
-
- var buildImports = {
- client: function (source) {
- return '@import "./theme";\n' + source + '\n' + [
- '@import "font-awesome";',
- '@import (inline) "../public/vendor/jquery/css/smoothness/jquery-ui.css";',
- '@import (inline) "../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
- '@import (inline) "../public/vendor/colorpicker/colorpicker.css";',
- '@import (inline) "../node_modules/cropperjs/dist/cropper.css";',
- '@import "../../public/less/flags.less";',
- '@import "../../public/less/blacklist.less";',
- '@import "../../public/less/generics.less";',
- '@import "../../public/less/mixins.less";',
- '@import "../../public/less/global.less";',
- ].map(function (str) {
- return str.replace(/\//g, path.sep);
- }).join('\n');
- },
- admin: function (source) {
- return source + '\n' + [
- '@import "font-awesome";',
- '@import "../public/less/admin/admin";',
- '@import "../public/less/generics.less";',
- '@import (inline) "../public/vendor/colorpicker/colorpicker.css";',
- '@import (inline) "../public/vendor/jquery/css/smoothness/jquery-ui.css";',
- '@import (inline) "../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
- '@import (inline) "../public/vendor/mdl/material.css";',
- ].map(function (str) {
- return str.replace(/\//g, path.sep);
- }).join('\n');
- },
- };
+var CSS = module.exports;
+
+var buildImports = {
+ client: function (source) {
+ return '@import "./theme";\n' + source + '\n' + [
+ '@import "font-awesome";',
+ '@import (inline) "../public/vendor/jquery/css/smoothness/jquery-ui.css";',
+ '@import (inline) "../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
+ '@import (inline) "../public/vendor/colorpicker/colorpicker.css";',
+ '@import (inline) "../node_modules/cropperjs/dist/cropper.css";',
+ '@import "../../public/less/flags.less";',
+ '@import "../../public/less/blacklist.less";',
+ '@import "../../public/less/generics.less";',
+ '@import "../../public/less/mixins.less";',
+ '@import "../../public/less/global.less";',
+ ].map(function (str) {
+ return str.replace(/\//g, path.sep);
+ }).join('\n');
+ },
+ admin: function (source) {
+ return source + '\n' + [
+ '@import "font-awesome";',
+ '@import "../public/less/admin/admin";',
+ '@import "../public/less/generics.less";',
+ '@import (inline) "../public/vendor/colorpicker/colorpicker.css";',
+ '@import (inline) "../public/vendor/jquery/css/smoothness/jquery-ui.css";',
+ '@import (inline) "../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
+ '@import (inline) "../public/vendor/mdl/material.css";',
+ ].map(function (str) {
+ return str.replace(/\//g, path.sep);
+ }).join('\n');
+ },
+};
- function filterMissingFiles(filepaths, callback) {
- async.filter(filepaths, function (filepath, next) {
- file.exists(path.join(__dirname, '../../node_modules', filepath), function (err, exists) {
- if (!exists) {
- winston.warn('[meta/css] File not found! ' + filepath);
- }
+function filterMissingFiles(filepaths, callback) {
+ async.filter(filepaths, function (filepath, next) {
+ file.exists(path.join(__dirname, '../../node_modules', filepath), function (err, exists) {
+ if (!exists) {
+ winston.warn('[meta/css] File not found! ' + filepath);
+ }
+
+ next(err, exists);
+ });
+ }, callback);
+}
+
+function getImports(files, prefix, extension, callback) {
+ var pluginDirectories = [];
+ var source = '';
+
+ files.forEach(function (styleFile) {
+ if (styleFile.endsWith(extension)) {
+ source += prefix + path.sep + styleFile + '";';
+ } else {
+ pluginDirectories.push(styleFile);
+ }
+ });
+
+ async.each(pluginDirectories, function (directory, next) {
+ file.walk(directory, function (err, styleFiles) {
+ if (err) {
+ return next(err);
+ }
- next(err, exists);
+ styleFiles.forEach(function (styleFile) {
+ source += prefix + path.sep + styleFile + '";';
});
- }, callback);
- }
- function getImports(files, prefix, extension, callback) {
- var pluginDirectories = [];
- var source = '';
+ next();
+ });
+ }, function (err) {
+ callback(err, source);
+ });
+}
+
+function getBundleMetadata(target, callback) {
+ var paths = [
+ path.join(__dirname, '../../node_modules'),
+ path.join(__dirname, '../../public/vendor/fontawesome/less'),
+ ];
+
+ async.waterfall([
+ function (next) {
+ if (target !== 'client') {
+ return next(null, null);
+ }
- files.forEach(function (styleFile) {
- if (styleFile.endsWith(extension)) {
- source += prefix + path.sep + styleFile + '";';
- } else {
- pluginDirectories.push(styleFile);
+ db.getObjectFields('config', ['theme:type', 'theme:id'], next);
+ },
+ function (themeData, next) {
+ if (target === 'client') {
+ var themeId = (themeData['theme:id'] || 'nodebb-theme-persona');
+ var baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla'));
+ paths.unshift(baseThemePath);
}
- });
- async.each(pluginDirectories, function (directory, next) {
- file.walk(directory, function (err, styleFiles) {
- if (err) {
- return next(err);
- }
+ async.parallel({
+ less: function (cb) {
+ async.waterfall([
+ function (next) {
+ filterMissingFiles(plugins.lessFiles, next);
+ },
+ function (lessFiles, next) {
+ getImports(lessFiles, '\n@import ".', '.less', next);
+ },
+ ], cb);
+ },
+ css: function (cb) {
+ async.waterfall([
+ function (next) {
+ filterMissingFiles(plugins.cssFiles, next);
+ },
+ function (cssFiles, next) {
+ getImports(cssFiles, '\n@import (inline) ".', '.css', next);
+ },
+ ], cb);
+ },
+ }, next);
+ },
+ function (result, next) {
+ var cssImports = result.css;
+ var lessImports = result.less;
- styleFiles.forEach(function (styleFile) {
- source += prefix + path.sep + styleFile + '";';
- });
+ var imports = cssImports + '\n' + lessImports;
+ imports = buildImports[target](imports);
- next();
- });
- }, function (err) {
- callback(err, source);
- });
- }
-
- function getBundleMetadata(target, callback) {
- var paths = [
- path.join(__dirname, '../../node_modules'),
- path.join(__dirname, '../../public/vendor/fontawesome/less'),
- ];
-
- async.waterfall([
- function (next) {
- if (target !== 'client') {
- return next(null, null);
- }
-
- db.getObjectFields('config', ['theme:type', 'theme:id'], next);
- },
- function (themeData, next) {
- if (target === 'client') {
- var themeId = (themeData['theme:id'] || 'nodebb-theme-persona');
- var baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla'));
- paths.unshift(baseThemePath);
- }
-
- async.parallel({
- less: function (cb) {
- async.waterfall([
- function (next) {
- filterMissingFiles(plugins.lessFiles, next);
- },
- function (lessFiles, next) {
- getImports(lessFiles, '\n@import ".', '.less', next);
- },
- ], cb);
- },
- css: function (cb) {
- async.waterfall([
- function (next) {
- filterMissingFiles(plugins.cssFiles, next);
- },
- function (cssFiles, next) {
- getImports(cssFiles, '\n@import (inline) ".', '.css', next);
- },
- ], cb);
- },
- }, next);
- },
- function (result, next) {
- var cssImports = result.css;
- var lessImports = result.less;
-
- var imports = cssImports + '\n' + lessImports;
- imports = buildImports[target](imports);
-
- next(null, imports);
- },
- ], function (err, imports) {
- if (err) {
- return callback(err);
- }
+ next(null, imports);
+ },
+ ], function (err, imports) {
+ if (err) {
+ return callback(err);
+ }
+
+ callback(null, { paths: paths, imports: imports });
+ });
+}
+
+CSS.buildBundle = function (target, fork, callback) {
+ async.waterfall([
+ function (next) {
+ getBundleMetadata(target, next);
+ },
+ function (data, next) {
+ var minify = global.env !== 'development';
+ minifier.css.bundle(data.imports, data.paths, minify, fork, next);
+ },
+ function (bundle, next) {
+ var filename = (target === 'client' ? 'stylesheet' : 'admin') + '.css';
- callback(null, { paths: paths, imports: imports });
- });
- }
-
- Meta.css.buildBundle = function (target, fork, callback) {
- async.waterfall([
- function (next) {
- getBundleMetadata(target, next);
- },
- function (data, next) {
- var minify = global.env !== 'development';
- minifier.css.bundle(data.imports, data.paths, minify, fork, next);
- },
- function (bundle, next) {
- var filename = (target === 'client' ? 'stylesheet' : 'admin') + '.css';
-
- fs.writeFile(path.join(__dirname, '../../build/public', filename), bundle.code, next);
- },
- ], callback);
- };
+ fs.writeFile(path.join(__dirname, '../../build/public', filename), bundle.code, next);
+ },
+ ], callback);
};
diff --git a/src/meta/dependencies.js b/src/meta/dependencies.js
index 3a16f0e9e5..db403732ec 100644
--- a/src/meta/dependencies.js
+++ b/src/meta/dependencies.js
@@ -9,73 +9,72 @@ require('colors');
var pkg = require('../../package.json');
-module.exports = function (Meta) {
- Meta.dependencies = {};
- var depsMissing = false;
- var depsOutdated = false;
+var Dependencies = module.exports;
- Meta.dependencies.check = function (callback) {
- var modules = Object.keys(pkg.dependencies);
+var depsMissing = false;
+var depsOutdated = false;
- winston.verbose('Checking dependencies for outdated modules');
+Dependencies.check = function (callback) {
+ var modules = Object.keys(pkg.dependencies);
- async.each(modules, Meta.dependencies.checkModule, function (err) {
- if (err) {
- return callback(err);
- }
+ winston.verbose('Checking dependencies for outdated modules');
- if (depsMissing) {
- callback(new Error('dependencies-missing'));
- } else if (depsOutdated) {
- callback(global.env !== 'development' ? new Error('dependencies-out-of-date') : null);
- } else {
- callback(null);
- }
- });
- };
+ async.each(modules, Dependencies.checkModule, function (err) {
+ if (err) {
+ return callback(err);
+ }
+
+ if (depsMissing) {
+ callback(new Error('dependencies-missing'));
+ } else if (depsOutdated) {
+ callback(global.env !== 'development' ? new Error('dependencies-out-of-date') : null);
+ } else {
+ callback(null);
+ }
+ });
+};
- Meta.dependencies.checkModule = function (moduleName, callback) {
- fs.readFile(path.join(__dirname, '../../node_modules/', moduleName, 'package.json'), {
- encoding: 'utf-8',
- }, function (err, pkgData) {
- if (err) {
- // If a bundled plugin/theme is not present, skip the dep check (#3384)
- if (err.code === 'ENOENT' && (moduleName === 'nodebb-rewards-essentials' || moduleName.startsWith('nodebb-plugin') || moduleName.startsWith('nodebb-theme'))) {
- winston.warn('[meta/dependencies] Bundled plugin ' + moduleName + ' not found, skipping dependency check.');
- return callback(null, true);
- }
- return callback(err);
+Dependencies.checkModule = function (moduleName, callback) {
+ fs.readFile(path.join(__dirname, '../../node_modules/', moduleName, 'package.json'), {
+ encoding: 'utf-8',
+ }, function (err, pkgData) {
+ if (err) {
+ // If a bundled plugin/theme is not present, skip the dep check (#3384)
+ if (err.code === 'ENOENT' && (moduleName === 'nodebb-rewards-essentials' || moduleName.startsWith('nodebb-plugin') || moduleName.startsWith('nodebb-theme'))) {
+ winston.warn('[meta/dependencies] Bundled plugin ' + moduleName + ' not found, skipping dependency check.');
+ return callback(null, true);
}
+ return callback(err);
+ }
- pkgData = Meta.dependencies.parseModuleData(moduleName, pkgData);
+ pkgData = Dependencies.parseModuleData(moduleName, pkgData);
- var satisfies = Meta.dependencies.doesSatisfy(pkgData, pkg.dependencies[moduleName]);
- callback(null, satisfies);
- });
- };
+ var satisfies = Dependencies.doesSatisfy(pkgData, pkg.dependencies[moduleName]);
+ callback(null, satisfies);
+ });
+};
- Meta.dependencies.parseModuleData = function (moduleName, pkgData) {
- try {
- pkgData = JSON.parse(pkgData);
- } catch (e) {
- winston.warn('[' + 'missing'.red + '] ' + moduleName.bold + ' is a required dependency but could not be found\n');
- depsMissing = true;
- return null;
- }
- return pkgData;
- };
+Dependencies.parseModuleData = function (moduleName, pkgData) {
+ try {
+ pkgData = JSON.parse(pkgData);
+ } catch (e) {
+ winston.warn('[' + 'missing'.red + '] ' + moduleName.bold + ' is a required dependency but could not be found\n');
+ depsMissing = true;
+ return null;
+ }
+ return pkgData;
+};
- Meta.dependencies.doesSatisfy = function (moduleData, packageJSONVersion) {
- if (!moduleData) {
- return false;
- }
- var versionOk = !semver.validRange(packageJSONVersion) || semver.satisfies(moduleData.version, packageJSONVersion);
- var githubRepo = moduleData._resolved && moduleData._resolved.indexOf('//github.com') !== -1;
- var satisfies = versionOk || githubRepo;
- if (!satisfies) {
- winston.warn('[' + 'outdated'.yellow + '] ' + moduleData.name.bold + ' installed v' + moduleData.version + ', package.json requires ' + packageJSONVersion + '\n');
- depsOutdated = true;
- }
- return satisfies;
- };
+Dependencies.doesSatisfy = function (moduleData, packageJSONVersion) {
+ if (!moduleData) {
+ return false;
+ }
+ var versionOk = !semver.validRange(packageJSONVersion) || semver.satisfies(moduleData.version, packageJSONVersion);
+ var githubRepo = moduleData._resolved && moduleData._resolved.indexOf('//github.com') !== -1;
+ var satisfies = versionOk || githubRepo;
+ if (!satisfies) {
+ winston.warn('[' + 'outdated'.yellow + '] ' + moduleData.name.bold + ' installed v' + moduleData.version + ', package.json requires ' + packageJSONVersion + '\n');
+ depsOutdated = true;
+ }
+ return satisfies;
};
diff --git a/src/meta/errors.js b/src/meta/errors.js
index f269490bbf..38e206e501 100644
--- a/src/meta/errors.js
+++ b/src/meta/errors.js
@@ -8,61 +8,59 @@ var cronJob = require('cron').CronJob;
var db = require('../database');
var analytics = require('../analytics');
-module.exports = function (Meta) {
- Meta.errors = {};
+var Errors = module.exports;
- var counters = {};
+var counters = {};
- new cronJob('0 * * * * *', function () {
- Meta.errors.writeData();
- }, null, true);
+new cronJob('0 * * * * *', function () {
+ Errors.writeData();
+}, null, true);
- Meta.errors.writeData = function () {
- var dbQueue = [];
- if (Object.keys(counters).length > 0) {
- for (var key in counters) {
- if (counters.hasOwnProperty(key)) {
- dbQueue.push(async.apply(db.sortedSetIncrBy, 'errors:404', counters[key], key));
- }
+Errors.writeData = function () {
+ var dbQueue = [];
+ if (Object.keys(counters).length > 0) {
+ for (var key in counters) {
+ if (counters.hasOwnProperty(key)) {
+ dbQueue.push(async.apply(db.sortedSetIncrBy, 'errors:404', counters[key], key));
}
- counters = {};
- async.series(dbQueue, function (err) {
- if (err) {
- winston.error(err);
- }
- });
}
- };
+ counters = {};
+ async.series(dbQueue, function (err) {
+ if (err) {
+ winston.error(err);
+ }
+ });
+ }
+};
- Meta.errors.log404 = function (route, callback) {
- callback = callback || function () {};
- if (!route) {
- return setImmediate(callback);
- }
- route = route.replace(/\/$/, ''); // remove trailing slashes
- analytics.increment('errors:404');
- counters[route] = counters[route] || 0;
- counters[route] += 1;
- setImmediate(callback);
- };
+Errors.log404 = function (route, callback) {
+ callback = callback || function () {};
+ if (!route) {
+ return setImmediate(callback);
+ }
+ route = route.replace(/\/$/, ''); // remove trailing slashes
+ analytics.increment('errors:404');
+ counters[route] = counters[route] || 0;
+ counters[route] += 1;
+ setImmediate(callback);
+};
- Meta.errors.get = function (escape, callback) {
- async.waterfall([
- function (next) {
- db.getSortedSetRevRangeWithScores('errors:404', 0, 199, next);
- },
- function (data, next) {
- data = data.map(function (nfObject) {
- nfObject.value = escape ? validator.escape(String(nfObject.value || '')) : nfObject.value;
- return nfObject;
- });
+Errors.get = function (escape, callback) {
+ async.waterfall([
+ function (next) {
+ db.getSortedSetRevRangeWithScores('errors:404', 0, 199, next);
+ },
+ function (data, next) {
+ data = data.map(function (nfObject) {
+ nfObject.value = escape ? validator.escape(String(nfObject.value || '')) : nfObject.value;
+ return nfObject;
+ });
- next(null, data);
- },
- ], callback);
- };
+ next(null, data);
+ },
+ ], callback);
+};
- Meta.errors.clear = function (callback) {
- db.delete('errors:404', callback);
- };
+Errors.clear = function (callback) {
+ db.delete('errors:404', callback);
};
diff --git a/src/meta/js.js b/src/meta/js.js
index b239ee21fe..8f483779da 100644
--- a/src/meta/js.js
+++ b/src/meta/js.js
@@ -10,341 +10,339 @@ var file = require('../file');
var plugins = require('../plugins');
var minifier = require('./minifier');
-module.exports = function (Meta) {
- Meta.js = {};
-
- Meta.js.scripts = {
- base: [
- 'node_modules/jquery/dist/jquery.js',
- 'node_modules/socket.io-client/dist/socket.io.js',
- 'public/vendor/jquery/timeago/jquery.timeago.js',
- 'public/vendor/jquery/js/jquery.form.min.js',
- 'public/vendor/visibility/visibility.min.js',
- 'node_modules/bootstrap/dist/js/bootstrap.js',
- 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js',
- 'public/vendor/jquery/textcomplete/jquery.textcomplete.js',
- 'public/vendor/requirejs/require.js',
- 'public/src/require-config.js',
- 'public/vendor/bootbox/bootbox.js',
- 'public/vendor/bootbox/wrapper.js',
- 'public/vendor/tinycon/tinycon.js',
- 'public/vendor/xregexp/xregexp.js',
- 'public/vendor/xregexp/unicode/unicode-base.js',
- 'node_modules/templates.js/lib/templates.js',
- 'public/src/utils.js',
- 'public/src/sockets.js',
- 'public/src/app.js',
- 'public/src/ajaxify.js',
- 'public/src/overrides.js',
- 'public/src/widgets.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
- rjs: [
- 'public/src/client/footer.js',
- 'public/src/client/chats.js',
- 'public/src/client/infinitescroll.js',
- 'public/src/client/pagination.js',
- 'public/src/client/recent.js',
- 'public/src/client/unread.js',
- 'public/src/client/topic.js',
- 'public/src/client/topic/events.js',
- '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',
- 'public/src/client/category.js',
- 'public/src/client/category/tools.js',
-
- 'public/src/modules/translator.js',
- 'public/src/modules/notifications.js',
- 'public/src/modules/chat.js',
- 'public/src/modules/components.js',
- 'public/src/modules/sort.js',
- 'public/src/modules/navigator.js',
- 'public/src/modules/topicSelect.js',
- 'public/src/modules/categorySelector.js',
- 'public/src/modules/share.js',
- 'public/src/modules/search.js',
- 'public/src/modules/alerts.js',
- 'public/src/modules/taskbar.js',
- 'public/src/modules/helpers.js',
- 'public/src/modules/string.js',
- 'public/src/modules/flags.js',
- 'public/src/modules/storage.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',
- 'cropper.js': 'node_modules/cropperjs/dist/cropper.min.js',
- 'jqueryui.js': 'public/vendor/jquery/js/jquery-ui.js',
- 'zxcvbn.js': 'node_modules/zxcvbn/dist/zxcvbn.js',
- ace: 'node_modules/ace-builds/src-min',
- },
- };
-
- var basePath = path.resolve(__dirname, '../..');
-
- function minifyModules(modules, fork, callback) {
- var moduleDirs = modules.reduce(function (prev, mod) {
- var dir = path.resolve(path.dirname(mod.destPath));
- if (prev.indexOf(dir) === -1) {
- prev.push(dir);
- }
- return prev;
- }, []);
-
- async.eachLimit(moduleDirs, 1000, mkdirp, function (err) {
- if (err) {
- return callback(err);
- }
-
- var filtered = modules.reduce(function (prev, mod) {
- if (mod.srcPath.endsWith('.min.js') || path.dirname(mod.srcPath).endsWith('min')) {
- prev.skip.push(mod);
- } else {
- prev.minify.push(mod);
- }
-
- return prev;
- }, { minify: [], skip: [] });
-
- async.parallel([
- function (cb) {
- minifier.js.minifyBatch(filtered.minify, fork, cb);
- },
- function (cb) {
- async.eachLimit(filtered.skip, 500, function (mod, next) {
- file.link(mod.srcPath, mod.destPath, next);
- }, cb);
- },
- ], callback);
- });
- }
+var JS = module.exports;
+
+JS.scripts = {
+ base: [
+ 'node_modules/jquery/dist/jquery.js',
+ 'node_modules/socket.io-client/dist/socket.io.js',
+ 'public/vendor/jquery/timeago/jquery.timeago.js',
+ 'public/vendor/jquery/js/jquery.form.min.js',
+ 'public/vendor/visibility/visibility.min.js',
+ 'node_modules/bootstrap/dist/js/bootstrap.js',
+ 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js',
+ 'public/vendor/jquery/textcomplete/jquery.textcomplete.js',
+ 'public/vendor/requirejs/require.js',
+ 'public/src/require-config.js',
+ 'public/vendor/bootbox/bootbox.js',
+ 'public/vendor/bootbox/wrapper.js',
+ 'public/vendor/tinycon/tinycon.js',
+ 'public/vendor/xregexp/xregexp.js',
+ 'public/vendor/xregexp/unicode/unicode-base.js',
+ 'node_modules/templates.js/lib/templates.js',
+ 'public/src/utils.js',
+ 'public/src/sockets.js',
+ 'public/src/app.js',
+ 'public/src/ajaxify.js',
+ 'public/src/overrides.js',
+ 'public/src/widgets.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
+ rjs: [
+ 'public/src/client/footer.js',
+ 'public/src/client/chats.js',
+ 'public/src/client/infinitescroll.js',
+ 'public/src/client/pagination.js',
+ 'public/src/client/recent.js',
+ 'public/src/client/unread.js',
+ 'public/src/client/topic.js',
+ 'public/src/client/topic/events.js',
+ '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',
+ 'public/src/client/category.js',
+ 'public/src/client/category/tools.js',
+
+ 'public/src/modules/translator.js',
+ 'public/src/modules/notifications.js',
+ 'public/src/modules/chat.js',
+ 'public/src/modules/components.js',
+ 'public/src/modules/sort.js',
+ 'public/src/modules/navigator.js',
+ 'public/src/modules/topicSelect.js',
+ 'public/src/modules/categorySelector.js',
+ 'public/src/modules/share.js',
+ 'public/src/modules/search.js',
+ 'public/src/modules/alerts.js',
+ 'public/src/modules/taskbar.js',
+ 'public/src/modules/helpers.js',
+ 'public/src/modules/string.js',
+ 'public/src/modules/flags.js',
+ 'public/src/modules/storage.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',
+ 'cropper.js': 'node_modules/cropperjs/dist/cropper.min.js',
+ 'jqueryui.js': 'public/vendor/jquery/js/jquery-ui.js',
+ 'zxcvbn.js': 'node_modules/zxcvbn/dist/zxcvbn.js',
+ ace: 'node_modules/ace-builds/src-min',
+ },
+};
- function linkModules(callback) {
- var modules = Meta.js.scripts.modules;
-
- async.eachLimit(Object.keys(modules), 1000, function (relPath, next) {
- var srcPath = path.join(__dirname, '../../', modules[relPath]);
- var destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
-
- async.parallel({
- dir: function (cb) {
- mkdirp(path.dirname(destPath), function (err) {
- cb(err);
- });
- },
- stats: function (cb) {
- fs.stat(srcPath, cb);
- },
- }, function (err, res) {
- if (err) {
- return next(err);
- }
- if (res.stats.isDirectory()) {
- return file.linkDirs(srcPath, destPath, next);
- }
+var basePath = path.resolve(__dirname, '../..');
- if (process.platform === 'win32') {
- fs.readFile(srcPath, function (err, file) {
- if (err) {
- return next(err);
- }
+function minifyModules(modules, fork, callback) {
+ var moduleDirs = modules.reduce(function (prev, mod) {
+ var dir = path.resolve(path.dirname(mod.destPath));
+ if (prev.indexOf(dir) === -1) {
+ prev.push(dir);
+ }
+ return prev;
+ }, []);
- fs.writeFile(destPath, file, next);
- });
- } else {
- file.link(srcPath, destPath, next);
- }
- });
- }, callback);
- }
+ async.eachLimit(moduleDirs, 1000, mkdirp, function (err) {
+ if (err) {
+ return callback(err);
+ }
- var moduleDirs = ['modules', 'admin', 'client'];
+ var filtered = modules.reduce(function (prev, mod) {
+ if (mod.srcPath.endsWith('.min.js') || path.dirname(mod.srcPath).endsWith('min')) {
+ prev.skip.push(mod);
+ } else {
+ prev.minify.push(mod);
+ }
- function getModuleList(callback) {
- var modules = Object.keys(Meta.js.scripts.modules).map(function (relPath) {
- return {
- srcPath: path.join(__dirname, '../../', Meta.js.scripts.modules[relPath]),
- destPath: path.join(__dirname, '../../build/public/src/modules', relPath),
- };
- });
+ return prev;
+ }, { minify: [], skip: [] });
- var coreDirs = moduleDirs.map(function (dir) {
- return {
- srcPath: path.join(__dirname, '../../public/src', dir),
- destPath: path.join(__dirname, '../../build/public/src', dir),
- };
- });
+ async.parallel([
+ function (cb) {
+ minifier.js.minifyBatch(filtered.minify, fork, cb);
+ },
+ function (cb) {
+ async.eachLimit(filtered.skip, 500, function (mod, next) {
+ file.link(mod.srcPath, mod.destPath, next);
+ }, cb);
+ },
+ ], callback);
+ });
+}
- modules = modules.concat(coreDirs);
+function linkModules(callback) {
+ var modules = JS.scripts.modules;
- var moduleFiles = [];
- async.eachLimit(modules, 1000, function (module, next) {
- var srcPath = module.srcPath;
- var destPath = module.destPath;
+ async.eachLimit(Object.keys(modules), 1000, function (relPath, next) {
+ var srcPath = path.join(__dirname, '../../', modules[relPath]);
+ var destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
- fs.stat(srcPath, function (err, stats) {
- if (err) {
- return next(err);
- }
- if (!stats.isDirectory()) {
- moduleFiles.push(module);
- return next();
- }
+ async.parallel({
+ dir: function (cb) {
+ mkdirp(path.dirname(destPath), function (err) {
+ cb(err);
+ });
+ },
+ stats: function (cb) {
+ fs.stat(srcPath, cb);
+ },
+ }, function (err, res) {
+ if (err) {
+ return next(err);
+ }
+ if (res.stats.isDirectory()) {
+ return file.linkDirs(srcPath, destPath, next);
+ }
- file.walk(srcPath, function (err, files) {
+ if (process.platform === 'win32') {
+ fs.readFile(srcPath, function (err, file) {
if (err) {
return next(err);
}
- var mods = files.filter(function (filePath) {
- return path.extname(filePath) === '.js';
- }).map(function (filePath) {
- return {
- srcPath: path.normalize(filePath),
- destPath: path.join(destPath, path.relative(srcPath, filePath)),
- };
- });
-
- moduleFiles = moduleFiles.concat(mods).map(function (mod) {
- mod.filename = path.relative(basePath, mod.srcPath).replace(/\\/g, '/');
- return mod;
- });
-
- next();
+ fs.writeFile(destPath, file, next);
});
- });
- }, function (err) {
- callback(err, moduleFiles);
+ } else {
+ file.link(srcPath, destPath, next);
+ }
});
- }
+ }, callback);
+}
- function clearModules(callback) {
- var builtPaths = moduleDirs.map(function (p) {
- return path.join(__dirname, '../../build/public/src', p);
- });
- async.each(builtPaths, function (builtPath, next) {
- rimraf(builtPath, next);
- }, function (err) {
- callback(err);
- });
- }
+var moduleDirs = ['modules', 'admin', 'client'];
- Meta.js.buildModules = function (fork, callback) {
- async.waterfall([
- clearModules,
- function (next) {
- if (global.env === 'development') {
- return linkModules(callback);
- }
+function getModuleList(callback) {
+ var modules = Object.keys(JS.scripts.modules).map(function (relPath) {
+ return {
+ srcPath: path.join(__dirname, '../../', JS.scripts.modules[relPath]),
+ destPath: path.join(__dirname, '../../build/public/src/modules', relPath),
+ };
+ });
- getModuleList(next);
- },
- function (modules, next) {
- minifyModules(modules, fork, next);
- },
- ], callback);
- };
+ var coreDirs = moduleDirs.map(function (dir) {
+ return {
+ srcPath: path.join(__dirname, '../../public/src', dir),
+ destPath: path.join(__dirname, '../../build/public/src', dir),
+ };
+ });
+
+ modules = modules.concat(coreDirs);
+
+ var moduleFiles = [];
+ async.eachLimit(modules, 1000, function (module, next) {
+ var srcPath = module.srcPath;
+ var destPath = module.destPath;
- Meta.js.linkStatics = function (callback) {
- rimraf(path.join(__dirname, '../../build/public/plugins'), function (err) {
+ fs.stat(srcPath, function (err, stats) {
if (err) {
- return callback(err);
+ return next(err);
+ }
+ if (!stats.isDirectory()) {
+ moduleFiles.push(module);
+ return next();
}
- async.eachLimit(Object.keys(plugins.staticDirs), 1000, function (mappedPath, next) {
- var sourceDir = plugins.staticDirs[mappedPath];
- var destDir = path.join(__dirname, '../../build/public/plugins', mappedPath);
- mkdirp(path.dirname(destDir), function (err) {
- if (err) {
- return next(err);
- }
+ file.walk(srcPath, function (err, files) {
+ if (err) {
+ return next(err);
+ }
- file.linkDirs(sourceDir, destDir, next);
+ var mods = files.filter(function (filePath) {
+ return path.extname(filePath) === '.js';
+ }).map(function (filePath) {
+ return {
+ srcPath: path.normalize(filePath),
+ destPath: path.join(destPath, path.relative(srcPath, filePath)),
+ };
});
- }, callback);
- });
- };
- function getBundleScriptList(target, callback) {
- var pluginDirectories = [];
+ moduleFiles = moduleFiles.concat(mods).map(function (mod) {
+ mod.filename = path.relative(basePath, mod.srcPath).replace(/\\/g, '/');
+ return mod;
+ });
- if (target === 'admin') {
- target = 'acp';
- }
- var pluginScripts = plugins[target + 'Scripts'].filter(function (path) {
- if (path.endsWith('.js')) {
- return true;
+ next();
+ });
+ });
+ }, function (err) {
+ callback(err, moduleFiles);
+ });
+}
+
+function clearModules(callback) {
+ var builtPaths = moduleDirs.map(function (p) {
+ return path.join(__dirname, '../../build/public/src', p);
+ });
+ async.each(builtPaths, function (builtPath, next) {
+ rimraf(builtPath, next);
+ }, function (err) {
+ callback(err);
+ });
+}
+
+JS.buildModules = function (fork, callback) {
+ async.waterfall([
+ clearModules,
+ function (next) {
+ if (global.env === 'development') {
+ return linkModules(callback);
}
- pluginDirectories.push(path);
- return false;
- });
+ getModuleList(next);
+ },
+ function (modules, next) {
+ minifyModules(modules, fork, next);
+ },
+ ], callback);
+};
+
+JS.linkStatics = function (callback) {
+ rimraf(path.join(__dirname, '../../build/public/plugins'), function (err) {
+ if (err) {
+ return callback(err);
+ }
+ async.eachLimit(Object.keys(plugins.staticDirs), 1000, function (mappedPath, next) {
+ var sourceDir = plugins.staticDirs[mappedPath];
+ var destDir = path.join(__dirname, '../../build/public/plugins', mappedPath);
- async.each(pluginDirectories, function (directory, next) {
- file.walk(directory, function (err, scripts) {
+ mkdirp(path.dirname(destDir), function (err) {
if (err) {
return next(err);
}
- pluginScripts = pluginScripts.concat(scripts);
- next();
+ file.linkDirs(sourceDir, destDir, next);
});
- }, function (err) {
+ }, callback);
+ });
+};
+
+function getBundleScriptList(target, callback) {
+ var pluginDirectories = [];
+
+ if (target === 'admin') {
+ target = 'acp';
+ }
+ var pluginScripts = plugins[target + 'Scripts'].filter(function (path) {
+ if (path.endsWith('.js')) {
+ return true;
+ }
+
+ pluginDirectories.push(path);
+ return false;
+ });
+
+ async.each(pluginDirectories, function (directory, next) {
+ file.walk(directory, function (err, scripts) {
if (err) {
- return callback(err);
+ return next(err);
}
- var scripts = Meta.js.scripts.base.concat(pluginScripts);
+ pluginScripts = pluginScripts.concat(scripts);
+ next();
+ });
+ }, function (err) {
+ if (err) {
+ return callback(err);
+ }
- if (target === 'client' && global.env !== 'development') {
- scripts = scripts.concat(Meta.js.scripts.rjs);
- }
+ var scripts = JS.scripts.base.concat(pluginScripts);
- scripts = scripts.map(function (script) {
- var srcPath = path.resolve(basePath, script).replace(/\\/g, '/');
- return {
- srcPath: srcPath,
- filename: path.relative(basePath, srcPath).replace(/\\/g, '/'),
- };
- });
+ if (target === 'client' && global.env !== 'development') {
+ scripts = scripts.concat(JS.scripts.rjs);
+ }
- callback(null, scripts);
+ scripts = scripts.map(function (script) {
+ var srcPath = path.resolve(basePath, script).replace(/\\/g, '/');
+ return {
+ srcPath: srcPath,
+ filename: path.relative(basePath, srcPath).replace(/\\/g, '/'),
+ };
});
- }
- Meta.js.buildBundle = function (target, fork, callback) {
- var fileNames = {
- client: 'nodebb.min.js',
- admin: 'acp.min.js',
- };
+ callback(null, scripts);
+ });
+}
- async.waterfall([
- function (next) {
- getBundleScriptList(target, next);
- },
- function (files, next) {
- var minify = global.env !== 'development';
- var filePath = path.join(__dirname, '../../build/public', fileNames[target]);
-
- minifier.js.bundle({
- files: files,
- filename: fileNames[target],
- destPath: filePath,
- }, minify, fork, next);
- },
- ], callback);
+JS.buildBundle = function (target, fork, callback) {
+ var fileNames = {
+ client: 'nodebb.min.js',
+ admin: 'acp.min.js',
};
- Meta.js.killMinifier = function () {
- minifier.killAll();
- };
+ async.waterfall([
+ function (next) {
+ getBundleScriptList(target, next);
+ },
+ function (files, next) {
+ var minify = global.env !== 'development';
+ var filePath = path.join(__dirname, '../../build/public', fileNames[target]);
+
+ minifier.js.bundle({
+ files: files,
+ filename: fileNames[target],
+ destPath: filePath,
+ }, minify, fork, next);
+ },
+ ], callback);
+};
+
+JS.killMinifier = function () {
+ minifier.killAll();
};
diff --git a/src/meta/logs.js b/src/meta/logs.js
index 30dd983a36..1f950d6057 100644
--- a/src/meta/logs.js
+++ b/src/meta/logs.js
@@ -3,18 +3,16 @@
var path = require('path');
var fs = require('fs');
-module.exports = function (Meta) {
- Meta.logs = {
- path: path.join(__dirname, '..', '..', 'logs', 'output.log'),
- };
+var Logs = module.exports;
- Meta.logs.get = function (callback) {
- fs.readFile(Meta.logs.path, {
- encoding: 'utf-8',
- }, callback);
- };
+Logs.path = path.join(__dirname, '..', '..', 'logs', 'output.log');
- Meta.logs.clear = function (callback) {
- fs.truncate(Meta.logs.path, 0, callback);
- };
+Logs.get = function (callback) {
+ fs.readFile(Logs.path, {
+ encoding: 'utf-8',
+ }, callback);
+};
+
+Logs.clear = function (callback) {
+ fs.truncate(Logs.path, 0, callback);
};
diff --git a/src/meta/settings.js b/src/meta/settings.js
index a1d13b248d..18eae100c3 100644
--- a/src/meta/settings.js
+++ b/src/meta/settings.js
@@ -4,61 +4,60 @@ var async = require('async');
var db = require('../database');
var plugins = require('../plugins');
+var Meta = require('../meta');
-module.exports = function (Meta) {
- Meta.settings = {};
+var Settings = module.exports;
- Meta.settings.get = function (hash, callback) {
- db.getObject('settings:' + hash, function (err, settings) {
- callback(err, settings || {});
- });
- };
-
- Meta.settings.getOne = function (hash, field, callback) {
- db.getObjectField('settings:' + hash, field, callback);
- };
-
- Meta.settings.set = function (hash, values, callback) {
- async.waterfall([
- function (next) {
- db.setObject('settings:' + hash, values, next);
- },
- function (next) {
- plugins.fireHook('action:settings.set', {
- plugin: hash,
- settings: values,
- });
+Settings.get = function (hash, callback) {
+ db.getObject('settings:' + hash, function (err, settings) {
+ callback(err, settings || {});
+ });
+};
- Meta.reloadRequired = true;
- next();
- },
- ], callback);
- };
+Settings.getOne = function (hash, field, callback) {
+ db.getObjectField('settings:' + hash, field, callback);
+};
- Meta.settings.setOne = function (hash, field, value, callback) {
- db.setObjectField('settings:' + hash, field, value, callback);
- };
+Settings.set = function (hash, values, callback) {
+ async.waterfall([
+ function (next) {
+ db.setObject('settings:' + hash, values, next);
+ },
+ function (next) {
+ plugins.fireHook('action:settings.set', {
+ plugin: hash,
+ settings: values,
+ });
+
+ Meta.reloadRequired = true;
+ next();
+ },
+ ], callback);
+};
- Meta.settings.setOnEmpty = function (hash, values, callback) {
- async.waterfall([
- function (next) {
- db.getObject('settings:' + hash, next);
- },
- function (settings, next) {
- settings = settings || {};
- var empty = {};
- Object.keys(values).forEach(function (key) {
- if (!settings.hasOwnProperty(key)) {
- empty[key] = values[key];
- }
- });
+Settings.setOne = function (hash, field, value, callback) {
+ db.setObjectField('settings:' + hash, field, value, callback);
+};
- if (Object.keys(empty).length) {
- db.setObject('settings:' + hash, empty, next);
- } else {
- next();
+Settings.setOnEmpty = function (hash, values, callback) {
+ async.waterfall([
+ function (next) {
+ db.getObject('settings:' + hash, next);
+ },
+ function (settings, next) {
+ settings = settings || {};
+ var empty = {};
+ Object.keys(values).forEach(function (key) {
+ if (!settings.hasOwnProperty(key)) {
+ empty[key] = values[key];
}
- },
- ], callback);
- };
+ });
+
+ if (Object.keys(empty).length) {
+ db.setObject('settings:' + hash, empty, next);
+ } else {
+ next();
+ }
+ },
+ ], callback);
};
diff --git a/src/meta/sounds.js b/src/meta/sounds.js
index e7bb7c3599..ec89b471da 100644
--- a/src/meta/sounds.js
+++ b/src/meta/sounds.js
@@ -9,125 +9,124 @@ var async = require('async');
var file = require('../file');
var plugins = require('../plugins');
var user = require('../user');
+var Meta = require('../meta');
var soundsPath = path.join(__dirname, '../../build/public/sounds');
var uploadsPath = path.join(__dirname, '../../public/uploads/sounds');
-module.exports = function (Meta) {
- Meta.sounds = {};
+var Sounds = module.exports;
- Meta.sounds.addUploads = function addUploads(callback) {
- fs.readdir(uploadsPath, function (err, files) {
- if (err) {
- if (err.code !== 'ENOENT') {
- return callback(err);
- }
-
- files = [];
+Sounds.addUploads = function addUploads(callback) {
+ fs.readdir(uploadsPath, function (err, files) {
+ if (err) {
+ if (err.code !== 'ENOENT') {
+ return callback(err);
}
- var uploadSounds = files.reduce(function (prev, fileName) {
- var name = fileName.split('.');
- if (!name.length || !name[0].length) {
- return prev;
- }
- name = name[0];
- name = name[0].toUpperCase() + name.slice(1);
+ files = [];
+ }
- prev[name] = fileName;
+ var uploadSounds = files.reduce(function (prev, fileName) {
+ var name = fileName.split('.');
+ if (!name.length || !name[0].length) {
return prev;
- }, {});
-
- plugins.soundpacks = plugins.soundpacks.filter(function (pack) {
- return pack.name !== 'Uploads';
- });
- if (Object.keys(uploadSounds).length) {
- plugins.soundpacks.push({
- name: 'Uploads',
- id: 'uploads',
- dir: uploadsPath,
- sounds: uploadSounds,
- });
}
+ name = name[0];
+ name = name[0].toUpperCase() + name.slice(1);
+
+ prev[name] = fileName;
+ return prev;
+ }, {});
- callback();
+ plugins.soundpacks = plugins.soundpacks.filter(function (pack) {
+ return pack.name !== 'Uploads';
});
- };
+ if (Object.keys(uploadSounds).length) {
+ plugins.soundpacks.push({
+ name: 'Uploads',
+ id: 'uploads',
+ dir: uploadsPath,
+ sounds: uploadSounds,
+ });
+ }
- Meta.sounds.build = function build(callback) {
- Meta.sounds.addUploads(function (err) {
- if (err) {
- return callback(err);
- }
+ callback();
+ });
+};
- var map = plugins.soundpacks.map(function (pack) {
- return Object.keys(pack.sounds).reduce(function (prev, soundName) {
- var soundPath = pack.sounds[soundName];
- prev[pack.name + ' | ' + soundName] = pack.id + '/' + soundPath;
- return prev;
- }, {});
- });
- map.unshift({});
- map = Object.assign.apply(null, map);
-
- async.series([
- function (next) {
- rimraf(soundsPath, next);
- },
- function (next) {
- mkdirp(soundsPath, next);
- },
- function (cb) {
- async.parallel([
- function (next) {
- fs.writeFile(path.join(soundsPath, 'fileMap.json'), JSON.stringify(map), next);
- },
- function (next) {
- async.each(plugins.soundpacks, function (pack, next) {
- file.linkDirs(pack.dir, path.join(soundsPath, pack.id), next);
- }, next);
- },
- ], cb);
- },
- ], function (err) {
- callback(err);
- });
- });
- };
+Sounds.build = function build(callback) {
+ Sounds.addUploads(function (err) {
+ if (err) {
+ return callback(err);
+ }
- var keys = ['chat-incoming', 'chat-outgoing', 'notification'];
+ var map = plugins.soundpacks.map(function (pack) {
+ return Object.keys(pack.sounds).reduce(function (prev, soundName) {
+ var soundPath = pack.sounds[soundName];
+ prev[pack.name + ' | ' + soundName] = pack.id + '/' + soundPath;
+ return prev;
+ }, {});
+ });
+ map.unshift({});
+ map = Object.assign.apply(null, map);
- Meta.sounds.getUserSoundMap = function getUserSoundMap(uid, callback) {
- async.parallel({
- defaultMapping: function (next) {
- Meta.configs.getFields(keys, next);
+ async.series([
+ function (next) {
+ rimraf(soundsPath, next);
},
- userSettings: function (next) {
- user.getSettings(uid, next);
+ function (next) {
+ mkdirp(soundsPath, next);
},
- }, function (err, results) {
- if (err) {
- return callback(err);
- }
-
- var userSettings = results.userSettings;
- userSettings = {
- notification: userSettings.notificationSound,
- 'chat-incoming': userSettings.incomingChatSound,
- 'chat-outgoing': userSettings.outgoingChatSound,
- };
- var defaultMapping = results.defaultMapping || {};
- var soundMapping = {};
-
- keys.forEach(function (key) {
- if (userSettings[key] || userSettings[key] === '') {
- soundMapping[key] = userSettings[key] || '';
- } else {
- soundMapping[key] = defaultMapping[key] || '';
- }
- });
+ function (cb) {
+ async.parallel([
+ function (next) {
+ fs.writeFile(path.join(soundsPath, 'fileMap.json'), JSON.stringify(map), next);
+ },
+ function (next) {
+ async.each(plugins.soundpacks, function (pack, next) {
+ file.linkDirs(pack.dir, path.join(soundsPath, pack.id), next);
+ }, next);
+ },
+ ], cb);
+ },
+ ], function (err) {
+ callback(err);
+ });
+ });
+};
- callback(null, soundMapping);
+var keys = ['chat-incoming', 'chat-outgoing', 'notification'];
+
+Sounds.getUserSoundMap = function getUserSoundMap(uid, callback) {
+ async.parallel({
+ defaultMapping: function (next) {
+ Meta.configs.getFields(keys, next);
+ },
+ userSettings: function (next) {
+ user.getSettings(uid, next);
+ },
+ }, function (err, results) {
+ if (err) {
+ return callback(err);
+ }
+
+ var userSettings = results.userSettings;
+ userSettings = {
+ notification: userSettings.notificationSound,
+ 'chat-incoming': userSettings.incomingChatSound,
+ 'chat-outgoing': userSettings.outgoingChatSound,
+ };
+ var defaultMapping = results.defaultMapping || {};
+ var soundMapping = {};
+
+ keys.forEach(function (key) {
+ if (userSettings[key] || userSettings[key] === '') {
+ soundMapping[key] = userSettings[key] || '';
+ } else {
+ soundMapping[key] = defaultMapping[key] || '';
+ }
});
- };
+
+ callback(null, soundMapping);
+ });
};
diff --git a/src/meta/tags.js b/src/meta/tags.js
index ac0b395a23..34ed3c43a9 100644
--- a/src/meta/tags.js
+++ b/src/meta/tags.js
@@ -4,163 +4,163 @@ var nconf = require('nconf');
var validator = require('validator');
var async = require('async');
var winston = require('winston');
+
var plugins = require('../plugins');
+var Meta = require('../meta');
+
+var Tags = module.exports;
+
+Tags.parse = function (req, meta, link, callback) {
+ async.parallel({
+ tags: function (next) {
+ var defaultTags = [{
+ name: 'viewport',
+ content: 'width=device-width, initial-scale=1.0',
+ }, {
+ name: 'content-type',
+ content: 'text/html; charset=UTF-8',
+ noEscape: true,
+ }, {
+ name: 'apple-mobile-web-app-capable',
+ content: 'yes',
+ }, {
+ name: 'mobile-web-app-capable',
+ content: 'yes',
+ }, {
+ property: 'og:site_name',
+ content: Meta.config.title || 'NodeBB',
+ }, {
+ name: 'msapplication-badge',
+ content: 'frequency=30; polling-uri=' + nconf.get('url') + '/sitemap.xml',
+ noEscape: true,
+ }];
+
+ if (Meta.config.keywords) {
+ defaultTags.push({
+ name: 'keywords',
+ content: Meta.config.keywords,
+ });
+ }
-module.exports = function (Meta) {
- Meta.tags = {};
+ if (Meta.config['brand:logo']) {
+ defaultTags.push({
+ name: 'msapplication-square150x150logo',
+ content: Meta.config['brand:logo'],
+ noEscape: true,
+ });
+ }
- Meta.tags.parse = function (req, meta, link, callback) {
- async.parallel({
- tags: function (next) {
- var defaultTags = [{
- name: 'viewport',
- content: 'width=device-width, initial-scale=1.0',
+ plugins.fireHook('filter:meta.getMetaTags', defaultTags, next);
+ },
+ 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: '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',
}, {
- name: 'content-type',
- content: 'text/html; charset=UTF-8',
- noEscape: true,
+ rel: 'icon',
+ sizes: '36x36',
+ href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-36.png',
}, {
- name: 'apple-mobile-web-app-capable',
- content: 'yes',
+ rel: 'icon',
+ sizes: '48x48',
+ href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-48.png',
}, {
- name: 'mobile-web-app-capable',
- content: 'yes',
+ rel: 'icon',
+ sizes: '72x72',
+ href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-72.png',
}, {
- property: 'og:site_name',
- content: Meta.config.title || 'NodeBB',
+ rel: 'icon',
+ sizes: '96x96',
+ href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-96.png',
}, {
- name: 'msapplication-badge',
- content: 'frequency=30; polling-uri=' + nconf.get('url') + '/sitemap.xml',
- noEscape: true,
- }];
-
- if (Meta.config.keywords) {
- defaultTags.push({
- name: 'keywords',
- content: Meta.config.keywords,
- });
- }
-
- if (Meta.config['brand:logo']) {
- defaultTags.push({
- name: 'msapplication-square150x150logo',
- content: Meta.config['brand:logo'],
- noEscape: true,
- });
- }
-
- plugins.fireHook('filter:meta.getMetaTags', defaultTags, next);
- },
- 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'] : ''),
+ sizes: '144x144',
+ href: nconf.get('relative_path') + '/assets/uploads/system/touchicon-144.png',
}, {
- 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',
- }, {
- rel: 'icon',
- sizes: '36x36',
- 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',
- }, {
- rel: 'icon',
- sizes: '72x72',
- 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',
- }, {
- rel: 'icon',
- sizes: '144x144',
- 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',
- });
- }
- plugins.fireHook('filter:meta.getLinkTags', defaultLinks, next);
- },
- }, function (err, results) {
- if (err) {
- return callback(err);
+ rel: 'icon',
+ sizes: '192x192',
+ 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);
+ }
- meta = results.tags.concat(meta || []).map(function (tag) {
- if (!tag || typeof tag.content !== 'string') {
- winston.warn('Invalid meta tag. ', tag);
- return tag;
- }
-
- if (!tag.noEscape) {
- tag.content = validator.escape(String(tag.content));
- }
-
+ meta = results.tags.concat(meta || []).map(function (tag) {
+ if (!tag || typeof tag.content !== 'string') {
+ winston.warn('Invalid meta tag. ', tag);
return tag;
- });
+ }
- addIfNotExists(meta, 'property', 'og:title', Meta.config.title || 'NodeBB');
+ if (!tag.noEscape) {
+ tag.content = validator.escape(String(tag.content));
+ }
- var ogUrl = nconf.get('url') + req.path;
- addIfNotExists(meta, 'property', 'og:url', ogUrl);
+ return tag;
+ });
- addIfNotExists(meta, 'name', 'description', Meta.config.description);
- addIfNotExists(meta, 'property', 'og:description', Meta.config.description);
+ addIfNotExists(meta, 'property', 'og:title', Meta.config.title || 'NodeBB');
- var ogImage = Meta.config['og:image'] || Meta.config['brand:logo'] || '';
- if (ogImage && !ogImage.startsWith('http')) {
- ogImage = nconf.get('url') + ogImage;
- }
- addIfNotExists(meta, 'property', 'og:image', ogImage);
- if (ogImage) {
- addIfNotExists(meta, 'property', 'og:image:width', 200);
- addIfNotExists(meta, 'property', 'og:image:height', 200);
- }
+ var ogUrl = nconf.get('url') + req.path;
+ addIfNotExists(meta, 'property', 'og:url', ogUrl);
- link = results.links.concat(link || []);
+ addIfNotExists(meta, 'name', 'description', Meta.config.description);
+ addIfNotExists(meta, 'property', 'og:description', Meta.config.description);
- callback(null, {
- meta: meta,
- link: link,
- });
- });
- };
+ var ogImage = Meta.config['og:image'] || Meta.config['brand:logo'] || '';
+ if (ogImage && !ogImage.startsWith('http')) {
+ ogImage = nconf.get('url') + ogImage;
+ }
+ addIfNotExists(meta, 'property', 'og:image', ogImage);
+ if (ogImage) {
+ addIfNotExists(meta, 'property', 'og:image:width', 200);
+ addIfNotExists(meta, 'property', 'og:image:height', 200);
+ }
- function addIfNotExists(meta, keyName, tagName, value) {
- var exists = false;
- meta.forEach(function (tag) {
- if (tag[keyName] === tagName) {
- exists = true;
- }
+ link = results.links.concat(link || []);
+
+ callback(null, {
+ meta: meta,
+ link: link,
});
+ });
+};
- if (!exists && value) {
- var data = {
- content: validator.escape(String(value)),
- };
- data[keyName] = tagName;
- meta.push(data);
+function addIfNotExists(meta, keyName, tagName, value) {
+ var exists = false;
+ meta.forEach(function (tag) {
+ if (tag[keyName] === tagName) {
+ exists = true;
}
+ });
+
+ if (!exists && value) {
+ var data = {
+ content: validator.escape(String(value)),
+ };
+ data[keyName] = tagName;
+ meta.push(data);
}
-};
+}
diff --git a/src/meta/themes.js b/src/meta/themes.js
index 9bca68c431..d034bd8a96 100644
--- a/src/meta/themes.js
+++ b/src/meta/themes.js
@@ -9,168 +9,167 @@ var async = require('async');
var file = require('../file');
var db = require('../database');
-
-module.exports = function (Meta) {
- Meta.themes = {};
-
- Meta.themes.get = function (callback) {
- var themePath = nconf.get('themes_path');
- if (typeof themePath !== 'string') {
- return callback(null, []);
- }
-
- async.waterfall([
- function (next) {
- fs.readdir(themePath, next);
- },
- function (files, next) {
- async.filter(files, function (file, next) {
- fs.stat(path.join(themePath, file), function (err, fileStat) {
- if (err) {
- if (err.code === 'ENOENT') {
- return next(null, false);
- }
- return next(err);
- }
-
- next(null, (fileStat.isDirectory() && file.slice(0, 13) === 'nodebb-theme-'));
- });
- }, next);
- },
- function (themes, next) {
- async.map(themes, function (theme, next) {
- var config = path.join(themePath, theme, 'theme.json');
-
- fs.readFile(config, function (err, file) {
- if (err) {
- if (err.code === 'ENOENT') {
- return next(null, null);
- }
- return next(err);
+var Meta = require('../meta');
+
+var Themes = module.exports;
+
+Themes.get = function (callback) {
+ var themePath = nconf.get('themes_path');
+ if (typeof themePath !== 'string') {
+ return callback(null, []);
+ }
+
+ async.waterfall([
+ function (next) {
+ fs.readdir(themePath, next);
+ },
+ function (files, next) {
+ async.filter(files, function (file, next) {
+ fs.stat(path.join(themePath, file), function (err, fileStat) {
+ if (err) {
+ if (err.code === 'ENOENT') {
+ return next(null, false);
}
- try {
- var configObj = JSON.parse(file.toString());
-
- // Minor adjustments for API output
- configObj.type = 'local';
- if (configObj.screenshot) {
- configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id;
- } else {
- configObj.screenshot_url = nconf.get('relative_path') + '/assets/images/themes/default.png';
- }
- next(null, configObj);
- } catch (err) {
- winston.error('[themes] Unable to parse theme.json ' + theme);
- next(null, null);
+ return next(err);
+ }
+
+ next(null, (fileStat.isDirectory() && file.slice(0, 13) === 'nodebb-theme-'));
+ });
+ }, next);
+ },
+ function (themes, next) {
+ async.map(themes, function (theme, next) {
+ var config = path.join(themePath, theme, 'theme.json');
+
+ fs.readFile(config, function (err, file) {
+ if (err) {
+ if (err.code === 'ENOENT') {
+ return next(null, null);
}
- });
- }, next);
- },
- function (themes, next) {
- themes = themes.filter(Boolean);
- next(null, themes);
- },
- ], callback);
- };
-
- Meta.themes.set = function (data, callback) {
- var themeData = {
- 'theme:type': data.type,
- 'theme:id': data.id,
- 'theme:staticDir': '',
- 'theme:templates': '',
- 'theme:src': '',
- };
-
- 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),
- ], function (err) {
- next(err);
- });
- },
- function (next) {
- fs.readFile(path.join(nconf.get('themes_path'), data.id, 'theme.json'), function (err, config) {
- if (!err) {
- config = JSON.parse(config.toString());
- next(null, config);
+ return next(err);
+ }
+ try {
+ var configObj = JSON.parse(file.toString());
+
+ // Minor adjustments for API output
+ configObj.type = 'local';
+ if (configObj.screenshot) {
+ configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id;
} else {
- next(err);
+ configObj.screenshot_url = nconf.get('relative_path') + '/assets/images/themes/default.png';
}
- });
- },
- function (config, next) {
- themeData['theme:staticDir'] = config.staticDir ? config.staticDir : '';
- themeData['theme:templates'] = config.templates ? config.templates : '';
- themeData['theme:src'] = '';
-
- Meta.configs.setMultiple(themeData, next);
+ next(null, configObj);
+ } catch (err) {
+ winston.error('[themes] Unable to parse theme.json ' + theme);
+ next(null, null);
+ }
+ });
+ }, next);
+ },
+ function (themes, next) {
+ themes = themes.filter(Boolean);
+ next(null, themes);
+ },
+ ], callback);
+};
- // Re-set the themes path (for when NodeBB is reloaded)
- Meta.themes.setPath(config);
- },
- ], callback);
-
- Meta.reloadRequired = true;
- break;
-
- case 'bootswatch':
- Meta.configs.setMultiple({
- 'theme:src': data.src,
- bootswatchSkin: data.id.toLowerCase(),
- }, callback);
- break;
- }
+Themes.set = function (data, callback) {
+ var themeData = {
+ 'theme:type': data.type,
+ 'theme:id': data.id,
+ 'theme:staticDir': '',
+ 'theme:templates': '',
+ 'theme:src': '',
};
- Meta.themes.setupPaths = function (callback) {
+ 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),
+ ], function (err) {
+ next(err);
+ });
+ },
function (next) {
- async.parallel({
- themesData: Meta.themes.get,
- currentThemeId: function (next) {
- db.getObjectField('config', 'theme:id', next);
- },
- }, next);
+ fs.readFile(path.join(nconf.get('themes_path'), data.id, 'theme.json'), function (err, config) {
+ if (!err) {
+ config = JSON.parse(config.toString());
+ next(null, config);
+ } else {
+ next(err);
+ }
+ });
},
- function (data, next) {
- var themeId = data.currentThemeId || 'nodebb-theme-persona';
-
- var themeObj = data.themesData.filter(function (themeObj) {
- return themeObj.id === themeId;
- })[0];
-
- if (process.env.NODE_ENV === 'development') {
- winston.info('[themes] Using theme ' + themeId);
- }
+ function (config, next) {
+ themeData['theme:staticDir'] = config.staticDir ? config.staticDir : '';
+ themeData['theme:templates'] = config.templates ? config.templates : '';
+ themeData['theme:src'] = '';
- if (!themeObj) {
- return callback(new Error('[[error:theme-not-found]]'));
- }
+ Meta.configs.setMultiple(themeData, next);
- Meta.themes.setPath(themeObj);
- next();
+ // Re-set the themes path (for when NodeBB is reloaded)
+ Themes.setPath(config);
},
], callback);
- };
- Meta.themes.setPath = function (themeObj) {
- // Theme's templates path
- var themePath = nconf.get('base_templates_path');
- var fallback = path.join(nconf.get('themes_path'), themeObj.id, 'templates');
+ Meta.reloadRequired = true;
+ break;
- if (themeObj.templates) {
- themePath = path.join(nconf.get('themes_path'), themeObj.id, themeObj.templates);
- } else if (file.existsSync(fallback)) {
- themePath = fallback;
- }
+ case 'bootswatch':
+ Meta.configs.setMultiple({
+ 'theme:src': data.src,
+ bootswatchSkin: data.id.toLowerCase(),
+ }, callback);
+ break;
+ }
+};
- nconf.set('theme_templates_path', themePath);
- nconf.set('theme_config', path.join(nconf.get('themes_path'), themeObj.id, 'theme.json'));
- };
+Themes.setupPaths = function (callback) {
+ async.waterfall([
+ function (next) {
+ async.parallel({
+ themesData: Themes.get,
+ currentThemeId: function (next) {
+ db.getObjectField('config', 'theme:id', next);
+ },
+ }, next);
+ },
+ function (data, next) {
+ var themeId = data.currentThemeId || 'nodebb-theme-persona';
+
+ var themeObj = data.themesData.filter(function (themeObj) {
+ return themeObj.id === themeId;
+ })[0];
+
+ if (process.env.NODE_ENV === 'development') {
+ winston.info('[themes] Using theme ' + themeId);
+ }
+
+ if (!themeObj) {
+ return callback(new Error('[[error:theme-not-found]]'));
+ }
+
+ Themes.setPath(themeObj);
+ next();
+ },
+ ], callback);
+};
+
+Themes.setPath = function (themeObj) {
+ // Theme's templates path
+ 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);
+ } else if (file.existsSync(fallback)) {
+ themePath = fallback;
+ }
+
+ nconf.set('theme_templates_path', themePath);
+ nconf.set('theme_config', path.join(nconf.get('themes_path'), themeObj.id, 'theme.json'));
};