mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-07-07 01:09:44 +02:00
Merge remote-tracking branch 'origin/develop'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -65,3 +65,4 @@ build
|
||||
test/files/normalise.jpg.png
|
||||
test/files/normalise-resized.jpg
|
||||
package-lock.json
|
||||
package.json
|
||||
|
||||
@@ -8,6 +8,8 @@ before_install:
|
||||
- "sudo service mongod start"
|
||||
before_script:
|
||||
- sleep 15 # wait for mongodb to be ready
|
||||
- cp package.default.json package.json
|
||||
- npm install
|
||||
- sh -c "if [ '$DB' = 'mongodb' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"mongo\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":27017,\\\"database\\\":0}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'redis' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"redis\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":6379,\\\"database\\\":0}\"; fi"
|
||||
after_success:
|
||||
|
||||
8
app.js
8
app.js
@@ -192,7 +192,8 @@ function setup() {
|
||||
process.stdout.write('\n' + separator + '\n\n');
|
||||
|
||||
if (err) {
|
||||
winston.error('There was a problem completing NodeBB setup: ', err.message);
|
||||
winston.error('There was a problem completing NodeBB setup', err);
|
||||
throw err;
|
||||
} else {
|
||||
if (data.hasOwnProperty('password')) {
|
||||
process.stdout.write('An administrative user was automatically created for you:\n');
|
||||
@@ -270,9 +271,10 @@ function activate() {
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error(err.message);
|
||||
winston.error('An error occurred during plugin activation', err);
|
||||
throw err;
|
||||
}
|
||||
process.exit(err ? 1 : 0);
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ Loader.restart = function () {
|
||||
|
||||
fs.readFile(pathToConfig, { encoding: 'utf-8' }, function (err, configFile) {
|
||||
if (err) {
|
||||
console.log('Error reading config : ' + err.message);
|
||||
process.exit();
|
||||
console.error('Error reading config');
|
||||
throw err;
|
||||
}
|
||||
|
||||
var conf = JSON.parse(configFile);
|
||||
@@ -240,11 +240,12 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) {
|
||||
Loader.start,
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.log('[loader] Error during startup: ' + err.message);
|
||||
console.error('[loader] Error during startup');
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No config detected, kickstart web installer
|
||||
require('child_process').fork('app');
|
||||
fork('app');
|
||||
}
|
||||
});
|
||||
|
||||
41
nodebb
41
nodebb
@@ -6,18 +6,20 @@ var fs = require('fs');
|
||||
var path = require('path');
|
||||
var cproc = require('child_process');
|
||||
|
||||
var packageInstall = require('./src/meta/package-install');
|
||||
|
||||
// check to make sure dependencies are installed
|
||||
try {
|
||||
fs.readFileSync(path.join(__dirname, './package.json'));
|
||||
fs.readFileSync(path.join(__dirname, 'node_modules/async/package.json'));
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
process.stdout.write('Dependencies not yet installed.\n');
|
||||
process.stdout.write('Installing them now...\n\n');
|
||||
|
||||
cproc.execSync('npm i --production', {
|
||||
cwd: __dirname,
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
packageInstall.updatePackageFile();
|
||||
packageInstall.preserveExtraneousPlugins();
|
||||
packageInstall.npmInstallProduction();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
@@ -451,15 +453,22 @@ var commands = {
|
||||
|
||||
return upgradeProc.on('close', function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
|
||||
process.stdout.write('Error occurred during upgrade');
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async.series([
|
||||
function (next) {
|
||||
packageInstall.updatePackageFile();
|
||||
packageInstall.preserveExtraneousPlugins();
|
||||
next();
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow);
|
||||
cproc.exec('npm i --production', { cwd: __dirname, stdio: 'ignore' }, next);
|
||||
packageInstall.npmInstallProduction();
|
||||
next();
|
||||
},
|
||||
function (next) {
|
||||
process.stdout.write('OK\n'.green);
|
||||
@@ -472,19 +481,21 @@ var commands = {
|
||||
var upgradeProc = fork(arr);
|
||||
|
||||
upgradeProc.on('close', next);
|
||||
upgradeProc.on('error', next);
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('\nError'.red + ': ' + err.message + '\n');
|
||||
} else {
|
||||
var message = 'NodeBB Upgrade Complete!';
|
||||
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||
var columns = process.stdout.columns;
|
||||
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
process.stdout.write('Error occurred during upgrade');
|
||||
throw err;
|
||||
}
|
||||
|
||||
var message = 'NodeBB Upgrade Complete!';
|
||||
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||
var columns = process.stdout.columns;
|
||||
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
"socket.io-redis": "5.2.0",
|
||||
"socketio-wildcard": "2.0.0",
|
||||
"spdx-license-list": "^3.0.1",
|
||||
"string": "^3.3.3",
|
||||
"toobusy-js": "^0.5.1",
|
||||
"uglify-js": "^3.1.5",
|
||||
"validator": "9.0.0",
|
||||
@@ -3,8 +3,12 @@
|
||||
"custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.",
|
||||
"custom-css.enable": "Enable Custom CSS",
|
||||
|
||||
"custom-js": "Custom Javascript",
|
||||
"custom-js.description": "Enter your own javascript here. It will be executed after the page is loaded completely.",
|
||||
"custom-js.enable": "Enable Custom Javascript",
|
||||
|
||||
"custom-header": "Custom Header",
|
||||
"custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <code><head></code> section of your forum's markup.",
|
||||
"custom-header.description": "Enter custom HTML here (ex. Meta Tags, etc.), which will be appended to the <code><head></code> section of your forum's markup. Script tags are allowed, but are discouraged, as the <a href=\"#custom-header\" data-toggle=\"tab\">Custom Javascript</a> tab is available.",
|
||||
"custom-header.enable": "Enable Custom Header",
|
||||
|
||||
"custom-css.livereload": "Enable Live Reload",
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"section-appearance": "Appearance",
|
||||
"appearance/themes": "Themes",
|
||||
"appearance/skins": "Skins",
|
||||
"appearance/customise": "Custom HTML & CSS",
|
||||
"appearance/customise": "Custom Content (HTML/JS/CSS)",
|
||||
|
||||
"section-extend": "Extend",
|
||||
"extend/plugins": "Plugins",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#customCSS, #customHTML, #email-editor {
|
||||
#customCSS, #customJS, #customHTML, #email-editor {
|
||||
width: 100%;
|
||||
height: 450px;
|
||||
display: block;
|
||||
|
||||
@@ -6,9 +6,11 @@ define('admin/appearance/customise', ['admin/settings', 'ace/ace'], function (Se
|
||||
Customise.init = function () {
|
||||
Settings.prepare(function () {
|
||||
$('#customCSS').text($('#customCSS-holder').val());
|
||||
$('#customJS').text($('#customJS-holder').val());
|
||||
$('#customHTML').text($('#customHTML-holder').val());
|
||||
|
||||
var customCSS = ace.edit('customCSS');
|
||||
var customJS = ace.edit('customJS');
|
||||
var customHTML = ace.edit('customHTML');
|
||||
|
||||
customCSS.setTheme('ace/theme/twilight');
|
||||
@@ -20,6 +22,15 @@ define('admin/appearance/customise', ['admin/settings', 'ace/ace'], function (Se
|
||||
$('#customCSS-holder').val(customCSS.getValue());
|
||||
});
|
||||
|
||||
customJS.setTheme('ace/theme/twilight');
|
||||
customJS.getSession().setMode('ace/mode/javascript');
|
||||
|
||||
customJS.on('change', function () {
|
||||
app.flags = app.flags || {};
|
||||
app.flags._unsaved = true;
|
||||
$('#customJS-holder').val(customJS.getValue());
|
||||
});
|
||||
|
||||
customHTML.setTheme('ace/theme/twilight');
|
||||
customHTML.getSession().setMode('ace/mode/html');
|
||||
|
||||
|
||||
@@ -63,11 +63,15 @@ define('forum/topic/move', ['categorySelector'], function (categorySelector) {
|
||||
}
|
||||
|
||||
function moveTopics() {
|
||||
socket.emit(Move.moveAll ? 'topics.moveAll' : 'topics.move', {
|
||||
var data = {
|
||||
tids: Move.tids,
|
||||
cid: selectedCategory.cid,
|
||||
currentCid: Move.currentCid,
|
||||
}, function (err) {
|
||||
};
|
||||
|
||||
$(window).trigger('action:topic.move', data);
|
||||
|
||||
socket.emit(Move.moveAll ? 'topics.moveAll' : 'topics.move', data, function (err) {
|
||||
modal.modal('hide');
|
||||
|
||||
if (err) {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
(function (factory) {
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
var relative_path = require('nconf').get('relative_path');
|
||||
module.exports = factory(require('../utils'), require('benchpressjs'), require('string'), relative_path);
|
||||
module.exports = factory(require('../utils'), require('benchpressjs'), relative_path);
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define('helpers', ['benchpress', 'string'], function (Benchpress, string) {
|
||||
return factory(utils, Benchpress, string, config.relative_path);
|
||||
define('helpers', ['benchpress'], function (Benchpress) {
|
||||
return factory(utils, Benchpress, config.relative_path);
|
||||
});
|
||||
}
|
||||
}(function (utils, Benchpress, S, relative_path) {
|
||||
}(function (utils, Benchpress, relative_path) {
|
||||
var helpers = {
|
||||
displayMenuItem: displayMenuItem,
|
||||
buildMetaTag: buildMetaTag,
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
|
||||
function stripTags(str) {
|
||||
return S(String(str)).stripTags().s;
|
||||
return utils.stripHTMLTags(str);
|
||||
}
|
||||
|
||||
function generateCategoryBackground(category) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,8 +10,8 @@
|
||||
}
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as a named module
|
||||
define('translator', ['string'], function (string) {
|
||||
return factory(string, loadClient, warn);
|
||||
define('translator', [], function () {
|
||||
return factory(utils, loadClient, warn);
|
||||
});
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
// Node
|
||||
@@ -37,14 +37,21 @@
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = factory(require('string'), loadServer, warn);
|
||||
module.exports = factory(require('../utils'), loadServer, warn);
|
||||
}());
|
||||
} else {
|
||||
window.translator = factory(window.string, loadClient, warn);
|
||||
}
|
||||
}(function (string, load, warn) {
|
||||
}(function (utils, load, warn) {
|
||||
var assign = Object.assign || jQuery.extend;
|
||||
function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
function escapeHTML(str) {
|
||||
return utils.decodeHTMLEntities(
|
||||
String(str)
|
||||
.replace(/[\s\xa0]+/g, ' ')
|
||||
.replace(/^\s+|\s+$/g, '')
|
||||
).replace(/[<>]/g, function (c) {
|
||||
return c === '<' ? '<' : '>';
|
||||
});
|
||||
}
|
||||
|
||||
var Translator = (function () {
|
||||
/**
|
||||
@@ -54,7 +61,6 @@
|
||||
*/
|
||||
function Translator(language) {
|
||||
var self = this;
|
||||
classCallCheck(self, Translator);
|
||||
|
||||
if (!language) {
|
||||
throw new TypeError('Parameter `language` must be a language string. Received ' + language + (language === '' ? '(empty string)' : ''));
|
||||
@@ -286,9 +292,7 @@
|
||||
}
|
||||
|
||||
var argsToTranslate = args.map(function (arg) {
|
||||
return string(arg).collapseWhitespace().decodeHTMLEntities().escapeHTML().s.replace(/&/g, '&');
|
||||
}).map(function (arg) {
|
||||
return self.translate(arg);
|
||||
return self.translate(escapeHTML(arg));
|
||||
});
|
||||
|
||||
return Promise.all(argsToTranslate).then(function (translatedArgs) {
|
||||
@@ -541,12 +545,13 @@
|
||||
return cb('');
|
||||
}
|
||||
|
||||
Translator.create(lang).translate(text).catch(function (err) {
|
||||
return Translator.create(lang).translate(text).then(function (output) {
|
||||
if (cb) {
|
||||
setTimeout(cb, 0, output);
|
||||
}
|
||||
return output;
|
||||
}, function (err) {
|
||||
warn('Translation failed: ' + err.stack);
|
||||
}).then(function (output) {
|
||||
cb(output);
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -25,6 +25,279 @@
|
||||
window.utils = factory(window.XRegExp);
|
||||
}
|
||||
}(function (XRegExp) {
|
||||
var freeze = Object.freeze || function (obj) { return obj; };
|
||||
|
||||
// add default escape function for escaping HTML entities
|
||||
var escapeCharMap = freeze({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'`': '`',
|
||||
'=': '=',
|
||||
});
|
||||
function replaceChar(c) {
|
||||
return escapeCharMap[c];
|
||||
}
|
||||
var escapeChars = /[&<>"'`=]/g;
|
||||
|
||||
var HTMLEntities = freeze({
|
||||
amp: '&',
|
||||
gt: '>',
|
||||
lt: '<',
|
||||
quot: '"',
|
||||
apos: "'",
|
||||
AElig: 198,
|
||||
Aacute: 193,
|
||||
Acirc: 194,
|
||||
Agrave: 192,
|
||||
Aring: 197,
|
||||
Atilde: 195,
|
||||
Auml: 196,
|
||||
Ccedil: 199,
|
||||
ETH: 208,
|
||||
Eacute: 201,
|
||||
Ecirc: 202,
|
||||
Egrave: 200,
|
||||
Euml: 203,
|
||||
Iacute: 205,
|
||||
Icirc: 206,
|
||||
Igrave: 204,
|
||||
Iuml: 207,
|
||||
Ntilde: 209,
|
||||
Oacute: 211,
|
||||
Ocirc: 212,
|
||||
Ograve: 210,
|
||||
Oslash: 216,
|
||||
Otilde: 213,
|
||||
Ouml: 214,
|
||||
THORN: 222,
|
||||
Uacute: 218,
|
||||
Ucirc: 219,
|
||||
Ugrave: 217,
|
||||
Uuml: 220,
|
||||
Yacute: 221,
|
||||
aacute: 225,
|
||||
acirc: 226,
|
||||
aelig: 230,
|
||||
agrave: 224,
|
||||
aring: 229,
|
||||
atilde: 227,
|
||||
auml: 228,
|
||||
ccedil: 231,
|
||||
eacute: 233,
|
||||
ecirc: 234,
|
||||
egrave: 232,
|
||||
eth: 240,
|
||||
euml: 235,
|
||||
iacute: 237,
|
||||
icirc: 238,
|
||||
igrave: 236,
|
||||
iuml: 239,
|
||||
ntilde: 241,
|
||||
oacute: 243,
|
||||
ocirc: 244,
|
||||
ograve: 242,
|
||||
oslash: 248,
|
||||
otilde: 245,
|
||||
ouml: 246,
|
||||
szlig: 223,
|
||||
thorn: 254,
|
||||
uacute: 250,
|
||||
ucirc: 251,
|
||||
ugrave: 249,
|
||||
uuml: 252,
|
||||
yacute: 253,
|
||||
yuml: 255,
|
||||
copy: 169,
|
||||
reg: 174,
|
||||
nbsp: 160,
|
||||
iexcl: 161,
|
||||
cent: 162,
|
||||
pound: 163,
|
||||
curren: 164,
|
||||
yen: 165,
|
||||
brvbar: 166,
|
||||
sect: 167,
|
||||
uml: 168,
|
||||
ordf: 170,
|
||||
laquo: 171,
|
||||
not: 172,
|
||||
shy: 173,
|
||||
macr: 175,
|
||||
deg: 176,
|
||||
plusmn: 177,
|
||||
sup1: 185,
|
||||
sup2: 178,
|
||||
sup3: 179,
|
||||
acute: 180,
|
||||
micro: 181,
|
||||
para: 182,
|
||||
middot: 183,
|
||||
cedil: 184,
|
||||
ordm: 186,
|
||||
raquo: 187,
|
||||
frac14: 188,
|
||||
frac12: 189,
|
||||
frac34: 190,
|
||||
iquest: 191,
|
||||
times: 215,
|
||||
divide: 247,
|
||||
'OElig;': 338,
|
||||
'oelig;': 339,
|
||||
'Scaron;': 352,
|
||||
'scaron;': 353,
|
||||
'Yuml;': 376,
|
||||
'fnof;': 402,
|
||||
'circ;': 710,
|
||||
'tilde;': 732,
|
||||
'Alpha;': 913,
|
||||
'Beta;': 914,
|
||||
'Gamma;': 915,
|
||||
'Delta;': 916,
|
||||
'Epsilon;': 917,
|
||||
'Zeta;': 918,
|
||||
'Eta;': 919,
|
||||
'Theta;': 920,
|
||||
'Iota;': 921,
|
||||
'Kappa;': 922,
|
||||
'Lambda;': 923,
|
||||
'Mu;': 924,
|
||||
'Nu;': 925,
|
||||
'Xi;': 926,
|
||||
'Omicron;': 927,
|
||||
'Pi;': 928,
|
||||
'Rho;': 929,
|
||||
'Sigma;': 931,
|
||||
'Tau;': 932,
|
||||
'Upsilon;': 933,
|
||||
'Phi;': 934,
|
||||
'Chi;': 935,
|
||||
'Psi;': 936,
|
||||
'Omega;': 937,
|
||||
'alpha;': 945,
|
||||
'beta;': 946,
|
||||
'gamma;': 947,
|
||||
'delta;': 948,
|
||||
'epsilon;': 949,
|
||||
'zeta;': 950,
|
||||
'eta;': 951,
|
||||
'theta;': 952,
|
||||
'iota;': 953,
|
||||
'kappa;': 954,
|
||||
'lambda;': 955,
|
||||
'mu;': 956,
|
||||
'nu;': 957,
|
||||
'xi;': 958,
|
||||
'omicron;': 959,
|
||||
'pi;': 960,
|
||||
'rho;': 961,
|
||||
'sigmaf;': 962,
|
||||
'sigma;': 963,
|
||||
'tau;': 964,
|
||||
'upsilon;': 965,
|
||||
'phi;': 966,
|
||||
'chi;': 967,
|
||||
'psi;': 968,
|
||||
'omega;': 969,
|
||||
'thetasym;': 977,
|
||||
'upsih;': 978,
|
||||
'piv;': 982,
|
||||
'ensp;': 8194,
|
||||
'emsp;': 8195,
|
||||
'thinsp;': 8201,
|
||||
'zwnj;': 8204,
|
||||
'zwj;': 8205,
|
||||
'lrm;': 8206,
|
||||
'rlm;': 8207,
|
||||
'ndash;': 8211,
|
||||
'mdash;': 8212,
|
||||
'lsquo;': 8216,
|
||||
'rsquo;': 8217,
|
||||
'sbquo;': 8218,
|
||||
'ldquo;': 8220,
|
||||
'rdquo;': 8221,
|
||||
'bdquo;': 8222,
|
||||
'dagger;': 8224,
|
||||
'Dagger;': 8225,
|
||||
'bull;': 8226,
|
||||
'hellip;': 8230,
|
||||
'permil;': 8240,
|
||||
'prime;': 8242,
|
||||
'Prime;': 8243,
|
||||
'lsaquo;': 8249,
|
||||
'rsaquo;': 8250,
|
||||
'oline;': 8254,
|
||||
'frasl;': 8260,
|
||||
'euro;': 8364,
|
||||
'image;': 8465,
|
||||
'weierp;': 8472,
|
||||
'real;': 8476,
|
||||
'trade;': 8482,
|
||||
'alefsym;': 8501,
|
||||
'larr;': 8592,
|
||||
'uarr;': 8593,
|
||||
'rarr;': 8594,
|
||||
'darr;': 8595,
|
||||
'harr;': 8596,
|
||||
'crarr;': 8629,
|
||||
'lArr;': 8656,
|
||||
'uArr;': 8657,
|
||||
'rArr;': 8658,
|
||||
'dArr;': 8659,
|
||||
'hArr;': 8660,
|
||||
'forall;': 8704,
|
||||
'part;': 8706,
|
||||
'exist;': 8707,
|
||||
'empty;': 8709,
|
||||
'nabla;': 8711,
|
||||
'isin;': 8712,
|
||||
'notin;': 8713,
|
||||
'ni;': 8715,
|
||||
'prod;': 8719,
|
||||
'sum;': 8721,
|
||||
'minus;': 8722,
|
||||
'lowast;': 8727,
|
||||
'radic;': 8730,
|
||||
'prop;': 8733,
|
||||
'infin;': 8734,
|
||||
'ang;': 8736,
|
||||
'and;': 8743,
|
||||
'or;': 8744,
|
||||
'cap;': 8745,
|
||||
'cup;': 8746,
|
||||
'int;': 8747,
|
||||
'there4;': 8756,
|
||||
'sim;': 8764,
|
||||
'cong;': 8773,
|
||||
'asymp;': 8776,
|
||||
'ne;': 8800,
|
||||
'equiv;': 8801,
|
||||
'le;': 8804,
|
||||
'ge;': 8805,
|
||||
'sub;': 8834,
|
||||
'sup;': 8835,
|
||||
'nsub;': 8836,
|
||||
'sube;': 8838,
|
||||
'supe;': 8839,
|
||||
'oplus;': 8853,
|
||||
'otimes;': 8855,
|
||||
'perp;': 8869,
|
||||
'sdot;': 8901,
|
||||
'lceil;': 8968,
|
||||
'rceil;': 8969,
|
||||
'lfloor;': 8970,
|
||||
'rfloor;': 8971,
|
||||
'lang;': 9001,
|
||||
'rang;': 9002,
|
||||
'loz;': 9674,
|
||||
'spades;': 9824,
|
||||
'clubs;': 9827,
|
||||
'hearts;': 9829,
|
||||
'diams;': 9830,
|
||||
});
|
||||
|
||||
var utils = {
|
||||
generateUUID: function () {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
@@ -33,6 +306,35 @@
|
||||
return v.toString(16);
|
||||
});
|
||||
},
|
||||
// https://github.com/substack/node-ent/blob/master/index.js
|
||||
decodeHTMLEntities: function (html) {
|
||||
return String(html)
|
||||
.replace(/&#(\d+);?/g, function (_, code) {
|
||||
return String.fromCharCode(code);
|
||||
})
|
||||
.replace(/&#[xX]([A-Fa-f0-9]+);?/g, function (_, hex) {
|
||||
return String.fromCharCode(parseInt(hex, 16));
|
||||
})
|
||||
.replace(/&([^;\W]+;?)/g, function (m, e) {
|
||||
var ee = e.replace(/;$/, '');
|
||||
var target = HTMLEntities[e] || (e.match(/;$/) && HTMLEntities[ee]);
|
||||
|
||||
if (typeof target === 'number') {
|
||||
return String.fromCharCode(target);
|
||||
} else if (typeof target === 'string') {
|
||||
return target;
|
||||
}
|
||||
|
||||
return m;
|
||||
});
|
||||
},
|
||||
// https://github.com/jprichardson/string.js/blob/master/lib/string.js
|
||||
stripHTMLTags: function (str, tags) {
|
||||
var pattern = (tags || ['']).map(function (tag) {
|
||||
return utils.escapeRegexChars(tag);
|
||||
}).join('|');
|
||||
return String(str).replace(new RegExp('<(\\/)?(' + (pattern || '[^\\s>]+') + ')(\\s+[^<>]*?)?\\s*(\\/)?>', 'gi'), '');
|
||||
},
|
||||
|
||||
invalidUnicodeChars: XRegExp('[^\\p{L}\\s\\d\\-_]', 'g'),
|
||||
invalidLatinChars: /[^\w\s\d\-_]/g,
|
||||
@@ -232,8 +534,15 @@
|
||||
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
},
|
||||
|
||||
escapeHTML: function (raw) {
|
||||
return raw.replace(/&/gm, '&').replace(/</gm, '<').replace(/>/gm, '>');
|
||||
escapeHTML: function (str) {
|
||||
if (str == null) {
|
||||
return '';
|
||||
}
|
||||
if (!str) {
|
||||
return String(str);
|
||||
}
|
||||
|
||||
return str.toString().replace(escapeChars, replaceChar);
|
||||
},
|
||||
|
||||
isAndroidBrowser: function () {
|
||||
|
||||
@@ -100,7 +100,7 @@ Analytics.writeData = function (callback) {
|
||||
|
||||
async.parallel(dbQueue, function (err) {
|
||||
if (err) {
|
||||
winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message);
|
||||
winston.error('[analytics] Encountered error while writing analytics to data store', err);
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
var nconf = require('nconf');
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
|
||||
var user = require('../../user');
|
||||
var posts = require('../../posts');
|
||||
@@ -13,6 +12,7 @@ var helpers = require('../helpers');
|
||||
var pagination = require('../../pagination');
|
||||
var messaging = require('../../messaging');
|
||||
var translator = require('../../translator');
|
||||
var utils = require('../../utils');
|
||||
|
||||
var profileController = module.exports;
|
||||
|
||||
@@ -87,7 +87,7 @@ profileController.get = function (req, res, callback) {
|
||||
userData.profileviews = 1;
|
||||
}
|
||||
|
||||
var plainAboutMe = userData.aboutme ? S(userData.aboutme).decodeHTMLEntities().stripTags().s : '';
|
||||
var plainAboutMe = userData.aboutme ? utils.stripHTMLTags(utils.decodeHTMLEntities(userData.aboutme)) : '';
|
||||
|
||||
res.locals.metaTags = [
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
var nconf = require('nconf');
|
||||
|
||||
var user = require('../user');
|
||||
@@ -217,7 +216,7 @@ function addTags(topicData, req, res) {
|
||||
var postAtIndex = findPost(Math.max(0, req.params.post_index - 1));
|
||||
|
||||
if (postAtIndex && postAtIndex.content) {
|
||||
description = S(postAtIndex.content).decodeHTMLEntities().stripTags().s;
|
||||
description = utils.stripHTMLTags(utils.decodeHTMLEntities(postAtIndex.content));
|
||||
}
|
||||
|
||||
if (description.length > 255) {
|
||||
|
||||
@@ -104,7 +104,7 @@ mongoModule.init = function (callback) {
|
||||
|
||||
mongoClient.connect(connString, connOptions, function (err, _db) {
|
||||
if (err) {
|
||||
winston.error('NodeBB could not connect to your Mongo database. Mongo returned the following error: ' + err.message);
|
||||
winston.error('NodeBB could not connect to your Mongo database. Mongo returned the following error', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ mongoModule.createIndices = function (callback) {
|
||||
async.apply(createIndex, 'objects', { expireAt: 1 }, { expireAfterSeconds: 0, background: true }),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('Error creating index ' + err.message);
|
||||
winston.error('Error creating index', err);
|
||||
return callback(err);
|
||||
}
|
||||
winston.info('[database] Checking database indices done!');
|
||||
|
||||
@@ -99,8 +99,8 @@ redisModule.connect = function (options) {
|
||||
if (dbIdx >= 0) {
|
||||
cxn.select(dbIdx, function (err) {
|
||||
if (err) {
|
||||
winston.error('NodeBB could not connect to your Redis database. Redis returned the following error: ' + err.message);
|
||||
process.exit();
|
||||
winston.error('NodeBB could not connect to your Redis database. Redis returned the following error', err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
var async = require('async');
|
||||
var validator = require('validator');
|
||||
var winston = require('winston');
|
||||
|
||||
var db = require('./database');
|
||||
var batch = require('./batch');
|
||||
@@ -143,8 +144,8 @@ events.output = function () {
|
||||
process.stdout.write('\nDisplaying last ten administrative events...\n'.bold);
|
||||
events.getEvents(0, 9, function (err, events) {
|
||||
if (err) {
|
||||
process.stdout.write(' Error '.red + String(err.message).reset);
|
||||
process.exit(1);
|
||||
winston.error('Error fetching events', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
events.forEach(function (event) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
var S = require('string');
|
||||
var winston = require('winston');
|
||||
var validator = require('validator');
|
||||
|
||||
@@ -65,7 +64,7 @@ Flags.init = function (callback) {
|
||||
},
|
||||
}, function (err, data) {
|
||||
if (err) {
|
||||
winston.error('[flags/init] Could not retrieve filters (error: ' + err.message + ')');
|
||||
winston.error('[flags/init] Could not retrieve filters', err);
|
||||
data.filters = {};
|
||||
}
|
||||
|
||||
@@ -660,7 +659,7 @@ Flags.notify = function (flagObj, uid, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var title = S(results.title).decodeHTMLEntities().s;
|
||||
var title = utils.decodeHTMLEntities(results.title);
|
||||
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
|
||||
|
||||
notifications.create({
|
||||
|
||||
@@ -52,7 +52,7 @@ module.exports = function (Groups) {
|
||||
hidden: 1,
|
||||
}, function (err) {
|
||||
if (err && err.message !== '[[error:group-already-exists]]') {
|
||||
winston.error('[groups.join] Could not create new hidden group: ' + err.message);
|
||||
winston.error('[groups.join] Could not create new hidden group', err);
|
||||
return callback(err);
|
||||
}
|
||||
next();
|
||||
|
||||
@@ -542,7 +542,7 @@ install.save = function (server_conf, callback) {
|
||||
|
||||
fs.writeFile(serverConfigPath, JSON.stringify(server_conf, null, 4), function (err) {
|
||||
if (err) {
|
||||
winston.error('Error saving server configuration! ' + err.message);
|
||||
winston.error('Error saving server configuration!', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ Logger.open = function (value) {
|
||||
|
||||
if (stream) {
|
||||
stream.on('error', function (err) {
|
||||
winston.error(err.message);
|
||||
winston.error(err);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
var validator = require('validator');
|
||||
|
||||
var db = require('./database');
|
||||
@@ -73,7 +72,7 @@ function canGet(hook, callerUid, uid, callback) {
|
||||
}
|
||||
|
||||
Messaging.parse = function (message, fromuid, uid, roomId, isNew, callback) {
|
||||
message = S(message).stripTags().decodeHTMLEntities().s;
|
||||
message = utils.decodeHTMLEntities(utils.stripHTMLTags(message));
|
||||
message = validator.escape(String(message));
|
||||
|
||||
plugins.fireHook('filter:parse.raw', message, function (err, parsed) {
|
||||
@@ -219,7 +218,7 @@ Messaging.getTeaser = function (uid, roomId, callback) {
|
||||
return callback();
|
||||
}
|
||||
if (teaser.content) {
|
||||
teaser.content = S(teaser.content).stripTags().decodeHTMLEntities().s;
|
||||
teaser.content = utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content));
|
||||
teaser.content = validator.escape(String(teaser.content));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
|
||||
var db = require('../database');
|
||||
var user = require('../user');
|
||||
@@ -73,7 +72,7 @@ module.exports = function (Messaging) {
|
||||
return next(err);
|
||||
}
|
||||
message.content = result;
|
||||
message.cleanedContent = S(result).stripTags().decodeHTMLEntities().s;
|
||||
message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(result));
|
||||
next(null, message);
|
||||
});
|
||||
}, next);
|
||||
|
||||
@@ -103,7 +103,7 @@ function beforeBuild(targets, callback) {
|
||||
async.apply(plugins.prepareForBuild, targets),
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[build] Encountered error preparing for build: ' + err.message);
|
||||
winston.error('[build] Encountered error preparing for build', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ function build(targets, callback) {
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[build] Encountered error during build step: ' + err.message);
|
||||
winston.error('[build] Encountered error during build step', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ exports.read = function read(callback) {
|
||||
|
||||
fs.readFile(filePath, function (err, buffer) {
|
||||
if (err) {
|
||||
winston.warn('[cache-buster] could not read cache buster: ' + err.message);
|
||||
winston.warn('[cache-buster] could not read cache buster', err);
|
||||
return callback(null, generate());
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ JS.scripts = {
|
||||
'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',
|
||||
],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var winston = require('winston');
|
||||
var path = require('path');
|
||||
var async = require('async');
|
||||
var fs = require('fs');
|
||||
@@ -182,11 +181,5 @@ exports.build = function buildLanguages(callback) {
|
||||
},
|
||||
getTranslationTree,
|
||||
writeLanguageFiles,
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[build] Language build failed: ' + err.message);
|
||||
throw err;
|
||||
}
|
||||
callback();
|
||||
});
|
||||
], callback);
|
||||
};
|
||||
|
||||
72
src/meta/package-install.js
Normal file
72
src/meta/package-install.js
Normal file
@@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var cproc = require('child_process');
|
||||
|
||||
var packageFilePath = path.join(__dirname, '../../package.json');
|
||||
var packageDefaultFilePath = path.join(__dirname, '../../package.default.json');
|
||||
var modulesPath = path.join(__dirname, '../../node_modules');
|
||||
|
||||
function updatePackageFile() {
|
||||
var oldPackageContents = {};
|
||||
|
||||
try {
|
||||
oldPackageContents = JSON.parse(fs.readFileSync(packageFilePath, 'utf8'));
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var defaultPackageContents = JSON.parse(fs.readFileSync(packageDefaultFilePath, 'utf8'));
|
||||
var packageContents = Object.assign({}, oldPackageContents, defaultPackageContents, {
|
||||
dependencies: Object.assign({}, oldPackageContents.dependencies, defaultPackageContents.dependencies),
|
||||
});
|
||||
|
||||
fs.writeFileSync(packageFilePath, JSON.stringify(packageContents, null, 2));
|
||||
}
|
||||
|
||||
exports.updatePackageFile = updatePackageFile;
|
||||
|
||||
function npmInstallProduction() {
|
||||
cproc.execSync('npm i --production', {
|
||||
cwd: path.join(__dirname, '../../'),
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
}
|
||||
|
||||
exports.npmInstallProduction = npmInstallProduction;
|
||||
|
||||
function preserveExtraneousPlugins() {
|
||||
// Skip if `node_modules/` is not found or inaccessible
|
||||
try {
|
||||
fs.accessSync(modulesPath, fs.constants.R_OK);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isPackage = /^nodebb-(plugin|theme|widget|reward)-\w+/;
|
||||
var packages = fs.readdirSync(modulesPath).filter(function (pkgName) {
|
||||
return isPackage.test(pkgName);
|
||||
});
|
||||
var packageContents = JSON.parse(fs.readFileSync(packageFilePath, 'utf8'));
|
||||
|
||||
var extraneous = packages
|
||||
// only extraneous plugins (ones not in package.json)
|
||||
.filter(function (pkgName) {
|
||||
return !packageContents.dependencies.hasOwnProperty(pkgName);
|
||||
})
|
||||
// reduce to a map of package names to package versions
|
||||
.reduce(function (map, pkgName) {
|
||||
var pkgConfig = JSON.parse(fs.readFileSync(path.join(modulesPath, pkgName, 'package.json')));
|
||||
map[pkgName] = pkgConfig.version;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
// Add those packages to package.json
|
||||
Object.assign(packageContents.dependencies, extraneous);
|
||||
fs.writeFileSync(packageFilePath, JSON.stringify(packageContents, null, 2));
|
||||
}
|
||||
|
||||
exports.preserveExtraneousPlugins = preserveExtraneousPlugins;
|
||||
@@ -66,9 +66,6 @@ module.exports = function (middleware) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
scripts: function (next) {
|
||||
plugins.fireHook('filter:scripts.get', [], next);
|
||||
},
|
||||
isAdmin: function (next) {
|
||||
user.isAdministrator(req.uid, next);
|
||||
},
|
||||
@@ -145,8 +142,8 @@ module.exports = function (middleware) {
|
||||
templateValues.userJSON = jsesc(JSON.stringify(results.user), { isScriptContext: true });
|
||||
templateValues.useCustomCSS = parseInt(meta.config.useCustomCSS, 10) === 1 && meta.config.customCSS;
|
||||
templateValues.customCSS = templateValues.useCustomCSS ? (meta.config.renderedCustomCSS || '') : '';
|
||||
templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1;
|
||||
templateValues.customJS = templateValues.useCustomJS ? meta.config.customJS : '';
|
||||
templateValues.useCustomHTML = parseInt(meta.config.useCustomHTML, 10) === 1;
|
||||
templateValues.customHTML = templateValues.useCustomHTML ? meta.config.customHTML : '';
|
||||
templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin;
|
||||
templateValues.defaultLang = meta.config.defaultLang || 'en-GB';
|
||||
templateValues.userLang = res.locals.config.userLang;
|
||||
@@ -157,12 +154,6 @@ module.exports = function (middleware) {
|
||||
templateValues.template = { name: res.locals.template };
|
||||
templateValues.template[res.locals.template] = true;
|
||||
|
||||
templateValues.scripts = results.scripts.map(function (script) {
|
||||
return { src: script };
|
||||
});
|
||||
|
||||
addTimeagoLocaleScript(templateValues.scripts, res.locals.config.userLang);
|
||||
|
||||
if (req.route && req.route.path === '/') {
|
||||
modifyTitle(templateValues);
|
||||
}
|
||||
@@ -194,6 +185,21 @@ module.exports = function (middleware) {
|
||||
}, next);
|
||||
},
|
||||
function (data, next) {
|
||||
async.parallel({
|
||||
scripts: async.apply(plugins.fireHook, 'filter:scripts.get', []),
|
||||
}, function (err, results) {
|
||||
next(err, data, results);
|
||||
});
|
||||
},
|
||||
function (data, results, next) {
|
||||
data.templateValues.scripts = results.scripts.map(function (script) {
|
||||
return { src: script };
|
||||
});
|
||||
addTimeagoLocaleScript(data.templateValues.scripts, res.locals.config.userLang);
|
||||
|
||||
data.templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1;
|
||||
data.templateValues.customJS = data.templateValues.useCustomJS ? meta.config.customJS : '';
|
||||
|
||||
req.app.render('footer', data.templateValues, next);
|
||||
},
|
||||
], callback);
|
||||
|
||||
@@ -132,7 +132,7 @@ module.exports = function (middleware) {
|
||||
try {
|
||||
p = decodeURIComponent(p);
|
||||
} catch (err) {
|
||||
winston.error(err.message);
|
||||
winston.error(err);
|
||||
p = '';
|
||||
}
|
||||
p = validator.escape(String(p));
|
||||
|
||||
@@ -4,7 +4,6 @@ var async = require('async');
|
||||
var winston = require('winston');
|
||||
var cron = require('cron').CronJob;
|
||||
var nconf = require('nconf');
|
||||
var S = require('string');
|
||||
var _ = require('lodash');
|
||||
|
||||
var db = require('./database');
|
||||
@@ -56,7 +55,7 @@ Notifications.getMultiple = function (nids, callback) {
|
||||
notification.datetimeISO = utils.toISOString(notification.datetime);
|
||||
|
||||
if (notification.bodyLong) {
|
||||
notification.bodyLong = S(notification.bodyLong).escapeHTML().s;
|
||||
notification.bodyLong = utils.escapeHTML(notification.bodyLong);
|
||||
}
|
||||
|
||||
notification.user = usersData[index];
|
||||
@@ -397,7 +396,7 @@ Notifications.prune = function (callback) {
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('Encountered error pruning notifications: ' + err.message);
|
||||
winston.error('Encountered error pruning notifications', err);
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
@@ -470,7 +469,7 @@ Notifications.merge = function (notifications, callback) {
|
||||
});
|
||||
var numUsers = usernames.length;
|
||||
|
||||
var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s;
|
||||
var title = utils.decodeHTMLEntities(notifications[modifyIndex].topicTitle || '');
|
||||
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
|
||||
titleEscaped = titleEscaped ? (', ' + titleEscaped) : '';
|
||||
|
||||
|
||||
@@ -4,16 +4,39 @@ var path = require('path');
|
||||
|
||||
var fork = require('./meta/debugFork');
|
||||
|
||||
exports.hash = function (rounds, password, callback) {
|
||||
function hash(rounds, password, callback) {
|
||||
forkChild({ type: 'hash', rounds: rounds, password: password }, callback);
|
||||
};
|
||||
}
|
||||
|
||||
exports.compare = function (password, hash, callback) {
|
||||
if (!hash || !password) {
|
||||
return setImmediate(callback, null, false);
|
||||
exports.hash = hash;
|
||||
|
||||
var fakeHashCache;
|
||||
function getFakeHash(callback) {
|
||||
if (fakeHashCache) {
|
||||
return callback(null, fakeHashCache);
|
||||
}
|
||||
forkChild({ type: 'compare', password: password, hash: hash }, callback);
|
||||
};
|
||||
|
||||
hash(12, Math.random().toString(), function (err, hash) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
fakeHashCache = hash;
|
||||
callback(null, fakeHashCache);
|
||||
});
|
||||
}
|
||||
|
||||
function compare(password, hash, callback) {
|
||||
getFakeHash(function (err, fakeHash) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
forkChild({ type: 'compare', password: password, hash: hash || fakeHash }, callback);
|
||||
});
|
||||
}
|
||||
|
||||
exports.compare = compare;
|
||||
|
||||
function forkChild(message, callback) {
|
||||
var child = fork(path.join(__dirname, 'bcrypt'));
|
||||
|
||||
@@ -63,7 +63,7 @@ Plugins.init = function (nbbApp, nbbMiddleware, callback) {
|
||||
|
||||
Plugins.reload(function (err) {
|
||||
if (err) {
|
||||
winston.error('[plugins] NodeBB encountered a problem while loading plugins', err.message);
|
||||
winston.error('[plugins] NodeBB encountered a problem while loading plugins', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ Plugins.reloadRoutes = function (callback) {
|
||||
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);
|
||||
winston.error('[plugins] Encountered error while executing post-router plugins hooks', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ Plugins.list = function (matching, callback) {
|
||||
json: true,
|
||||
}, function (err, res, body) {
|
||||
if (err) {
|
||||
winston.error('Error parsing plugins : ' + err.message);
|
||||
winston.error('Error parsing plugins', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ function loadPluginInfo(pluginPath, callback) {
|
||||
} catch (err) {
|
||||
var pluginDir = path.basename(pluginPath);
|
||||
|
||||
winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json! ' + err.message);
|
||||
winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json!', err);
|
||||
return callback(new Error('[[error:parse-error]]'));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ var path = require('path');
|
||||
var fs = require('fs');
|
||||
var nconf = require('nconf');
|
||||
var os = require('os');
|
||||
var cproc = require('child_process');
|
||||
|
||||
var db = require('../database');
|
||||
var meta = require('../meta');
|
||||
@@ -107,7 +108,7 @@ module.exports = function (Plugins) {
|
||||
}
|
||||
|
||||
function runNpmCommand(command, pkgName, version, callback) {
|
||||
require('child_process').execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', [command, pkgName + (command === 'install' ? '@' + version : ''), '--no-save'], function (err, stdout) {
|
||||
cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', [command, pkgName + (command === 'install' ? '@' + version : ''), '--save'], function (err, stdout) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ var async = require('async');
|
||||
var nconf = require('nconf');
|
||||
var url = require('url');
|
||||
var winston = require('winston');
|
||||
var S = require('string');
|
||||
|
||||
var meta = require('../meta');
|
||||
var cache = require('./cache');
|
||||
var plugins = require('../plugins');
|
||||
var translator = require('../translator');
|
||||
var utils = require('../utils');
|
||||
|
||||
module.exports = function (Posts) {
|
||||
Posts.urlRegex = {
|
||||
@@ -82,7 +82,6 @@ module.exports = function (Posts) {
|
||||
|
||||
function sanitizeSignature(signature) {
|
||||
signature = translator.escape(signature);
|
||||
var string = S(signature);
|
||||
var tagsToStrip = [];
|
||||
|
||||
if (parseInt(meta.config['signatures:disableLinks'], 10) === 1) {
|
||||
@@ -93,6 +92,6 @@ module.exports = function (Posts) {
|
||||
tagsToStrip.push('img');
|
||||
}
|
||||
|
||||
return tagsToStrip.length ? string.stripTags.apply(string, tagsToStrip).s : signature;
|
||||
return utils.stripHTMLTags(signature, tagsToStrip);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
var async = require('async');
|
||||
var validator = require('validator');
|
||||
var S = require('string');
|
||||
var _ = require('lodash');
|
||||
|
||||
var topics = require('../topics');
|
||||
@@ -144,8 +143,7 @@ module.exports = function (Posts) {
|
||||
|
||||
function stripTags(content) {
|
||||
if (content) {
|
||||
var s = S(content);
|
||||
return s.stripTags.apply(s, utils.stripTags).s;
|
||||
return utils.stripHTMLTags(content, utils.stripTags);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ var Reset = {};
|
||||
Reset.reset = function (callback) {
|
||||
db.init(function (err) {
|
||||
if (err) {
|
||||
winston.error(err.message);
|
||||
process.exit(1);
|
||||
winston.error(err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (nconf.get('t')) {
|
||||
@@ -50,7 +50,7 @@ Reset.reset = function (callback) {
|
||||
if (!err) {
|
||||
winston.info('[reset] Reset complete.');
|
||||
} else {
|
||||
winston.error('[reset] Errors were encountered while resetting your forum settings: %s', err.message);
|
||||
winston.error('[reset] Errors were encountered while resetting your forum settings: %s', err);
|
||||
}
|
||||
|
||||
callback();
|
||||
@@ -141,7 +141,7 @@ function resetPlugin(pluginId, callback) {
|
||||
},
|
||||
], function (err) {
|
||||
if (err) {
|
||||
winston.error('[reset] Could not disable plugin: %s encountered error %s', pluginId, err.message);
|
||||
winston.error('[reset] Could not disable plugin: %s encountered error %s', pluginId, err);
|
||||
} else if (active) {
|
||||
winston.info('[reset] Plugin `%s` disabled', pluginId);
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
var S = require('string');
|
||||
|
||||
var db = require('../database');
|
||||
var websockets = require('./index');
|
||||
@@ -12,6 +11,7 @@ var topics = require('../topics');
|
||||
var privileges = require('../privileges');
|
||||
var notifications = require('../notifications');
|
||||
var plugins = require('../plugins');
|
||||
var utils = require('../utils');
|
||||
|
||||
var SocketHelpers = {};
|
||||
|
||||
@@ -105,7 +105,7 @@ SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, not
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var title = S(results.topicTitle).decodeHTMLEntities().s;
|
||||
var title = utils.decodeHTMLEntities(results.topicTitle);
|
||||
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
|
||||
|
||||
notifications.create({
|
||||
@@ -151,7 +151,7 @@ SocketHelpers.sendNotificationToTopicOwner = function (tid, fromuid, command, no
|
||||
return;
|
||||
}
|
||||
ownerUid = results.topicData.uid;
|
||||
var title = S(results.topicData.title).decodeHTMLEntities().s;
|
||||
var title = utils.decodeHTMLEntities(results.topicData.title);
|
||||
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
|
||||
|
||||
notifications.create({
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
var async = require('async');
|
||||
var validator = require('validator');
|
||||
var _ = require('lodash');
|
||||
var S = require('string');
|
||||
|
||||
var posts = require('../../posts');
|
||||
var groups = require('../../groups');
|
||||
var events = require('../../events');
|
||||
var meta = require('../../meta');
|
||||
var utils = require('../../utils');
|
||||
var websockets = require('../index');
|
||||
|
||||
module.exports = function (SocketPosts) {
|
||||
@@ -20,7 +20,7 @@ module.exports = function (SocketPosts) {
|
||||
}
|
||||
|
||||
// Trim and remove HTML (latter for composers that send in HTML, like redactor)
|
||||
var contentLen = S(data.content).stripTags().s.trim().length;
|
||||
var contentLen = utils.stripHTMLTags(data.content).trim().length;
|
||||
|
||||
if (data.title && data.title.length < parseInt(meta.config.minimumTitleLength, 10)) {
|
||||
return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'));
|
||||
|
||||
@@ -28,7 +28,8 @@ module.exports = function (SocketTopics) {
|
||||
function (_topicData, next) {
|
||||
topicData = _topicData;
|
||||
topicData.tid = tid;
|
||||
topics.tools.move(tid, data.cid, socket.uid, next);
|
||||
data.uid = socket.uid;
|
||||
topics.tools.move(tid, data, next);
|
||||
},
|
||||
function (next) {
|
||||
socketHelpers.emitToTopicAndCategory('event:topic_moved', topicData);
|
||||
@@ -59,8 +60,9 @@ module.exports = function (SocketTopics) {
|
||||
categories.getAllTopicIds(data.currentCid, 0, -1, next);
|
||||
},
|
||||
function (tids, next) {
|
||||
data.uid = socket.uid;
|
||||
async.eachLimit(tids, 50, function (tid, next) {
|
||||
topics.tools.move(tid, data.cid, socket.uid, next);
|
||||
topics.tools.move(tid, data, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
var validator = require('validator');
|
||||
var S = require('string');
|
||||
|
||||
var db = require('../database');
|
||||
var utils = require('../utils');
|
||||
var plugins = require('../plugins');
|
||||
@@ -343,7 +343,7 @@ module.exports = function (Topics) {
|
||||
function check(item, min, max, minError, maxError, callback) {
|
||||
// Trim and remove HTML (latter for composers that send in HTML, like redactor)
|
||||
if (typeof item === 'string') {
|
||||
item = S(item).stripTags().s.trim();
|
||||
item = utils.stripHTMLTags(item).trim();
|
||||
}
|
||||
|
||||
if (item === null || item === undefined || item.length < parseInt(min, 10)) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
var winston = require('winston');
|
||||
|
||||
var db = require('../database');
|
||||
@@ -13,6 +12,7 @@ var privileges = require('../privileges');
|
||||
var meta = require('../meta');
|
||||
var emailer = require('../emailer');
|
||||
var plugins = require('../plugins');
|
||||
var utils = require('../utils');
|
||||
|
||||
module.exports = function (Topics) {
|
||||
Topics.toggleFollow = function (tid, uid, callback) {
|
||||
@@ -214,7 +214,7 @@ module.exports = function (Topics) {
|
||||
title = postData.topic.title;
|
||||
|
||||
if (title) {
|
||||
title = S(title).decodeHTMLEntities().s;
|
||||
title = utils.decodeHTMLEntities(title);
|
||||
titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
var S = require('string');
|
||||
var winston = require('winston');
|
||||
|
||||
var meta = require('../meta');
|
||||
@@ -91,8 +90,7 @@ module.exports = function (Topics) {
|
||||
if (tidToPost[topic.tid]) {
|
||||
tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index];
|
||||
if (tidToPost[topic.tid].content) {
|
||||
var s = S(tidToPost[topic.tid].content);
|
||||
tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags).s;
|
||||
tidToPost[topic.tid].content = utils.stripHTMLTags(tidToPost[topic.tid].content, utils.stripTags);
|
||||
}
|
||||
}
|
||||
return tidToPost[topic.tid];
|
||||
|
||||
@@ -243,9 +243,10 @@ module.exports = function (Topics) {
|
||||
], callback);
|
||||
};
|
||||
|
||||
topicTools.move = function (tid, cid, uid, callback) {
|
||||
topicTools.move = function (tid, data, callback) {
|
||||
var topic;
|
||||
var oldCid;
|
||||
var cid = data.cid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
Topics.exists(tid, next);
|
||||
@@ -315,12 +316,11 @@ module.exports = function (Topics) {
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
plugins.fireHook('action:topic.move', {
|
||||
tid: tid,
|
||||
fromCid: oldCid,
|
||||
toCid: cid,
|
||||
uid: uid,
|
||||
});
|
||||
var hookData = _.clone(data);
|
||||
hookData.fromCid = oldCid;
|
||||
hookData.toCid = cid;
|
||||
hookData.tid = tid;
|
||||
plugins.fireHook('action:topic.move', hookData);
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
|
||||
37
src/upgrades/1.7.0/generate-custom-html.js
Normal file
37
src/upgrades/1.7.0/generate-custom-html.js
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
var meta = require('../../meta');
|
||||
|
||||
module.exports = {
|
||||
name: 'Generate customHTML block from old customJS setting',
|
||||
timestamp: Date.UTC(2017, 9, 12),
|
||||
method: function (callback) {
|
||||
var newHTML = meta.config.customJS;
|
||||
var newJS = [];
|
||||
|
||||
// Forgive me for parsing HTML with regex...
|
||||
var scriptMatch = /^<script\s?(?!async|deferred)?>([\s\S]+?)<\/script>/m;
|
||||
var match = scriptMatch.exec(newHTML);
|
||||
|
||||
while (match) {
|
||||
if (match[1]) {
|
||||
// Append to newJS array
|
||||
newJS.push(match[1].trim());
|
||||
|
||||
// Remove the match from the existing value
|
||||
newHTML = ((match.index > 0 ? newHTML.slice(0, match.index) : '') + newHTML.slice(match.index + match[0].length)).trim();
|
||||
}
|
||||
|
||||
match = scriptMatch.exec(newHTML);
|
||||
}
|
||||
|
||||
// Combine newJS array
|
||||
newJS = newJS.join('\n\n');
|
||||
|
||||
// Write both values to config
|
||||
meta.configs.setMultiple({
|
||||
customHTML: newHTML,
|
||||
customJS: newJS,
|
||||
}, callback);
|
||||
},
|
||||
};
|
||||
@@ -45,7 +45,7 @@ Digest.execute = function (payload, callback) {
|
||||
},
|
||||
], function (err, count) {
|
||||
if (err) {
|
||||
winston.error('[user/jobs] Could not send digests (' + payload.interval + '): ' + err.message);
|
||||
winston.error('[user/jobs] Could not send digests (' + payload.interval + ')', err);
|
||||
} else {
|
||||
winston.info('[user/jobs] Digest (' + payload.interval + ') scheduling completed. ' + count + ' email(s) sent.');
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
var S = require('string');
|
||||
|
||||
var db = require('../database');
|
||||
var meta = require('../meta');
|
||||
var notifications = require('../notifications');
|
||||
var privileges = require('../privileges');
|
||||
var utils = require('../utils');
|
||||
|
||||
var UserNotifications = module.exports;
|
||||
|
||||
@@ -281,7 +281,7 @@ UserNotifications.sendTopicNotificationToFollowers = function (uid, topicData, p
|
||||
|
||||
var title = topicData.title;
|
||||
if (title) {
|
||||
title = S(title).decodeHTMLEntities().s;
|
||||
title = utils.decodeHTMLEntities(title);
|
||||
}
|
||||
|
||||
notifications.create({
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var S = require('string');
|
||||
|
||||
var utils = require('../utils');
|
||||
var meta = require('../meta');
|
||||
@@ -61,7 +60,7 @@ module.exports = function (User) {
|
||||
} else if (field === 'fullname') {
|
||||
return updateFullname(updateUid, data.fullname, next);
|
||||
} else if (field === 'signature') {
|
||||
data[field] = S(data[field]).stripTags().s;
|
||||
data[field] = utils.stripHTMLTags(data[field]);
|
||||
}
|
||||
|
||||
User.setUserField(updateUid, field, data[field], next);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div id="customise" class="customise">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="active"><a href="#custom-css" data-toggle="tab">[[admin/appearance/customise:custom-css]]</a></li>
|
||||
<li><a href="#custom-js" data-toggle="tab">[[admin/appearance/customise:custom-js]]</a></li>
|
||||
<li><a href="#custom-header" data-toggle="tab">[[admin/appearance/customise:custom-header]]</a></li>
|
||||
</ul>
|
||||
<br />
|
||||
@@ -23,19 +24,37 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="custom-header">
|
||||
<div class="tab-pane fade" id="custom-js">
|
||||
<p>
|
||||
[[admin/appearance/customise:custom-header.description]]
|
||||
[[admin/appearance/customise:custom-js.description]]
|
||||
</p>
|
||||
|
||||
<div id="customHTML"></div>
|
||||
<input type="hidden" id="customHTML-holder" value="" data-field="customJS" />
|
||||
<div id="customJS"></div>
|
||||
<input type="hidden" id="customJS-holder" value="" data-field="customJS" />
|
||||
|
||||
<br />
|
||||
<form class="form">
|
||||
<div class="form-group">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="useCustomJS">
|
||||
<input class="mdl-switch__input" id="useCustomJS" type="checkbox" data-field="useCustomJS" />
|
||||
<span class="mdl-switch__label">[[admin/appearance/customise:custom-js.enable]]</span>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="custom-header">
|
||||
<p>
|
||||
[[admin/appearance/customise:custom-header.description]]
|
||||
</p>
|
||||
|
||||
<div id="customHTML"></div>
|
||||
<input type="hidden" id="customHTML-holder" value="" data-field="customHTML" />
|
||||
|
||||
<br />
|
||||
<form class="form">
|
||||
<div class="form-group">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="useCustomHTML">
|
||||
<input class="mdl-switch__input" id="useCustomHTML" type="checkbox" data-field="useCustomHTML" />
|
||||
<span class="mdl-switch__label">[[admin/appearance/customise:custom-header.enable]]</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -43,13 +43,13 @@ if (nconf.get('ssl')) {
|
||||
module.exports.server = server;
|
||||
|
||||
server.on('error', function (err) {
|
||||
winston.error(err);
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
winston.error('NodeBB address in use, exiting...');
|
||||
process.exit(1);
|
||||
winston.error('NodeBB address in use, exiting...', err);
|
||||
} else {
|
||||
throw err;
|
||||
winston.error(err);
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
|
||||
module.exports.listen = function (callback) {
|
||||
@@ -301,13 +301,12 @@ function listen(callback) {
|
||||
if (isSocket) {
|
||||
oldUmask = process.umask('0000');
|
||||
module.exports.testSocket(socketPath, function (err) {
|
||||
if (!err) {
|
||||
server.listen.apply(server, args);
|
||||
} else {
|
||||
winston.error('[startup] NodeBB was unable to secure domain socket access (' + socketPath + ')');
|
||||
winston.error('[startup] ' + err.message);
|
||||
process.exit();
|
||||
if (err) {
|
||||
winston.error('[startup] NodeBB was unable to secure domain socket access (' + socketPath + ')', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
server.listen.apply(server, args);
|
||||
});
|
||||
} else {
|
||||
server.listen.apply(server, args);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var string = require('string');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var assert = require('assert');
|
||||
|
||||
@@ -5,6 +5,7 @@ var assert = require('assert');
|
||||
var path = require('path');
|
||||
var nconf = require('nconf');
|
||||
var request = require('request');
|
||||
var fs = require('fs');
|
||||
|
||||
var db = require('./mocks/databasemock');
|
||||
var plugins = require('../src/plugins');
|
||||
@@ -128,6 +129,9 @@ describe('Plugins', function () {
|
||||
assert.equal(pluginData.active, false);
|
||||
assert.equal(pluginData.installed, true);
|
||||
|
||||
var packageFile = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
|
||||
assert(packageFile.dependencies[pluginName]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -160,6 +164,10 @@ describe('Plugins', function () {
|
||||
assert.ifError(err);
|
||||
assert.equal(pluginData.installed, false);
|
||||
assert.equal(pluginData.active, false);
|
||||
|
||||
var packageFile = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
|
||||
assert(!packageFile.dependencies[pluginName]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,30 @@ describe('Utility Methods', function () {
|
||||
var $ = global.$;
|
||||
global.window = window;
|
||||
|
||||
// https://github.com/jprichardson/string.js/blob/master/test/string.test.js
|
||||
it('should decode HTML entities', function (done) {
|
||||
assert.strictEqual(
|
||||
utils.decodeHTMLEntities('Ken Thompson & Dennis Ritchie'),
|
||||
'Ken Thompson & Dennis Ritchie'
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.decodeHTMLEntities('3 < 4'),
|
||||
'3 < 4'
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.decodeHTMLEntities('http://'),
|
||||
'http://'
|
||||
);
|
||||
done();
|
||||
});
|
||||
it('should strip HTML tags', function (done) {
|
||||
assert.strictEqual(utils.stripHTMLTags('<p>just <b>some</b> text</p>'), 'just some text');
|
||||
assert.strictEqual(utils.stripHTMLTags('<p>just <b>some</b> text</p>', ['p']), 'just <b>some</b> text');
|
||||
assert.strictEqual(utils.stripHTMLTags('<i>just</i> some <image/> text', ['i']), 'just some <image/> text');
|
||||
assert.strictEqual(utils.stripHTMLTags('<i>just</i> some <image/> <div>text</div>', ['i', 'div']), 'just some <image/> text');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should preserve case if requested', function (done) {
|
||||
var slug = utils.slugify('UPPER CASE', true);
|
||||
assert.equal(slug, 'UPPER-CASE');
|
||||
|
||||
Reference in New Issue
Block a user