chore: eslint max-len

v1.18.x
Peter Jaszkowiak 4 years ago committed by Julian Lam
parent 5c2f0f0557
commit cc9d6fd08b

@ -81,8 +81,7 @@
} }
], ],
// allow lines of up to 120 characters // allow lines of up to 120 characters
// "max-len": ["error", { "code": 120, "tabWidth": 2, "ignoreUrls": true, "ignoreStrings": true, "ignoreTemplateLiterals": true, "ignoreRegExpLiterals": true }], "max-len": ["error", { "code": 120, "tabWidth": 2, "ignoreUrls": true, "ignoreStrings": true, "ignoreTemplateLiterals": true, "ignoreRegExpLiterals": true }],
"max-len": "off", // do this LAST
// === Disable rules === // === Disable rules ===
// more liberal naming // more liberal naming

@ -184,7 +184,9 @@ define('admin/manage/users', [
data[cur.name] = cur.value; data[cur.name] = cur.value;
return data; return data;
}, {}); }, {});
var until = formData.length > 0 ? (Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))) : 0; var until = formData.length > 0 ? (
Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))
) : 0;
Promise.all(uids.map(function (uid) { Promise.all(uids.map(function (uid) {
return api.put('/users/' + uid + '/ban', { return api.put('/users/' + uid + '/ban', {

@ -62,7 +62,11 @@ ajaxify = window.ajaxify || {};
$('#footer, #content').removeClass('hide').addClass('ajaxifying'); $('#footer, #content').removeClass('hide').addClass('ajaxifying');
ajaxify.loadData(url, function (err, data) { ajaxify.loadData(url, function (err, data) {
if (!err || (err && err.data && (parseInt(err.data.status, 10) !== 302 && parseInt(err.data.status, 10) !== 308))) { if (!err || (
err &&
err.data &&
(parseInt(err.data.status, 10) !== 302 && parseInt(err.data.status, 10) !== 308)
)) {
ajaxify.updateHistory(url, quiet); ajaxify.updateHistory(url, quiet);
} }
@ -340,7 +344,8 @@ ajaxify = window.ajaxify || {};
if (typeof script === 'string') { if (typeof script === 'string') {
return function (next) { return function (next) {
require(['hooks', script], function (hooks, module) { require(['hooks', script], function (hooks, module) {
// Hint: useful if you want to override a loaded library (e.g. replace core client-side logic), or call a method other than .init() // Hint: useful if you want to override a loaded library (e.g. replace core client-side logic),
// or call a method other than .init()
hooks.fire('static:script.init', { tpl_url, name: script, module }).then(() => { hooks.fire('static:script.init', { tpl_url, name: script, module }).then(() => {
if (module && module.init) { if (module && module.init) {
module.init(); module.init();

@ -43,7 +43,9 @@ define('forum/account/edit', [
aboutme: $('#inputAboutMe').val(), aboutme: $('#inputAboutMe').val(),
}; };
userData.groupTitle = JSON.stringify(Array.isArray(userData.groupTitle) ? userData.groupTitle : [userData.groupTitle]); userData.groupTitle = JSON.stringify(
Array.isArray(userData.groupTitle) ? userData.groupTitle : [userData.groupTitle]
);
$(window).trigger('action:profile.update', userData); $(window).trigger('action:profile.update', userData);

@ -150,7 +150,9 @@ define('forum/account/header', [
return data; return data;
}, {}); }, {});
var until = formData.length > 0 ? (Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))) : 0; var until = formData.length > 0 ? (
Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))
) : 0;
api.put('/users/' + theirid + '/ban', { api.put('/users/' + theirid + '/ban', {
until: until, until: until,

@ -10,7 +10,17 @@ define('forum/groups/details', [
'api', 'api',
'slugify', 'slugify',
'categorySelector', 'categorySelector',
], function (memberList, iconSelect, components, coverPhoto, pictureCropper, translator, api, slugify, categorySelector) { ], function (
memberList,
iconSelect,
components,
coverPhoto,
pictureCropper,
translator,
api,
slugify,
categorySelector
) {
var Details = {}; var Details = {};
var groupName; var groupName;

@ -130,7 +130,10 @@ define('forum/topic', [
if (components.get('post/anchor', postIndex - 1).length) { if (components.get('post/anchor', postIndex - 1).length) {
return navigator.scrollToPostIndex(postIndex - 1, true, 0); return navigator.scrollToPostIndex(postIndex - 1, true, 0);
} }
} else if (bookmark && (!config.usePagination || (config.usePagination && ajaxify.data.pagination.currentPage === 1)) && ajaxify.data.postcount > ajaxify.data.bookmarkThreshold) { } else if (bookmark && (
!config.usePagination ||
(config.usePagination && ajaxify.data.pagination.currentPage === 1)
) && ajaxify.data.postcount > ajaxify.data.bookmarkThreshold) {
app.alert({ app.alert({
alert_id: 'bookmark', alert_id: 'bookmark',
message: '[[topic:bookmark_instructions]]', message: '[[topic:bookmark_instructions]]',
@ -250,7 +253,14 @@ define('forum/topic', [
index = Math.max(1, ajaxify.data.postcount - index + 2); index = Math.max(1, ajaxify.data.postcount - index + 2);
} }
if (ajaxify.data.postcount > ajaxify.data.bookmarkThreshold && (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10) || ajaxify.data.postcount < parseInt(currentBookmark, 10))) { if (
ajaxify.data.postcount > ajaxify.data.bookmarkThreshold &&
(
!currentBookmark ||
parseInt(index, 10) > parseInt(currentBookmark, 10) ||
ajaxify.data.postcount < parseInt(currentBookmark, 10)
)
) {
if (app.user.uid) { if (app.user.uid) {
socket.emit('topics.bookmark', { socket.emit('topics.bookmark', {
tid: ajaxify.data.tid, tid: ajaxify.data.tid,

@ -84,7 +84,11 @@ define('forum/topic/events', [
} }
function onTopicPurged(data) { function onTopicPurged(data) {
if (ajaxify.data.category && ajaxify.data.category.slug && parseInt(data.tid, 10) === parseInt(ajaxify.data.tid, 10)) { if (
ajaxify.data.category &&
ajaxify.data.category.slug &&
parseInt(data.tid, 10) === parseInt(ajaxify.data.tid, 10)
) {
ajaxify.go('category/' + ajaxify.data.category.slug, null, true); ajaxify.go('category/' + ajaxify.data.category.slug, null, true);
} }
} }

@ -13,7 +13,12 @@ define('forum/topic/posts', [
var Posts = { }; var Posts = { };
Posts.onNewPost = function (data) { Posts.onNewPost = function (data) {
if (!data || !data.posts || !data.posts.length || parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)) { if (
!data ||
!data.posts ||
!data.posts.length ||
parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)
) {
return; return;
} }
@ -88,8 +93,10 @@ define('forum/topic/posts', [
ajaxify.data.pagination.pageCount = Math.max(1, Math.ceil(posts[0].topic.postcount / config.postsPerPage)); ajaxify.data.pagination.pageCount = Math.max(1, Math.ceil(posts[0].topic.postcount / config.postsPerPage));
var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1; var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1;
var isPostVisible = (ajaxify.data.pagination.currentPage === ajaxify.data.pagination.pageCount && direction === 1) || var isPostVisible = (
(ajaxify.data.pagination.currentPage === 1 && direction === -1); ajaxify.data.pagination.currentPage === ajaxify.data.pagination.pageCount &&
direction === 1
) || (ajaxify.data.pagination.currentPage === 1 && direction === -1);
if (isPostVisible) { if (isPostVisible) {
createNewPosts(data, components.get('post').not('[data-index=0]'), direction, false, scrollToPost); createNewPosts(data, components.get('post').not('[data-index=0]'), direction, false, scrollToPost);
@ -299,7 +306,9 @@ define('forum/topic/posts', [
} }
Promise.all(events.map((event) => { Promise.all(events.map((event) => {
const beforeIdx = postTimestamps.findIndex(timestamp => (reverse ? (timestamp < event.timestamp) : (timestamp > event.timestamp))); const beforeIdx = postTimestamps.findIndex(
timestamp => (reverse ? (timestamp < event.timestamp) : (timestamp > event.timestamp))
);
let postEl; let postEl;
if (beforeIdx > -1) { if (beforeIdx > -1) {
postEl = document.querySelector(`[component="post"][data-pid="${ajaxify.data.posts[beforeIdx + (reverse ? 1 : 0)].pid}"]`); postEl = document.querySelector(`[component="post"][data-pid="${ajaxify.data.posts[beforeIdx + (reverse ? 1 : 0)].pid}"]`);

@ -34,7 +34,12 @@ define('handleBack', [
function onBackClicked(isMarkedUnread) { function onBackClicked(isMarkedUnread) {
var highlightUnread = isMarkedUnread && ajaxify.data.template.unread; var highlightUnread = isMarkedUnread && ajaxify.data.template.unread;
if (ajaxify.data.template.category || ajaxify.data.template.recent || ajaxify.data.template.popular || highlightUnread) { if (
ajaxify.data.template.category ||
ajaxify.data.template.recent ||
ajaxify.data.template.popular ||
highlightUnread
) {
var bookmarkIndex = storage.getItem('category:bookmark'); var bookmarkIndex = storage.getItem('category:bookmark');
var clickedIndex = storage.getItem('category:bookmark:clicked'); var clickedIndex = storage.getItem('category:bookmark:clicked');

@ -28,7 +28,9 @@ define('hooks', [], () => {
return listeners.reduce((promise, listener) => promise.then((data) => { return listeners.reduce((promise, listener) => promise.then((data) => {
try { try {
const result = listener(data); const result = listener(data);
return utils.isPromise(result) ? result.then(data => Promise.resolve(data)).catch(e => _onHookError(e, listener, data)) : result; return utils.isPromise(result) ?
result.then(data => Promise.resolve(data)).catch(e => _onHookError(e, listener, data)) :
result;
} catch (e) { } catch (e) {
return _onHookError(e, listener, data); return _onHookError(e, listener, data);
} }

@ -176,7 +176,9 @@ define('pictureCropper', ['cropper'], function (Cropper) {
function checkCORS(cropperTool, data) { function checkCORS(cropperTool, data) {
var imageData; var imageData;
try { try {
imageData = data.imageType ? cropperTool.getCroppedCanvas().toDataURL(data.imageType) : cropperTool.getCroppedCanvas().toDataURL(); imageData = data.imageType ?
cropperTool.getCroppedCanvas().toDataURL(data.imageType) :
cropperTool.getCroppedCanvas().toDataURL();
} catch (err) { } catch (err) {
var corsErrors = [ var corsErrors = [
'The operation is insecure.', 'The operation is insecure.',

@ -42,8 +42,22 @@ define('settings/key', function () {
@returns Key | null The Key-Object the focused element should be set to. @returns Key | null The Key-Object the focused element should be set to.
*/ */
function getKey(event) { function getKey(event) {
var anyModChange = event.ctrlKey !== lastKey.c || event.altKey !== lastKey.a || event.shiftKey !== lastKey.s || event.metaKey !== lastKey.m; var anyModChange = (
var modChange = event.ctrlKey + event.altKey + event.shiftKey + event.metaKey - lastKey.c - lastKey.a - lastKey.s - lastKey.m; event.ctrlKey !== lastKey.c ||
event.altKey !== lastKey.a ||
event.shiftKey !== lastKey.s ||
event.metaKey !== lastKey.m
);
var modChange = (
event.ctrlKey +
event.altKey +
event.shiftKey +
event.metaKey -
lastKey.c -
lastKey.a -
lastKey.s -
lastKey.m
);
var key = new Key(); var key = new Key();
key.c = event.ctrlKey; key.c = event.ctrlKey;
key.a = event.altKey; key.a = event.altKey;

@ -90,9 +90,15 @@ define('settings/object', function () {
if (value[propertyName] === undefined && attributes['data-new'] !== undefined) { if (value[propertyName] === undefined && attributes['data-new'] !== undefined) {
value[propertyName] = attributes['data-new']; value[propertyName] = attributes['data-new'];
} }
addObjectPropertyElement(element, key, attributes, propertyName, value[propertyName], separator.clone(), function (el) { addObjectPropertyElement(
element.append(el); element,
}); key,
attributes,
propertyName,
value[propertyName],
separator.clone(),
function (el) { element.append(el); }
);
} }
} }
} }

@ -96,9 +96,19 @@ define('topicList', [
function onNewTopic(data) { function onNewTopic(data) {
if ( if (
(ajaxify.data.selectedCids && ajaxify.data.selectedCids.length && ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1) || (
(ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') || ajaxify.data.selectedCids &&
(ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10)) ajaxify.data.selectedCids.length &&
ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1
) ||
(
ajaxify.data.selectedFilter &&
ajaxify.data.selectedFilter.filter === 'watched'
) ||
(
ajaxify.data.template.category &&
parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10)
)
) { ) {
return; return;
} }
@ -113,11 +123,25 @@ define('topicList', [
return; return;
} }
if (!post.topic.isFollowing && ( if (!post.topic.isFollowing && (
(parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10)) || parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10) ||
(ajaxify.data.selectedCids && ajaxify.data.selectedCids.length && ajaxify.data.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1) || (
(ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'new') || ajaxify.data.selectedCids &&
(ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched' && !post.topic.isFollowing) || ajaxify.data.selectedCids.length &&
(ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10)) ajaxify.data.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1
) ||
(
ajaxify.data.selectedFilter &&
ajaxify.data.selectedFilter.filter === 'new'
) ||
(
ajaxify.data.selectedFilter &&
ajaxify.data.selectedFilter.filter === 'watched' &&
!post.topic.isFollowing
) ||
(
ajaxify.data.template.category &&
parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10)
)
)) { )) {
return; return;
} }

@ -308,7 +308,8 @@
warn('[translator] Parameter `namespace` is ' + namespace + (namespace === '' ? '(empty string)' : '')); warn('[translator] Parameter `namespace` is ' + namespace + (namespace === '' ? '(empty string)' : ''));
translation = Promise.resolve({}); translation = Promise.resolve({});
} else { } else {
this.translations[namespace] = this.translations[namespace] || this.load(this.lang, namespace).catch(function () { return {}; }); this.translations[namespace] = this.translations[namespace] ||
this.load(this.lang, namespace).catch(function () { return {}; });
translation = this.translations[namespace]; translation = this.translations[namespace];
} }

@ -646,7 +646,10 @@
params.forEach(function (param) { params.forEach(function (param) {
var val = param.split('='); var val = param.split('=');
var key = decodeURI(val[0]); var key = decodeURI(val[0]);
var value = options.disableToType || options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1])); var value = (
options.disableToType ||
options.skipToType[key] ? decodeURI(val[1]) : utils.toType(decodeURI(val[1]))
);
if (key) { if (key) {
if (key.substr(-2, 2) === '[]') { if (key.substr(-2, 2) === '[]') {
@ -732,8 +735,11 @@
isInternalURI: function (targetLocation, referenceLocation, relative_path) { isInternalURI: function (targetLocation, referenceLocation, relative_path) {
return targetLocation.host === '' || // Relative paths are always internal links return targetLocation.host === '' || // Relative paths are always internal links
( (
targetLocation.host === referenceLocation.host && targetLocation.protocol === referenceLocation.protocol && // Otherwise need to check if protocol and host match targetLocation.host === referenceLocation.host &&
(relative_path.length > 0 ? targetLocation.pathname.indexOf(relative_path) === 0 : true) // Subfolder installs need this additional check // Otherwise need to check if protocol and host match
targetLocation.protocol === referenceLocation.protocol &&
// Subfolder installs need this additional check
(relative_path.length > 0 ? targetLocation.pathname.indexOf(relative_path) === 0 : true)
); );
}, },

@ -181,12 +181,17 @@ Analytics.getDailyStatsForSet = async function (set, day, numDays) {
const daysArr = []; const daysArr = [];
day = new Date(day); day = new Date(day);
day.setDate(day.getDate() + 1); // set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values // set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values
day.setDate(day.getDate() + 1);
day.setHours(0, 0, 0, 0); day.setHours(0, 0, 0, 0);
while (numDays > 0) { while (numDays > 0) {
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const dayData = await Analytics.getHourlyStatsForSet(set, day.getTime() - (1000 * 60 * 60 * 24 * (numDays - 1)), 24); const dayData = await Analytics.getHourlyStatsForSet(
set,
day.getTime() - (1000 * 60 * 60 * 24 * (numDays - 1)),
24
);
daysArr.push(dayData.reduce((cur, next) => cur + next)); daysArr.push(dayData.reduce((cur, next) => cur + next));
numDays -= 1; numDays -= 1;
} }

@ -118,7 +118,9 @@ Categories.getModeratorUids = async function (cids) {
const uniqGroups = _.uniq(_.flatten(sets.groupNames)); const uniqGroups = _.uniq(_.flatten(sets.groupNames));
const groupUids = await groups.getMembersOfGroups(uniqGroups); const groupUids = await groups.getMembersOfGroups(uniqGroups);
const map = _.zipObject(uniqGroups, groupUids); const map = _.zipObject(uniqGroups, groupUids);
const moderatorUids = cids.map((cid, index) => _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))))); const moderatorUids = cids.map(
(cid, index) => _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))))
);
return moderatorUids; return moderatorUids;
}; };

@ -68,7 +68,8 @@ function runSteps(tasks) {
} }
const message = 'NodeBB Upgrade Complete!'; const 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 // some consoles will return undefined/zero columns,
// so just use 2 spaces in upgrade script if we can't get our column count
const { columns } = process.stdout; const { columns } = process.stdout;
const spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' '; const spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';

@ -36,7 +36,10 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) {
const { canViewInfo } = results; const { canViewInfo } = results;
const isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10); const isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10);
userData.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0); userData.age = Math.max(
0,
userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0
);
userData.emailClass = 'hide'; userData.emailClass = 'hide';

@ -65,7 +65,10 @@ async function incrementProfileViews(req, userData) {
if (req.uid >= 1) { if (req.uid >= 1) {
req.session.uids_viewed = req.session.uids_viewed || {}; req.session.uids_viewed = req.session.uids_viewed || {};
if (req.uid !== userData.uid && (!req.session.uids_viewed[userData.uid] || req.session.uids_viewed[userData.uid] < Date.now() - 3600000)) { if (
req.uid !== userData.uid &&
(!req.session.uids_viewed[userData.uid] || req.session.uids_viewed[userData.uid] < Date.now() - 3600000)
) {
await user.incrementUserFieldBy(userData.uid, 'profileviews', 1); await user.incrementUserFieldBy(userData.uid, 'profileviews', 1);
req.session.uids_viewed[userData.uid] = Date.now(); req.session.uids_viewed[userData.uid] = Date.now();
} }
@ -102,7 +105,9 @@ async function getPosts(callerUid, userData, setSuffix) {
} }
if (pids.length) { if (pids.length) {
const p = await posts.getPostSummaryByPids(pids, callerUid, { stripTags: false }); const p = await posts.getPostSummaryByPids(pids, callerUid, { stripTags: false });
postData.push(...p.filter(p => p && p.topic && (isAdmin || cidToIsMod[p.topic.cid] || (!p.deleted && !p.topic.deleted)))); postData.push(...p.filter(
p => p && p.topic && (isAdmin || cidToIsMod[p.topic.cid] || (!p.deleted && !p.topic.deleted))
));
} }
start += count; start += count;
} while (postData.length < count && hasMorePosts); } while (postData.length < count && hasMorePosts);

@ -99,7 +99,9 @@ settingsController.get = async function (req, res, next) {
'disabled', 'disabled',
]; ];
userData.upvoteNotifFreq = notifFreqOptions.map(name => ({ name: name, selected: name === userData.settings.upvoteNotifFreq })); userData.upvoteNotifFreq = notifFreqOptions.map(
name => ({ name: name, selected: name === userData.settings.upvoteNotifFreq })
);
userData.categoryWatchState = { [userData.settings.categoryWatchState]: true }; userData.categoryWatchState = { [userData.settings.categoryWatchState]: true };

@ -22,10 +22,13 @@ pluginsController.get = async function (req, res) {
memo[cur.label] = cur.value; memo[cur.label] = cur.value;
return memo; return memo;
}, {}); }, {});
const trendingPlugins = all.filter(plugin => plugin && Object.keys(trendingScores).includes(plugin.id)).sort((a, b) => trendingScores[b.id] - trendingScores[a.id]).map((plugin) => { const trendingPlugins = all
plugin.downloads = trendingScores[plugin.id]; .filter(plugin => plugin && Object.keys(trendingScores).includes(plugin.id))
return plugin; .sort((a, b) => trendingScores[b.id] - trendingScores[a.id])
}); .map((plugin) => {
plugin.downloads = trendingScores[plugin.id];
return plugin;
});
res.render('admin/extend/plugins', { res.render('admin/extend/plugins', {
installed: installedPlugins, installed: installedPlugins,

@ -95,7 +95,9 @@ apiController.loadConfig = async function (req) {
config.usePagination = settings.usePagination; config.usePagination = settings.usePagination;
config.topicsPerPage = settings.topicsPerPage; config.topicsPerPage = settings.topicsPerPage;
config.postsPerPage = settings.postsPerPage; config.postsPerPage = settings.postsPerPage;
config.userLang = validator.escape(String((req.query.lang ? req.query.lang : null) || settings.userLang || config.defaultLang)); config.userLang = validator.escape(
String((req.query.lang ? req.query.lang : null) || settings.userLang || config.defaultLang)
);
config.acpLang = validator.escape(String((req.query.lang ? req.query.lang : null) || settings.acpLang)); config.acpLang = validator.escape(String((req.query.lang ? req.query.lang : null) || settings.acpLang));
config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab;
config.topicPostSort = settings.topicPostSort || config.topicPostSort; config.topicPostSort = settings.topicPostSort || config.topicPostSort;

@ -83,7 +83,11 @@ authenticationController.register = async function (req, res) {
throw new Error('[[error:invalid-email]]'); throw new Error('[[error:invalid-email]]');
} }
if (!userData.username || userData.username.length < meta.config.minimumUsernameLength || slugify(userData.username).length < meta.config.minimumUsernameLength) { if (
!userData.username ||
userData.username.length < meta.config.minimumUsernameLength ||
slugify(userData.username).length < meta.config.minimumUsernameLength
) {
throw new Error('[[error:username-too-short]]'); throw new Error('[[error:username-too-short]]');
} }

@ -315,7 +315,12 @@ helpers.getVisibleCategories = async function (params) {
return false; return false;
} }
const hasVisibleChildren = checkVisibleChildren(c, cidToAllowed, cidToWatchState, states); const hasVisibleChildren = checkVisibleChildren(c, cidToAllowed, cidToWatchState, states);
const isCategoryVisible = cidToAllowed[c.cid] && (showLinks || !c.link) && !c.disabled && states.includes(cidToWatchState[c.cid]); const isCategoryVisible = (
cidToAllowed[c.cid] &&
(showLinks || !c.link) &&
!c.disabled &&
states.includes(cidToWatchState[c.cid])
);
const shouldBeRemoved = !hasVisibleChildren && !isCategoryVisible; const shouldBeRemoved = !hasVisibleChildren && !isCategoryVisible;
const shouldBeDisaplayedAsDisabled = hasVisibleChildren && !isCategoryVisible; const shouldBeDisaplayedAsDisabled = hasVisibleChildren && !isCategoryVisible;
@ -380,7 +385,8 @@ function checkVisibleChildren(c, cidToAllowed, cidToWatchState, states) {
return false; return false;
} }
return c.children.some(c => !c.disabled && ( return c.children.some(c => !c.disabled && (
(cidToAllowed[c.cid] && states.includes(cidToWatchState[c.cid])) || checkVisibleChildren(c, cidToAllowed, cidToWatchState, states) (cidToAllowed[c.cid] && states.includes(cidToWatchState[c.cid])) ||
checkVisibleChildren(c, cidToAllowed, cidToWatchState, states)
)); ));
} }

@ -202,7 +202,9 @@ Controllers.registerInterstitial = async function (req, res, next) {
return helpers.redirect(res, returnTo || '/'); return helpers.redirect(res, returnTo || '/');
} }
const renders = data.interstitials.map(interstitial => req.app.renderAsync(interstitial.template, interstitial.data || {})); const renders = data.interstitials.map(
interstitial => req.app.renderAsync(interstitial.template, interstitial.data || {})
);
const sections = await Promise.all(renders); const sections = await Promise.all(renders);
res.render('registerComplete', { res.render('registerComplete', {

@ -131,7 +131,10 @@ modsController.flags.detail = async function (req, res, next) {
assignees: results.assignees, assignees: results.assignees,
type_bool: ['post', 'user', 'empty'].reduce((memo, cur) => { type_bool: ['post', 'user', 'empty'].reduce((memo, cur) => {
if (cur !== 'empty') { if (cur !== 'empty') {
memo[cur] = results.flagData.type === cur && (!results.flagData.target || !!Object.keys(results.flagData.target).length); memo[cur] = results.flagData.type === cur && (
!results.flagData.target ||
!!Object.keys(results.flagData.target).length
);
} else { } else {
memo[cur] = !Object.keys(results.flagData.target).length; memo[cur] = !Object.keys(results.flagData.target).length;
} }

@ -22,7 +22,10 @@ const upload_url = nconf.get('upload_url');
topicsController.get = async function getTopic(req, res, callback) { topicsController.get = async function getTopic(req, res, callback) {
const tid = req.params.topic_id; const tid = req.params.topic_id;
if ((req.params.post_index && !utils.isNumber(req.params.post_index) && req.params.post_index !== 'unread') || !utils.isNumber(tid)) { if (
(req.params.post_index && !utils.isNumber(req.params.post_index) && req.params.post_index !== 'unread') ||
!utils.isNumber(tid)
) {
return callback(); return callback();
} }
let postIndex = parseInt(req.params.post_index, 10) || 1; let postIndex = parseInt(req.params.post_index, 10) || 1;
@ -40,7 +43,11 @@ topicsController.get = async function getTopic(req, res, callback) {
let currentPage = parseInt(req.query.page, 10) || 1; let currentPage = parseInt(req.query.page, 10) || 1;
const pageCount = Math.max(1, Math.ceil((topicData && topicData.postcount) / settings.postsPerPage)); const pageCount = Math.max(1, Math.ceil((topicData && topicData.postcount) / settings.postsPerPage));
if (!topicData || userPrivileges.disabled || (settings.usePagination && (currentPage < 1 || currentPage > pageCount))) { if (
!topicData ||
userPrivileges.disabled ||
(settings.usePagination && (currentPage < 1 || currentPage > pageCount))
) {
return callback(); return callback();
} }

@ -101,7 +101,10 @@ async function uploadAsFile(req, uploadedFile) {
async function resizeImage(fileObj) { async function resizeImage(fileObj) {
const imageData = await image.size(fileObj.path); const imageData = await image.size(fileObj.path);
if (imageData.width < meta.config.resizeImageWidthThreshold || meta.config.resizeImageWidth > meta.config.resizeImageWidthThreshold) { if (
imageData.width < meta.config.resizeImageWidthThreshold ||
meta.config.resizeImageWidth > meta.config.resizeImageWidthThreshold
) {
return fileObj; return fileObj;
} }

@ -168,7 +168,8 @@ Topics.deleteThumb = async (req, res) => {
}; };
async function checkThumbPrivileges({ tid, uid, res }) { async function checkThumbPrivileges({ tid, uid, res }) {
// req.params.tid could be either a tid (pushing a new thumb to an existing topic) or a post UUID (a new topic being composed) // req.params.tid could be either a tid (pushing a new thumb to an existing topic)
// or a post UUID (a new topic being composed)
const isUUID = validator.isUUID(tid); const isUUID = validator.isUUID(tid);
// Sanity-check the tid if it's strictly not a uuid // Sanity-check the tid if it's strictly not a uuid

@ -95,7 +95,9 @@ module.exports = function (module) {
const batch = require('../../batch'); const batch = require('../../batch');
const batchSize = Math.ceil(key.length / Math.ceil(key.length / 100)); const batchSize = Math.ceil(key.length / Math.ceil(key.length / 100));
await batch.processArray(key, async currentBatch => batches.push(currentBatch), { batch: batchSize }); await batch.processArray(key, async currentBatch => batches.push(currentBatch), { batch: batchSize });
const batchData = await Promise.all(batches.map(batch => doQuery({ $in: batch }, { _id: 0, _key: 0 }, 0, stop + 1))); const batchData = await Promise.all(batches.map(
batch => doQuery({ $in: batch }, { _id: 0, _key: 0 }, 0, stop + 1)
));
result = dbHelpers.mergeBatch(batchData, 0, stop, sort); result = dbHelpers.mergeBatch(batchData, 0, stop, sort);
if (start > 0) { if (start > 0) {
result = result.slice(start, stop !== -1 ? stop + 1 : undefined); result = result.slice(start, stop !== -1 ? stop + 1 : undefined);

@ -65,7 +65,10 @@ module.exports = function (module) {
const bulk = module.client.collection('objects').initializeUnorderedBulkOp(); const bulk = module.client.collection('objects').initializeUnorderedBulkOp();
for (let i = 0; i < keys.length; i += 1) { for (let i = 0; i < keys.length; i += 1) {
bulk.find({ _key: keys[i], value: value }).upsert().updateOne({ $set: { score: parseFloat(isArrayOfScores ? scores[i] : scores) } }); bulk
.find({ _key: keys[i], value: value })
.upsert()
.updateOne({ $set: { score: parseFloat(isArrayOfScores ? scores[i] : scores) } });
} }
await bulk.execute(); await bulk.execute();
}; };

@ -16,9 +16,10 @@ module.exports = function (Groups) {
// Only process those groups that have the cid in its memberPostCids setting (or no setting at all) // Only process those groups that have the cid in its memberPostCids setting (or no setting at all)
const groupData = await groups.getGroupsFields(groupNames, ['memberPostCids']); const groupData = await groups.getGroupsFields(groupNames, ['memberPostCids']);
groupNames = groupNames.filter( groupNames = groupNames.filter((groupName, idx) => (
(groupName, idx) => !groupData[idx].memberPostCidsArray.length || groupData[idx].memberPostCidsArray.includes(postData.cid) !groupData[idx].memberPostCidsArray.length ||
); groupData[idx].memberPostCidsArray.includes(postData.cid)
));
const keys = groupNames.map(groupName => `group:${groupName}:member:pids`); const keys = groupNames.map(groupName => `group:${groupName}:member:pids`);
await db.sortedSetsAdd(keys, postData.timestamp, postData.pid); await db.sortedSetsAdd(keys, postData.timestamp, postData.pid);

@ -129,7 +129,13 @@ async function setupConfig() {
const redisQuestions = require('./database/redis').questions; const redisQuestions = require('./database/redis').questions;
const mongoQuestions = require('./database/mongo').questions; const mongoQuestions = require('./database/mongo').questions;
const postgresQuestions = require('./database/postgres').questions; const postgresQuestions = require('./database/postgres').questions;
const allQuestions = questions.main.concat(questions.optional).concat(redisQuestions).concat(mongoQuestions).concat(postgresQuestions); const allQuestions = [
...questions.main,
...questions.optional,
...redisQuestions,
...mongoQuestions,
...postgresQuestions,
];
allQuestions.forEach((question) => { allQuestions.forEach((question) => {
if (install.values.hasOwnProperty(question.name)) { if (install.values.hasOwnProperty(question.name)) {
@ -307,7 +313,8 @@ async function createAdmin() {
const results = await promptGet(questions); const results = await promptGet(questions);
return await success(results); return await success(results);
} }
// If automated setup did not provide a user password, generate one, it will be shown to the user upon setup completion // If automated setup did not provide a user password, generate one,
// it will be shown to the user upon setup completion
if (!install.values.hasOwnProperty('admin:password') && !nconf.get('admin:password')) { if (!install.values.hasOwnProperty('admin:password') && !nconf.get('admin:password')) {
console.log('Password was not provided during automated setup, generating one...'); console.log('Password was not provided during automated setup, generating one...');
password = utils.generateUUID().slice(0, 8); password = utils.generateUUID().slice(0, 8);

@ -20,7 +20,9 @@ module.exports = function (Messaging) {
const keys = mids.map(mid => `message:${mid}`); const keys = mids.map(mid => `message:${mid}`);
const messages = await (fields.length ? db.getObjectsFields(keys, fields) : db.getObjects(keys)); const messages = await (fields.length ? db.getObjectsFields(keys, fields) : db.getObjects(keys));
return await Promise.all(messages.map(async (message, idx) => modifyMessage(message, fields, parseInt(mids[idx], 10)))); return await Promise.all(messages.map(
async (message, idx) => modifyMessage(message, fields, parseInt(mids[idx], 10))
));
}; };
Messaging.getMessageField = async (mid, field) => { Messaging.getMessageField = async (mid, field) => {

@ -41,7 +41,10 @@ module.exports = function (middleware) {
middleware.exposePrivilegeSet = async (req, res, next) => { middleware.exposePrivilegeSet = async (req, res, next) => {
// Exposes a user's global/admin privilege set // Exposes a user's global/admin privilege set
res.locals.privileges = { ...await privileges.global.get(req.user.uid), ...await privileges.admin.get(req.user.uid) }; res.locals.privileges = {
...await privileges.global.get(req.user.uid),
...await privileges.admin.get(req.user.uid),
};
return next(); return next();
}; };
}; };

@ -118,7 +118,11 @@ Notifications.create = async function (data) {
} }
data.importance = data.importance || 5; data.importance = data.importance || 5;
const oldNotif = await db.getObject(`notifications:${data.nid}`); const oldNotif = await db.getObject(`notifications:${data.nid}`);
if (oldNotif && parseInt(oldNotif.pid, 10) === parseInt(data.pid, 10) && parseInt(oldNotif.importance, 10) > parseInt(data.importance, 10)) { if (
oldNotif &&
parseInt(oldNotif.pid, 10) === parseInt(data.pid, 10) &&
parseInt(oldNotif.importance, 10) > parseInt(data.importance, 10)
) {
return null; return null;
} }
const now = Date.now(); const now = Date.now();

@ -94,7 +94,9 @@ module.exports = function (Posts) {
absolute = `//${current[1]}`; absolute = `//${current[1]}`;
} }
content = content.slice(0, current.index + regex.length) + absolute + content.slice(current.index + regex.length + current[1].length); content = content.slice(0, current.index + regex.length) +
absolute +
content.slice(current.index + regex.length + current[1].length);
} }
} catch (err) { } catch (err) {
winston.verbose(err.messsage); winston.verbose(err.messsage);
@ -117,7 +119,10 @@ module.exports = function (Posts) {
Posts.configureSanitize = async () => { Posts.configureSanitize = async () => {
// Each allowed tags should have some common global attributes... // Each allowed tags should have some common global attributes...
sanitizeConfig.allowedTags.forEach((tag) => { sanitizeConfig.allowedTags.forEach((tag) => {
sanitizeConfig.allowedAttributes[tag] = _.union(sanitizeConfig.allowedAttributes[tag], sanitizeConfig.globalAttributes); sanitizeConfig.allowedAttributes[tag] = _.union(
sanitizeConfig.allowedAttributes[tag],
sanitizeConfig.globalAttributes
);
}); });
// Some plugins might need to adjust or whitelist their own tags... // Some plugins might need to adjust or whitelist their own tags...

@ -39,7 +39,8 @@ module.exports = function (Posts) {
const cidToCategory = toObject('cid', topicsAndCategories.categories); const cidToCategory = toObject('cid', topicsAndCategories.categories);
posts.forEach((post) => { posts.forEach((post) => {
// If the post author isn't represented in the retrieved users' data, then it means they were deleted, assume guest. // If the post author isn't represented in the retrieved users' data,
// then it means they were deleted, assume guest.
if (!uidToUser.hasOwnProperty(post.uid)) { if (!uidToUser.hasOwnProperty(post.uid)) {
post.uid = 0; post.uid = 0;
} }

@ -94,8 +94,11 @@ module.exports = function (privileges) {
const cidsSet = new Set(allowedCids); const cidsSet = new Set(allowedCids);
const canViewDeleted = _.zipObject(cids, results.view_deleted); const canViewDeleted = _.zipObject(cids, results.view_deleted);
pids = postData.filter(post => post.topic && cidsSet.has(post.topic.cid) && pids = postData.filter(post => (
((!post.topic.deleted && !post.deleted) || canViewDeleted[post.topic.cid] || results.isAdmin)).map(post => post.pid); post.topic &&
cidsSet.has(post.topic.cid) &&
((!post.topic.deleted && !post.deleted) || canViewDeleted[post.topic.cid] || results.isAdmin)
)).map(post => post.pid);
const data = await plugins.hooks.fire('filter:privileges.posts.filter', { const data = await plugins.hooks.fire('filter:privileges.posts.filter', {
privilege: privilege, privilege: privilege,
@ -121,10 +124,19 @@ module.exports = function (privileges) {
return { flag: true }; return { flag: true };
} }
if (!results.isMod && meta.config.postEditDuration && (Date.now() - results.postData.timestamp > meta.config.postEditDuration * 1000)) { if (
!results.isMod &&
meta.config.postEditDuration &&
(Date.now() - results.postData.timestamp > meta.config.postEditDuration * 1000)
) {
return { flag: false, message: `[[error:post-edit-duration-expired, ${meta.config.postEditDuration}]]` }; return { flag: false, message: `[[error:post-edit-duration-expired, ${meta.config.postEditDuration}]]` };
} }
if (!results.isMod && meta.config.newbiePostEditDuration > 0 && meta.config.newbiePostDelayThreshold > results.userData.reputation && Date.now() - results.postData.timestamp > meta.config.newbiePostEditDuration * 1000) { if (
!results.isMod &&
meta.config.newbiePostEditDuration > 0 &&
meta.config.newbiePostDelayThreshold > results.userData.reputation &&
Date.now() - results.postData.timestamp > meta.config.newbiePostEditDuration * 1000
) {
return { flag: false, message: `[[error:post-edit-duration-expired, ${meta.config.newbiePostEditDuration}]]` }; return { flag: false, message: `[[error:post-edit-duration-expired, ${meta.config.newbiePostEditDuration}]]` };
} }

@ -71,12 +71,18 @@ module.exports = function (privileges) {
const cids = _.uniq(topicsData.map(topic => topic.cid)); const cids = _.uniq(topicsData.map(topic => topic.cid));
const results = await privileges.categories.getBase(privilege, cids, uid); const results = await privileges.categories.getBase(privilege, cids, uid);
const allowedCids = cids.filter((cid, index) => !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin)); const allowedCids = cids.filter((cid, index) => (
!results.categories[index].disabled &&
(results.allowedTo[index] || results.isAdmin)
));
const cidsSet = new Set(allowedCids); const cidsSet = new Set(allowedCids);
const canViewDeleted = _.zipObject(cids, results.view_deleted); const canViewDeleted = _.zipObject(cids, results.view_deleted);
tids = topicsData.filter(t => cidsSet.has(t.cid) && (!t.deleted || canViewDeleted[t.cid] || results.isAdmin)).map(t => t.tid); tids = topicsData.filter(t => (
cidsSet.has(t.cid) &&
(!t.deleted || canViewDeleted[t.cid] || results.isAdmin)
)).map(t => t.tid);
const data = await plugins.hooks.fire('filter:privileges.topics.filter', { const data = await plugins.hooks.fire('filter:privileges.topics.filter', {
privilege: privilege, privilege: privilege,

@ -97,7 +97,9 @@ async function generateForTopic(req, res) {
const replies = topicData.posts.slice(1); const replies = topicData.posts.slice(1);
replies.forEach((postData) => { replies.forEach((postData) => {
if (!postData.deleted) { if (!postData.deleted) {
const dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString(); const dateStamp = new Date(
parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)
).toUTCString();
feed.item({ feed.item({
title: `Reply to ${utils.stripHTMLTags(topicData.title, utils.tags)} on ${dateStamp}`, title: `Reply to ${utils.stripHTMLTags(topicData.title, utils.tags)} on ${dateStamp}`,

@ -11,7 +11,14 @@ helpers.setupPageRoute = function (router, name, middleware, middlewares, contro
middleware.pluginHooks, middleware.pluginHooks,
].concat(middlewares); ].concat(middlewares);
router.get(name, middleware.busyCheck, middleware.applyCSRF, middleware.buildHeader, middlewares, helpers.tryRoute(controller)); router.get(
name,
middleware.busyCheck,
middleware.applyCSRF,
middleware.buildHeader,
middlewares,
helpers.tryRoute(controller)
);
router.get(`/api${name}`, middlewares, helpers.tryRoute(controller)); router.get(`/api${name}`, middlewares, helpers.tryRoute(controller));
}; };

@ -10,8 +10,16 @@ const { setupApiRoute } = routeHelpers;
module.exports = function () { module.exports = function () {
const middlewares = [middleware.authenticate]; const middlewares = [middleware.authenticate];
// setupApiRoute(router, 'put', '/', [...middlewares, middleware.checkRequired.bind(null, ['path']), middleware.assert.folder], controllers.write.files.upload); // setupApiRoute(router, 'put', '/', [
setupApiRoute(router, 'delete', '/', [...middlewares, middleware.checkRequired.bind(null, ['path']), middleware.assert.path], controllers.write.files.delete); // ...middlewares,
// middleware.checkRequired.bind(null, ['path']),
// middleware.assert.folder
// ], controllers.write.files.upload);
setupApiRoute(router, 'delete', '/', [
...middlewares,
middleware.checkRequired.bind(null, ['path']),
middleware.assert.path,
], controllers.write.files.delete);
return router; return router;
}; };

@ -42,7 +42,9 @@ SocketAdmin.before = async function (socket, method) {
// Check admin privileges mapping (if not in mapping, deny access) // Check admin privileges mapping (if not in mapping, deny access)
const privilegeSet = privileges.admin.socketMap.hasOwnProperty(method) ? privileges.admin.socketMap[method].split(';') : []; const privilegeSet = privileges.admin.socketMap.hasOwnProperty(method) ? privileges.admin.socketMap[method].split(';') : [];
const hasPrivilege = (await Promise.all(privilegeSet.map(async privilege => privileges.admin.can(privilege, socket.uid)))).some(Boolean); const hasPrivilege = (await Promise.all(privilegeSet.map(
async privilege => privileges.admin.can(privilege, socket.uid)
))).some(Boolean);
if (privilegeSet.length && hasPrivilege) { if (privilegeSet.length && hasPrivilege) {
return; return;
} }

@ -41,7 +41,8 @@ Analytics.get = function (socket, data, callback) {
}, },
}, (err, data) => { }, (err, data) => {
data.pastDay = data.pageviews.reduce((a, b) => parseInt(a, 10) + parseInt(b, 10)); data.pastDay = data.pageviews.reduce((a, b) => parseInt(a, 10) + parseInt(b, 10));
data.pageviews[data.pageviews.length - 1] = parseInt(data.pageviews[data.pageviews.length - 1], 10) + analytics.getUnwrittenPageviews(); const last = data.pageviews.length - 1;
data.pageviews[last] = parseInt(data.pageviews[last], 10) + analytics.getUnwrittenPageviews();
callback(err, data); callback(err, data);
}); });
} }

@ -185,7 +185,9 @@ async function checkMaintenance(socket) {
throw new Error(`[[pages:maintenance.text, ${validator.escape(String(meta.config.title || 'NodeBB'))}]]`); throw new Error(`[[pages:maintenance.text, ${validator.escape(String(meta.config.title || 'NodeBB'))}]]`);
} }
const getSessionAsync = util.promisify((sid, callback) => db.sessionStore.get(sid, (err, sessionObj) => callback(err, sessionObj || null))); const getSessionAsync = util.promisify(
(sid, callback) => db.sessionStore.get(sid, (err, sessionObj) => callback(err, sessionObj || null))
);
async function validateSession(socket) { async function validateSession(socket) {
const req = socket.request; const req = socket.request;

@ -26,7 +26,10 @@ module.exports = function (SocketTopics) {
const reverse = data.topicPostSort === 'newest_to_oldest' || data.topicPostSort === 'most_votes'; const reverse = data.topicPostSort === 'newest_to_oldest' || data.topicPostSort === 'most_votes';
let start = Math.max(0, parseInt(data.after, 10)); let start = Math.max(0, parseInt(data.after, 10));
const infScrollPostsPerPage = Math.max(0, Math.min(meta.config.postsPerPage || 20, parseInt(data.count, 10) || meta.config.postsPerPage || 20)); const infScrollPostsPerPage = Math.max(0, Math.min(
meta.config.postsPerPage || 20,
parseInt(data.count, 10) || meta.config.postsPerPage || 20
));
if (data.direction === -1) { if (data.direction === -1) {
start -= (infScrollPostsPerPage + 1); start -= (infScrollPostsPerPage + 1);
@ -96,7 +99,10 @@ module.exports = function (SocketTopics) {
}; };
function calculateStartStop(data) { function calculateStartStop(data) {
const itemsPerPage = Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20); const itemsPerPage = Math.min(
meta.config.topicsPerPage || 20,
parseInt(data.count, 10) || meta.config.topicsPerPage || 20
);
let start = Math.max(0, parseInt(data.after, 10)); let start = Math.max(0, parseInt(data.after, 10));
if (data.direction === -1) { if (data.direction === -1) {
start -= itemsPerPage; start -= itemsPerPage;

@ -12,7 +12,8 @@ const Events = module.exports;
* You are able to define additional topic event types here. * You are able to define additional topic event types here.
* Register to hook `filter:topicEvents.init` and append your custom type to the `types` object. * Register to hook `filter:topicEvents.init` and append your custom type to the `types` object.
* You can then log a custom topic event by calling `topics.events.log(tid, { type, uid });` * You can then log a custom topic event by calling `topics.events.log(tid, { type, uid });`
* `uid` is optional; if you pass in a valid uid in the payload, the user avatar/username will be rendered as part of the event text * `uid` is optional; if you pass in a valid uid in the payload,
* the user avatar/username will be rendered as part of the event text
* *
*/ */
Events._types = { Events._types = {

@ -151,7 +151,12 @@ module.exports = function (Topics) {
topicData = filtered; topicData = filtered;
const cids = params.cids && params.cids.map(String); const cids = params.cids && params.cids.map(String);
tids = topicData.filter(t => t && t.cid && !isCidIgnored[t.cid] && (!cids || cids.includes(String(t.cid)))).map(t => t.tid); tids = topicData.filter(t => (
t &&
t.cid &&
!isCidIgnored[t.cid] &&
(!cids || cids.includes(String(t.cid)))
)).map(t => t.tid);
const result = await plugins.hooks.fire('filter:topics.filterSortedTids', { tids: tids, params: params }); const result = await plugins.hooks.fire('filter:topics.filterSortedTids', { tids: tids, params: params });
return result.tids; return result.tids;

@ -56,7 +56,8 @@ module.exports = function (Topics) {
users[user.uid] = user; users[user.uid] = user;
}); });
postData.forEach((post) => { postData.forEach((post) => {
// If the post author isn't represented in the retrieved users' data, then it means they were deleted, assume guest. // If the post author isn't represented in the retrieved users' data,
// then it means they were deleted, assume guest.
if (!users.hasOwnProperty(post.uid)) { if (!users.hasOwnProperty(post.uid)) {
post.uid = 0; post.uid = 0;
} }

@ -47,7 +47,12 @@ module.exports = {
// has no history, but is banned, create plain object with just uid and timestmap // has no history, but is banned, create plain object with just uid and timestmap
if (!results.bans.length && parseInt(results.userData.banned, 10)) { if (!results.bans.length && parseInt(results.userData.banned, 10)) {
const banTimestamp = results.userData.lastonline || results.userData.lastposttime || results.userData.joindate || Date.now(); const banTimestamp = (
results.userData.lastonline ||
results.userData.lastposttime ||
results.userData.joindate ||
Date.now()
);
const banKey = `uid:${uid}:ban:${banTimestamp}`; const banKey = `uid:${uid}:ban:${banTimestamp}`;
addBan(banKey, { uid: uid, timestamp: banTimestamp }, next); addBan(banKey, { uid: uid, timestamp: banTimestamp }, next);
return; return;

@ -62,8 +62,12 @@ module.exports = function (User) {
]); ]);
}; };
const getSessionFromStore = util.promisify((sid, callback) => db.sessionStore.get(sid, (err, sessObj) => callback(err, sessObj || null))); const getSessionFromStore = util.promisify(
const sessionStoreDestroy = util.promisify((sid, callback) => db.sessionStore.destroy(sid, err => callback(err))); (sid, callback) => db.sessionStore.get(sid, (err, sessObj) => callback(err, sessObj || null))
);
const sessionStoreDestroy = util.promisify(
(sid, callback) => db.sessionStore.destroy(sid, err => callback(err))
);
User.auth.getSessions = async function (uid, curSessionId) { User.auth.getSessions = async function (uid, curSessionId) {
await cleanExpiredSessions(uid); await cleanExpiredSessions(uid);

@ -33,7 +33,19 @@ process.on('message', async (msg) => {
const profilePath = path.join(__dirname, '../../../build/export', profileFile); const profilePath = path.join(__dirname, '../../../build/export', profileFile);
const user = require('../index'); const user = require('../index');
const [userData, userSettings, ips, sessions, usernames, emails, bookmarks, watchedTopics, upvoted, downvoted, following] = await Promise.all([ const [
userData,
userSettings,
ips,
sessions,
usernames,
emails,
bookmarks,
watchedTopics,
upvoted,
downvoted,
following,
] = await Promise.all([
db.getObject(`user:${targetUid}`), db.getObject(`user:${targetUid}`),
db.getObject(`user:${targetUid}:settings`), db.getObject(`user:${targetUid}:settings`),
user.getIPs(targetUid, 9), user.getIPs(targetUid, 9),

@ -41,7 +41,11 @@ module.exports = function (User) {
const lasttime = userData[field] || 0; const lasttime = userData[field] || 0;
if (meta.config.newbiePostDelay > 0 && meta.config.newbiePostDelayThreshold > userData.reputation && now - lasttime < meta.config.newbiePostDelay * 1000) { if (
meta.config.newbiePostDelay > 0 &&
meta.config.newbiePostDelayThreshold > userData.reputation &&
now - lasttime < meta.config.newbiePostDelay * 1000
) {
throw new Error(`[[error:too-many-posts-newbie, ${meta.config.newbiePostDelay}, ${meta.config.newbiePostDelayThreshold}]]`); throw new Error(`[[error:too-many-posts-newbie, ${meta.config.newbiePostDelay}, ${meta.config.newbiePostDelayThreshold}]]`);
} else if (now - lasttime < meta.config.postDelay * 1000) { } else if (now - lasttime < meta.config.postDelay * 1000) {
throw new Error(`[[error:too-many-posts, ${meta.config.postDelay}]]`); throw new Error(`[[error:too-many-posts, ${meta.config.postDelay}]]`);

@ -47,16 +47,16 @@ module.exports = function (User) {
settings.openOutgoingLinksInNewTab = parseInt(getSetting(settings, 'openOutgoingLinksInNewTab', 0), 10) === 1; settings.openOutgoingLinksInNewTab = parseInt(getSetting(settings, 'openOutgoingLinksInNewTab', 0), 10) === 1;
settings.dailyDigestFreq = getSetting(settings, 'dailyDigestFreq', 'off'); settings.dailyDigestFreq = getSetting(settings, 'dailyDigestFreq', 'off');
settings.usePagination = parseInt(getSetting(settings, 'usePagination', 0), 10) === 1; settings.usePagination = parseInt(getSetting(settings, 'usePagination', 0), 10) === 1;
settings.topicsPerPage = settings.topicsPerPage = Math.min(
Math.min( meta.config.maxTopicsPerPage,
meta.config.maxTopicsPerPage, settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : defaultTopicsPerPage,
Math.min(settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : defaultTopicsPerPage, defaultTopicsPerPage) defaultTopicsPerPage
); );
settings.postsPerPage = settings.postsPerPage = Math.min(
Math.min( meta.config.maxPostsPerPage,
meta.config.maxPostsPerPage, settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : defaultPostsPerPage,
Math.min(settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : defaultPostsPerPage, defaultPostsPerPage) defaultPostsPerPage
); );
settings.userLang = settings.userLang || meta.config.defaultLang || 'en-GB'; settings.userLang = settings.userLang || meta.config.defaultLang || 'en-GB';
settings.acpLang = settings.acpLang || settings.userLang; settings.acpLang = settings.acpLang || settings.userLang;
settings.topicPostSort = getSetting(settings, 'topicPostSort', 'oldest_to_newest'); settings.topicPostSort = getSetting(settings, 'topicPostSort', 'oldest_to_newest');
@ -91,12 +91,20 @@ module.exports = function (User) {
User.saveSettings = async function (uid, data) { User.saveSettings = async function (uid, data) {
const maxPostsPerPage = meta.config.maxPostsPerPage || 20; const maxPostsPerPage = meta.config.maxPostsPerPage || 20;
if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > maxPostsPerPage) { if (
!data.postsPerPage ||
parseInt(data.postsPerPage, 10) <= 1 ||
parseInt(data.postsPerPage, 10) > maxPostsPerPage
) {
throw new Error(`[[error:invalid-pagination-value, 2, ${maxPostsPerPage}]]`); throw new Error(`[[error:invalid-pagination-value, 2, ${maxPostsPerPage}]]`);
} }
const maxTopicsPerPage = meta.config.maxTopicsPerPage || 20; const maxTopicsPerPage = meta.config.maxTopicsPerPage || 20;
if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > maxTopicsPerPage) { if (
!data.topicsPerPage ||
parseInt(data.topicsPerPage, 10) <= 1 ||
parseInt(data.topicsPerPage, 10) > maxTopicsPerPage
) {
throw new Error(`[[error:invalid-pagination-value, 2, ${maxTopicsPerPage}]]`); throw new Error(`[[error:invalid-pagination-value, 2, ${maxTopicsPerPage}]]`);
} }

@ -286,7 +286,8 @@ describe('API', async () => {
generateTests(writeApi, Object.keys(writeApi.paths), writeApi.servers[0].url); generateTests(writeApi, Object.keys(writeApi.paths), writeApi.servers[0].url);
function generateTests(api, paths, prefix) { function generateTests(api, paths, prefix) {
// Iterate through all documented paths, make a call to it, and compare the result body with what is defined in the spec // Iterate through all documented paths, make a call to it,
// and compare the result body with what is defined in the spec
const pathLib = path; // for calling path module from inside this forEach const pathLib = path; // for calling path module from inside this forEach
paths.forEach((path) => { paths.forEach((path) => {
const context = api.paths[path]; const context = api.paths[path];

@ -545,7 +545,11 @@ describe('Categories', () => {
}, },
function (category, next) { function (category, next) {
child1Cid = category.cid; child1Cid = category.cid;
socketCategories.copySettingsFrom({ uid: adminUid }, { fromCid: parentCid, toCid: child1Cid, copyParent: true }, next); socketCategories.copySettingsFrom(
{ uid: adminUid },
{ fromCid: parentCid, toCid: child1Cid, copyParent: true },
next
);
}, },
function (destinationCategory, next) { function (destinationCategory, next) {
Categories.getCategoryField(child1Cid, 'description', next); Categories.getCategoryField(child1Cid, 'description', next);

@ -224,7 +224,10 @@ describe('Messaging Library', () => {
it('should send not a user-leave system message when a user tries to leave a room they are not in', async () => { it('should send not a user-leave system message when a user tries to leave a room they are not in', async () => {
await socketModules.chats.leave({ uid: bazUid }, roomId); await socketModules.chats.leave({ uid: bazUid }, roomId);
const messages = await socketModules.chats.getMessages({ uid: fooUid }, { uid: fooUid, roomId: roomId, start: 0 }); const messages = await socketModules.chats.getMessages(
{ uid: fooUid },
{ uid: fooUid, roomId: roomId, start: 0 }
);
assert.equal(messages.length, 4); assert.equal(messages.length, 4);
const message = messages.pop(); const message = messages.pop();
assert.strictEqual(message.system, true); assert.strictEqual(message.system, true);

@ -446,7 +446,10 @@ describe('Post\'s', () => {
it('should purge posts and purge topic', (done) => { it('should purge posts and purge topic', (done) => {
createTopicWithReply((topicPostData, replyData) => { createTopicWithReply((topicPostData, replyData) => {
socketPosts.purgePosts({ uid: voterUid }, { pids: [replyData.pid, topicPostData.postData.pid], tid: topicPostData.topicData.tid }, (err) => { socketPosts.purgePosts({ uid: voterUid }, {
pids: [replyData.pid, topicPostData.postData.pid],
tid: topicPostData.topicData.tid,
}, (err) => {
assert.ifError(err); assert.ifError(err);
posts.exists(`post:${replyData.pid}`, (err, exists) => { posts.exists(`post:${replyData.pid}`, (err, exists) => {
assert.ifError(err); assert.ifError(err);

@ -58,7 +58,12 @@ describe('Topic\'s', () => {
}); });
it('should create a new topic with proper parameters', (done) => { it('should create a new topic with proper parameters', (done) => {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
assert.ifError(err); assert.ifError(err);
assert(result); assert(result);
topic.tid = result.topicData.tid; topic.tid = result.topicData.tid;
@ -170,7 +175,12 @@ describe('Topic\'s', () => {
let newPost; let newPost;
before((done) => { before((done) => {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
if (err) { if (err) {
return done(err); return done(err);
} }
@ -265,7 +275,12 @@ describe('Topic\'s', () => {
let newPost; let newPost;
before((done) => { before((done) => {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
if (err) { if (err) {
return done(err); return done(err);
} }
@ -471,7 +486,12 @@ describe('Topic\'s', () => {
before((done) => { before((done) => {
async.waterfall([ async.waterfall([
function (next) { function (next) {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
assert.ifError(err); assert.ifError(err);
newTopic = result.topicData; newTopic = result.topicData;
next(); next();
@ -985,7 +1005,12 @@ describe('Topic\'s', () => {
groups.join('administrators', topic.userId, next); groups.join('administrators', topic.userId, next);
}, },
function (next) { function (next) {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
assert.ifError(err); assert.ifError(err);
newTopic = result.topicData; newTopic = result.topicData;
next(); next();
@ -1276,7 +1301,12 @@ describe('Topic\'s', () => {
const socketTopics = require('../src/socket.io/topics'); const socketTopics = require('../src/socket.io/topics');
let tid; let tid;
before((done) => { before((done) => {
topics.post({ uid: topic.userId, title: topic.title, content: topic.content, cid: topic.categoryId }, (err, result) => { topics.post({
uid: topic.userId,
title: topic.title,
content: topic.content,
cid: topic.categoryId,
}, (err, result) => {
assert.ifError(err); assert.ifError(err);
tid = result.topicData.tid; tid = result.topicData.tid;
done(); done();

@ -196,36 +196,51 @@ describe('Upload Controllers', () => {
}); });
// it('should fail if topic thumbs are disabled', function (done) { // it('should fail if topic thumbs are disabled', function (done) {
// helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) { // helpers.uploadFile(
// assert.ifError(err); // nconf.get('url') + '/api/topic/thumb/upload',
// assert.strictEqual(res.statusCode, 404); // path.join(__dirname, '../test/files/test.png'),
// console.log(body); // {}, jar, csrf_token,
// assert(body && body.status && body.status.code); // function (err, res, body) {
// assert.strictEqual(body.status.code, '[[error:topic-thumbnails-are-disabled]]'); // assert.ifError(err);
// done(); // assert.strictEqual(res.statusCode, 404);
// }); // console.log(body);
// assert(body && body.status && body.status.code);
// assert.strictEqual(body.status.code, '[[error:topic-thumbnails-are-disabled]]');
// done();
// }
// );
// }); // });
// it('should fail if file is not image', function (done) { // it('should fail if file is not image', function (done) {
// meta.config.allowTopicsThumbnail = 1; // meta.config.allowTopicsThumbnail = 1;
// helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/503.html'), {}, jar, csrf_token, function (err, res, body) { // helpers.uploadFile(
// assert.ifError(err); // nconf.get('url') + '/api/topic/thumb/upload',
// assert.equal(res.statusCode, 500); // path.join(__dirname, '../test/files/503.html'),
// assert.equal(body.error, '[[error:invalid-file]]'); // {}, jar, csrf_token,
// done(); // function (err, res, body) {
// }); // assert.ifError(err);
// assert.equal(res.statusCode, 500);
// assert.equal(body.error, '[[error:invalid-file]]');
// done();
// }
// );
// }); // });
// it('should upload topic thumb', function (done) { // it('should upload topic thumb', function (done) {
// meta.config.allowTopicsThumbnail = 1; // meta.config.allowTopicsThumbnail = 1;
// helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) { // helpers.uploadFile(
// assert.ifError(err); // nconf.get('url') + '/api/topic/thumb/upload',
// assert.equal(res.statusCode, 200); // path.join(__dirname, '../test/files/test.png'),
// assert(Array.isArray(body)); // {}, jar, csrf_token,
// assert(body[0].path); // function (err, res, body) {
// assert(body[0].url); // assert.ifError(err);
// done(); // assert.equal(res.statusCode, 200);
// }); // assert(Array.isArray(body));
// assert(body[0].path);
// assert(body[0].url);
// done();
// }
// );
// }); // });
it('should not allow non image uploads', (done) => { it('should not allow non image uploads', (done) => {

Loading…
Cancel
Save