refactor: tab rules

isekai-main
Barış Soner Uşaklı 3 years ago
parent c26870d227
commit fb363957d1

@ -146,7 +146,7 @@
"@commitlint/config-angular": "14.1.0", "@commitlint/config-angular": "14.1.0",
"coveralls": "3.1.1", "coveralls": "3.1.1",
"eslint": "7.32.0", "eslint": "7.32.0",
"eslint-config-nodebb": "0.0.3", "eslint-config-nodebb": "0.1.1",
"eslint-plugin-import": "2.25.3", "eslint-plugin-import": "2.25.3",
"grunt": "1.4.1", "grunt": "1.4.1",
"grunt-contrib-watch": "1.1.0", "grunt-contrib-watch": "1.1.0",

@ -84,7 +84,7 @@ define('admin/manage/privileges', [
Privileges.exposeAssumedPrivileges(); Privileges.exposeAssumedPrivileges();
checkboxRowSelector.updateAll(); checkboxRowSelector.updateAll();
Privileges.addEvents(); // events with confirmation modals Privileges.addEvents(); // events with confirmation modals
}; };
Privileges.addEvents = function () { Privileges.addEvents = function () {

@ -145,7 +145,7 @@ define('admin/manage/users', [
const uids = getSelectedUids(); const uids = getSelectedUids();
if (!uids.length) { if (!uids.length) {
app.alertError('[[error:no-users-selected]]'); app.alertError('[[error:no-users-selected]]');
return false; // specifically to keep the menu open return false; // specifically to keep the menu open
} }
bootbox.confirm((uids.length > 1 ? '[[admin/manage/users:alerts.confirm-ban-multi]]' : '[[admin/manage/users:alerts.confirm-ban]]'), function (confirm) { bootbox.confirm((uids.length > 1 ? '[[admin/manage/users:alerts.confirm-ban-multi]]' : '[[admin/manage/users:alerts.confirm-ban]]'), function (confirm) {
@ -163,7 +163,7 @@ define('admin/manage/users', [
const uids = getSelectedUids(); const uids = getSelectedUids();
if (!uids.length) { if (!uids.length) {
app.alertError('[[error:no-users-selected]]'); app.alertError('[[error:no-users-selected]]');
return false; // specifically to keep the menu open return false; // specifically to keep the menu open
} }
Benchpress.render('admin/partials/temporary-ban', {}).then(function (html) { Benchpress.render('admin/partials/temporary-ban', {}).then(function (html) {
@ -207,7 +207,7 @@ define('admin/manage/users', [
const uids = getSelectedUids(); const uids = getSelectedUids();
if (!uids.length) { if (!uids.length) {
app.alertError('[[error:no-users-selected]]'); app.alertError('[[error:no-users-selected]]');
return false; // specifically to keep the menu open return false; // specifically to keep the menu open
} }
Promise.all(uids.map(function (uid) { Promise.all(uids.map(function (uid) {

@ -536,7 +536,7 @@ $(document).ready(function () {
} }
// eslint-disable-next-line no-script-url // eslint-disable-next-line no-script-url
if (hrefEmpty(this.href) || this.protocol === 'javascript:' || href === '#' || href === '') { if (hrefEmpty(this.href) || this.protocol === 'javascript:' || href === '#' || href === '') {
return e.preventDefault(); return e.preventDefault();
} }

@ -37,7 +37,7 @@ app.flags = {};
* e.g. New Topic/Reply, post tools * e.g. New Topic/Reply, post tools
*/ */
if (document.body) { if (document.body) {
let earlyQueue = []; // once we can ES6, use Set instead let earlyQueue = []; // once we can ES6, use Set instead
const earlyClick = function (ev) { const earlyClick = function (ev) {
let btnEl = ev.target.closest('button'); let btnEl = ev.target.closest('button');
const anchorEl = ev.target.closest('a'); const anchorEl = ev.target.closest('a');
@ -114,7 +114,7 @@ app.flags = {};
}); });
}; };
app.require = async (modules) => { // allows you to await require.js modules app.require = async (modules) => { // allows you to await require.js modules
const single = !Array.isArray(modules); const single = !Array.isArray(modules);
if (single) { if (single) {
modules = [modules]; modules = [modules];

@ -45,7 +45,7 @@ define('forum/chats/search', ['components', 'api'], function (components, api) {
function displayUser(chatsListEl, userObj) { function displayUser(chatsListEl, userObj) {
function createUserImage() { function createUserImage() {
return (userObj.picture ? return (userObj.picture ?
'<img src="' + userObj.picture + '" title="' + userObj.username + '" />' : '<img src="' + userObj.picture + '" title="' + userObj.username + '" />' :
'<div class="user-icon" style="background-color: ' + userObj['icon:bgColor'] + '">' + userObj['icon:text'] + '</div>') + '<div class="user-icon" style="background-color: ' + userObj['icon:bgColor'] + '">' + userObj['icon:text'] + '</div>') +
'<i class="fa fa-circle status ' + userObj.status + '"></i> ' + userObj.username; '<i class="fa fa-circle status ' + userObj.status + '"></i> ' + userObj.username;
} }

@ -102,7 +102,7 @@ define('forum/groups/details', [
Details.deleteGroup(); Details.deleteGroup();
break; break;
case 'join': // intentional fall-throughs! case 'join': // intentional fall-throughs!
api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(app.alertError); api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(app.alertError);
break; break;
@ -111,7 +111,7 @@ define('forum/groups/details', [
break; break;
// TODO (14/10/2020): rewrite these to use api module and merge with above 2 case blocks // TODO (14/10/2020): rewrite these to use api module and merge with above 2 case blocks
case 'accept': // intentional fall-throughs! case 'accept': // intentional fall-throughs!
case 'reject': case 'reject':
case 'issueInvite': case 'issueInvite':
case 'rescindInvite': case 'rescindInvite':

@ -5,7 +5,7 @@ define('forum/infinitescroll', ['hooks'], function (hooks) {
const scroll = {}; const scroll = {};
let callback; let callback;
let previousScrollTop = 0; let previousScrollTop = 0;
let loadingMore = false; let loadingMore = false;
let container; let container;
let scrollTimeout = 0; let scrollTimeout = 0;

@ -1,7 +1,7 @@
'use strict'; 'use strict';
define('chat', [ define('chat', [
'components', 'taskbar', 'translator', 'hooks', 'bootbox', 'components', 'taskbar', 'translator', 'hooks', 'bootbox',
], function (components, taskbar, translator, hooks, bootbox) { ], function (components, taskbar, translator, hooks, bootbox) {
const module = {}; const module = {};
let newMessage = false; let newMessage = false;

@ -285,7 +285,7 @@
case 'iPad': case 'iPad':
icons += '<i class="fa fa-fw fa-tablet"></i>'; icons += '<i class="fa fa-fw fa-tablet"></i>';
break; break;
case 'iPod': // intentional fall-through case 'iPod': // intentional fall-through
case 'iPhone': case 'iPhone':
icons += '<i class="fa fa-fw fa-mobile"></i>'; icons += '<i class="fa fa-fw fa-mobile"></i>';
break; break;

@ -6,10 +6,10 @@ define('hooks', [], () => {
temporary: new Set(), temporary: new Set(),
runOnce: new Set(), runOnce: new Set(),
deprecated: { deprecated: {
'action:script.load': 'filter:script.load', // 👋 @ 1.18.0 'action:script.load': 'filter:script.load', // 👋 @ 1.18.0
'action:category.loaded': 'action:topics.loaded', // 👋 @ 1.19.0 'action:category.loaded': 'action:topics.loaded', // 👋 @ 1.19.0
'action:category.loading': 'action:topics.loading', // 👋 @ 1.19.0 'action:category.loading': 'action:topics.loading', // 👋 @ 1.19.0
'action:composer.check': 'filter:composer.check', // 👋 @ 1.19.0 'action:composer.check': 'filter:composer.check', // 👋 @ 1.19.0
}, },
}; };

@ -142,7 +142,7 @@ define('notifications', [
Tinycon.setBubble(count > 99 ? '99+' : count); Tinycon.setBubble(count > 99 ? '99+' : count);
} }
if (navigator.setAppBadge) { // feature detection if (navigator.setAppBadge) { // feature detection
navigator.setAppBadge(count); navigator.setAppBadge(count);
} }
}; };

@ -20,7 +20,7 @@ define('scrollStop', function () {
if ( if (
(e.originalEvent.deltaY < 0 && scrollTop === 0) || // scroll up (e.originalEvent.deltaY < 0 && scrollTop === 0) || // scroll up
(e.originalEvent.deltaY > 0 && (elementHeight + scrollTop) >= scrollHeight) // scroll down (e.originalEvent.deltaY > 0 && (elementHeight + scrollTop) >= scrollHeight) // scroll down
) { ) {
return false; return false;
} }

@ -737,7 +737,7 @@
}, },
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.host === referenceLocation.host &&
// Otherwise need to check if protocol and host match // Otherwise need to check if protocol and host match

@ -94,7 +94,7 @@ postsAPI.edit = async function (caller, data) {
]); ]);
const uids = _.uniq(_.flatten(memberData).concat(String(caller.uid))); const uids = _.uniq(_.flatten(memberData).concat(String(caller.uid)));
uids.forEach(uid => websockets.in(`uid_${uid}`).emit('event:post_edited', editResult)); uids.forEach(uid => websockets.in(`uid_${uid}`).emit('event:post_edited', editResult));
return returnData; return returnData;
}; };

@ -71,7 +71,7 @@ topicsAPI.reply = async function (caller, data) {
return queueObj; return queueObj;
} }
const postData = await topics.reply(payload); // postData seems to be a subset of postObj, refactor? const postData = await topics.reply(payload); // postData seems to be a subset of postObj, refactor?
const postObj = await posts.getPostSummaryByPids([postData.pid], caller.uid, {}); const postObj = await posts.getPostSummaryByPids([postData.pid], caller.uid, {});
const result = { const result = {

@ -21,7 +21,7 @@ module.exports = function (Categories) {
data.name = String(data.name || `Category ${cid}`); data.name = String(data.name || `Category ${cid}`);
const slug = `${cid}/${slugify(data.name)}`; const slug = `${cid}/${slugify(data.name)}`;
const smallestOrder = firstChild.length ? firstChild[0].score - 1 : 1; const smallestOrder = firstChild.length ? firstChild[0].score - 1 : 1;
const order = data.order || smallestOrder; // If no order provided, place it at the top const order = data.order || smallestOrder; // If no order provided, place it at the top
const colours = Categories.assignColours(); const colours = Categories.assignColours();
let category = { let category = {

@ -392,7 +392,7 @@ Categories.buildForSelectCategories = function (categories, fields, parentCid) {
rootCategories.forEach(category => recursive(category, categoriesData, '', 0)); rootCategories.forEach(category => recursive(category, categoriesData, '', 0));
const pickFields = [ const pickFields = [
'cid', 'name', 'level', 'icon', 'parentCid', 'cid', 'name', 'level', 'icon', 'parentCid',
'color', 'bgColor', 'backgroundImage', 'imageClass', 'color', 'bgColor', 'backgroundImage', 'imageClass',
]; ];
fields = fields || []; fields = fields || [];

@ -153,7 +153,7 @@ module.exports = function (Categories) {
function getPostsRecursive(category, posts) { function getPostsRecursive(category, posts) {
if (Array.isArray(category.posts)) { if (Array.isArray(category.posts)) {
category.posts.forEach(p => posts.push(p)); category.posts.forEach(p => posts.push(p));
} }
category.children.forEach(child => getPostsRecursive(child, posts)); category.children.forEach(child => getPostsRecursive(child, posts));

@ -100,7 +100,7 @@ nconf.argv(opts).env({
prestart.setupWinston(); prestart.setupWinston();
// Alternate configuration file support // Alternate configuration file support
const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json'); const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json');
const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database')); const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));
prestart.loadConfig(configFile); prestart.loadConfig(configFile);

@ -97,7 +97,7 @@ async function checkPlugins() {
const toCheck = Object.keys(plugins); const toCheck = Object.keys(plugins);
if (!toCheck.length) { if (!toCheck.length) {
process.stdout.write(' OK'.green + ''.reset); process.stdout.write(' OK'.green + ''.reset);
return []; // no extraneous plugins installed return []; // no extraneous plugins installed
} }
const suggestedModules = await getSuggestedModules(nbbVersion, toCheck); const suggestedModules = await getSuggestedModules(nbbVersion, toCheck);
process.stdout.write(' OK'.green + ''.reset); process.stdout.write(' OK'.green + ''.reset);

@ -78,7 +78,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {})
userData.isSelf = isSelf; userData.isSelf = isSelf;
userData.isFollowing = results.isFollowing; userData.isFollowing = results.isFollowing;
userData.hasPrivateChat = results.hasPrivateChat; userData.hasPrivateChat = results.hasPrivateChat;
userData.showHidden = results.canEdit; // remove in v1.19.0 userData.showHidden = results.canEdit; // remove in v1.19.0
userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : [];
userData.disableSignatures = meta.config.disableSignatures === 1; userData.disableSignatures = meta.config.disableSignatures === 1;
userData['reputation:disabled'] = meta.config['reputation:disabled'] === 1; userData['reputation:disabled'] = meta.config['reputation:disabled'] === 1;

@ -60,17 +60,17 @@ settingsController.get = async function (req, res, next) {
userData.bootswatchSkinOptions = [ userData.bootswatchSkinOptions = [
{ name: 'Default', value: '' }, { name: 'Default', value: '' },
{ name: 'Cerulean', value: 'cerulean' }, { name: 'Cerulean', value: 'cerulean' },
{ name: 'Cosmo', value: 'cosmo' }, { name: 'Cosmo', value: 'cosmo' },
{ name: 'Cyborg', value: 'cyborg' }, { name: 'Cyborg', value: 'cyborg' },
{ name: 'Darkly', value: 'darkly' }, { name: 'Darkly', value: 'darkly' },
{ name: 'Flatly', value: 'flatly' }, { name: 'Flatly', value: 'flatly' },
{ name: 'Journal', value: 'journal' }, { name: 'Journal', value: 'journal' },
{ name: 'Lumen', value: 'lumen' }, { name: 'Lumen', value: 'lumen' },
{ name: 'Paper', value: 'paper' }, { name: 'Paper', value: 'paper' },
{ name: 'Readable', value: 'readable' }, { name: 'Readable', value: 'readable' },
{ name: 'Sandstone', value: 'sandstone' }, { name: 'Sandstone', value: 'sandstone' },
{ name: 'Simplex', value: 'simplex' }, { name: 'Simplex', value: 'simplex' },
{ name: 'Slate', value: 'slate' }, { name: 'Slate', value: 'slate' },
{ name: 'Spacelab', value: 'spacelab' }, { name: 'Spacelab', value: 'spacelab' },
{ name: 'Superhero', value: 'superhero' }, { name: 'Superhero', value: 'superhero' },
{ name: 'United', value: 'united' }, { name: 'United', value: 'united' },

@ -188,7 +188,7 @@ async function getStatsFromAnalytics(set, field) {
today: data.slice(-1)[0], today: data.slice(-1)[0],
lastweek: sum(data.slice(-14)), lastweek: sum(data.slice(-14)),
thisweek: sum(data.slice(-7)), thisweek: sum(data.slice(-7)),
lastmonth: sum(data.slice(0)), // entire set lastmonth: sum(data.slice(0)), // entire set
thismonth: sum(data.slice(-30)), thismonth: sum(data.slice(-30)),
alltime: await getGlobalField(field), alltime: await getGlobalField(field),
}; };

@ -15,8 +15,8 @@ eventsController.get = async function (req, res) {
// Limit by date // Limit by date
let from = req.query.start ? new Date(req.query.start) || undefined : undefined; let from = req.query.start ? new Date(req.query.start) || undefined : undefined;
let to = req.query.end ? new Date(req.query.end) || undefined : new Date(); let to = req.query.end ? new Date(req.query.end) || undefined : new Date();
from = from && from.setHours(0, 0, 0, 0); // setHours returns a unix timestamp (Number, not Date) from = from && from.setHours(0, 0, 0, 0); // setHours returns a unix timestamp (Number, not Date)
to = to && to.setHours(23, 59, 59, 999); // setHours returns a unix timestamp (Number, not Date) to = to && to.setHours(23, 59, 59, 999); // setHours returns a unix timestamp (Number, not Date)
const currentFilter = req.query.type || ''; const currentFilter = req.query.type || '';

@ -21,7 +21,7 @@ privilegesController.get = async function (req, res) {
name: '[[admin/manage/privileges:global]]', name: '[[admin/manage/privileges:global]]',
icon: 'fa-list', icon: 'fa-list',
}, { }, {
cid: 'admin', // what do? cid: 'admin',
name: '[[admin/manage/privileges:admin]]', name: '[[admin/manage/privileges:admin]]',
icon: 'fa-lock', icon: 'fa-lock',
}]; }];

@ -106,7 +106,7 @@ authenticationController.register = async function (req, res) {
user.isPasswordValid(userData.password); user.isPasswordValid(userData.password);
res.locals.processLogin = true; // set it to false in plugin if you wish to just register only res.locals.processLogin = true; // set it to false in plugin if you wish to just register only
await plugins.hooks.fire('filter:register.check', { req: req, res: res, userData: userData }); await plugins.hooks.fire('filter:register.check', { req: req, res: res, userData: userData });
const data = await registerAndLoginUser(req, res, userData); const data = await registerAndLoginUser(req, res, userData);
@ -151,7 +151,7 @@ authenticationController.registerComplete = async function (req, res) {
req.body.files = req.files; req.body.files = req.files;
if ( if (
(cur.callback.constructor && cur.callback.constructor.name === 'AsyncFunction') || (cur.callback.constructor && cur.callback.constructor.name === 'AsyncFunction') ||
cur.callback.length === 2 // non-async function w/o callback cur.callback.length === 2 // non-async function w/o callback
) { ) {
memo.push(cur.callback); memo.push(cur.callback);
} else { } else {
@ -187,7 +187,7 @@ authenticationController.registerComplete = async function (req, res) {
if (req.session.registration.register === true) { if (req.session.registration.register === true) {
res.locals.processLogin = true; res.locals.processLogin = true;
req.body.noscript = 'true'; // trigger full page load on error req.body.noscript = 'true'; // trigger full page load on error
const data = await registerAndLoginUser(req, res, req.session.registration); const data = await registerAndLoginUser(req, res, req.session.registration);
if (!data) { if (!data) {
@ -388,7 +388,9 @@ authenticationController.onSuccessfulLogin = async function (req, uid) {
version: req.useragent.version, version: req.useragent.version,
}); });
await Promise.all([ await Promise.all([
new Promise(resolve => req.session.save(resolve)), new Promise((resolve) => {
req.session.save(resolve);
}),
user.auth.addSession(uid, req.sessionID), user.auth.addSession(uid, req.sessionID),
user.updateLastOnlineTime(uid), user.updateLastOnlineTime(uid),
user.updateOnlineUsers(uid), user.updateOnlineUsers(uid),

@ -114,7 +114,7 @@ modsController.flags.detail = async function (req, res, next) {
results.privileges = { ...results.privileges[0], ...results.privileges[1] }; results.privileges = { ...results.privileges[0], ...results.privileges[1] };
if (!results.flagData || (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length))) { if (!results.flagData || (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length))) {
return next(); // 404 return next(); // 404
} }
if (results.flagData.type === 'user') { if (results.flagData.type === 'user') {

@ -50,7 +50,7 @@ Topics.pin = async (req, res) => {
if (req.body.expiry) { if (req.body.expiry) {
await topics.tools.setPinExpiry(req.params.tid, req.body.expiry, req.uid); await topics.tools.setPinExpiry(req.params.tid, req.body.expiry, req.uid);
} }
await api.topics.pin(req, { tids: [req.params.tid] }); await api.topics.pin(req, { tids: [req.params.tid] });
helpers.formatApiResponse(200, res); helpers.formatApiResponse(200, res);
}; };
@ -107,7 +107,7 @@ Topics.deleteTags = async (req, res) => {
}; };
Topics.getThumbs = async (req, res) => { Topics.getThumbs = async (req, res) => {
if (isFinite(req.params.tid)) { // post_uuids can be passed in occasionally, in that case no checks are necessary if (isFinite(req.params.tid)) { // post_uuids can be passed in occasionally, in that case no checks are necessary
const [exists, canRead] = await Promise.all([ const [exists, canRead] = await Promise.all([
topics.exists(req.params.tid), topics.exists(req.params.tid),
privileges.topics.can('topics:read', req.params.tid, req.uid), privileges.topics.can('topics:read', req.params.tid, req.uid),
@ -126,7 +126,7 @@ Topics.addThumb = async (req, res) => {
return; return;
} }
const files = await uploadsController.uploadThumb(req, res); // response is handled here const files = await uploadsController.uploadThumb(req, res); // response is handled here
// Add uploaded files to topic zset // Add uploaded files to topic zset
if (files && files.length) { if (files && files.length) {

@ -58,7 +58,7 @@ module.exports = function (module) {
if (params.withScores) { if (params.withScores) {
project.score = '$totalScore'; project.score = '$totalScore';
} }
pipeline.push({ $project: project }); pipeline.push({ $project: project });
let data = await module.client.collection('objects').aggregate(pipeline).toArray(); let data = await module.client.collection('objects').aggregate(pipeline).toArray();
if (!params.withScores) { if (!params.withScores) {

@ -28,7 +28,7 @@ module.exports = function (module) {
}); });
return key.map(k => res.rows.some(r => r.k === k)); return key.map(k => res.rows.some(r => r.k === k));
} }
const res = await module.pool.query({ const res = await module.pool.query({
name: 'exists', name: 'exists',
text: ` text: `
SELECT EXISTS(SELECT * SELECT EXISTS(SELECT *

@ -64,8 +64,8 @@ Flags.init = async function () {
cid: function (sets, orSets, key) { cid: function (sets, orSets, key) {
prepareSets(sets, orSets, 'flags:byCid:', key); prepareSets(sets, orSets, 'flags:byCid:', key);
}, },
page: function () { /* noop */ }, page: function () { /* noop */ },
perPage: function () { /* noop */ }, perPage: function () { /* noop */ },
quick: function (sets, orSets, key, uid) { quick: function (sets, orSets, key, uid) {
switch (key) { switch (key) {
case 'mine': case 'mine':
@ -141,7 +141,7 @@ Flags.getFlagIdsWithFilters = async function ({ filters, uid, query }) {
winston.warn(`[flags/list] No flag filter type found: ${type}`); winston.warn(`[flags/list] No flag filter type found: ${type}`);
} }
} }
sets = (sets.length || orSets.length) ? sets : ['flags:datetime']; // No filter default sets = (sets.length || orSets.length) ? sets : ['flags:datetime']; // No filter default
let flagIds = []; let flagIds = [];
if (sets.length === 1) { if (sets.length === 1) {
@ -244,7 +244,7 @@ Flags.sort = async function (flagIds, sort) {
break; break;
} }
case 'upvotes': // fall-through case 'upvotes': // fall-through
case 'downvotes': case 'downvotes':
case 'replies': { case 'replies': {
flagIds = await filterPosts(flagIds); flagIds = await filterPosts(flagIds);
@ -426,8 +426,8 @@ Flags.create = async function (type, id, uid, reason, timestamp) {
}), }),
Flags.addReport(flagId, type, id, uid, reason, timestamp), Flags.addReport(flagId, type, id, uid, reason, timestamp),
db.sortedSetAdd('flags:datetime', timestamp, flagId), // by time, the default db.sortedSetAdd('flags:datetime', timestamp, flagId), // by time, the default
db.sortedSetAdd(`flags:byType:${type}`, timestamp, flagId), // by flag type db.sortedSetAdd(`flags:byType:${type}`, timestamp, flagId), // by flag type
db.sortedSetIncrBy('flags:byTarget', 1, [type, id].join(':')), // by flag target (score is count) db.sortedSetIncrBy('flags:byTarget', 1, [type, id].join(':')), // by flag target (score is count)
analytics.increment('flags') // some fancy analytics analytics.increment('flags') // some fancy analytics
); );
@ -441,7 +441,7 @@ Flags.create = async function (type, id, uid, reason, timestamp) {
if (type === 'post') { if (type === 'post') {
batched.push( batched.push(
db.sortedSetAdd(`flags:byPid:${id}`, timestamp, flagId), // by target pid db.sortedSetAdd(`flags:byPid:${id}`, timestamp, flagId), // by target pid
posts.setPostField(id, 'flagId', flagId) posts.setPostField(id, 'flagId', flagId)
); );

@ -45,7 +45,7 @@ module.exports = function (Groups) {
groupNames = [groupNames]; groupNames = [groupNames];
} }
const sets = []; const sets = [];
groupNames.forEach(groupName => sets.push(`group:${groupName}:pending`, `group:${groupName}:invited`)); groupNames.forEach(groupName => sets.push(`group:${groupName}:pending`, `group:${groupName}:invited`));
await db.setsRemove(sets, uid); await db.setsRemove(sets, uid);
}; };

@ -42,7 +42,7 @@ module.exports = function (Groups) {
groups.sort((a, b) => b.createtime - a.createtime); groups.sort((a, b) => b.createtime - a.createtime);
break; break;
case 'alpha': // intentional fall-through case 'alpha': // intentional fall-through
default: default:
groups.sort((a, b) => (a.slug > b.slug ? 1 : -1)); groups.sort((a, b) => (a.slug > b.slug ? 1 : -1));
} }

@ -7,7 +7,7 @@ const plugins = require('../plugins');
const meta = require('../meta'); const meta = require('../meta');
module.exports = function (Messaging) { module.exports = function (Messaging) {
Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser
Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => {
let uids = await Messaging.getUidsInRoom(roomId, 0, -1); let uids = await Messaging.getUidsInRoom(roomId, 0, -1);

@ -45,8 +45,8 @@ Blacklist.get = async function () {
Blacklist.test = async function (clientIp) { Blacklist.test = async function (clientIp) {
// Some handy test addresses // Some handy test addresses
// clientIp = '2001:db8:85a3:0:0:8a2e:370:7334'; // IPv6 // clientIp = '2001:db8:85a3:0:0:8a2e:370:7334'; // IPv6
// clientIp = '127.0.15.1'; // IPv4 // clientIp = '127.0.15.1'; // IPv4
// clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail // clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail
if (!clientIp) { if (!clientIp) {
return; return;
@ -62,15 +62,15 @@ Blacklist.test = async function (clientIp) {
} }
if ( if (
!Blacklist._rules.ipv4.includes(clientIp) && // not explicitly specified in ipv4 list !Blacklist._rules.ipv4.includes(clientIp) && // not explicitly specified in ipv4 list
!Blacklist._rules.ipv6.includes(clientIp) && // not explicitly specified in ipv6 list !Blacklist._rules.ipv6.includes(clientIp) && // not explicitly specified in ipv6 list
!Blacklist._rules.cidr.some((subnet) => { !Blacklist._rules.cidr.some((subnet) => {
const cidr = ipaddr.parseCIDR(subnet); const cidr = ipaddr.parseCIDR(subnet);
if (addr.kind() !== cidr[0].kind()) { if (addr.kind() !== cidr[0].kind()) {
return false; return false;
} }
return addr.match(cidr); return addr.match(cidr);
}) // not in a blacklisted IPv4 or IPv6 cidr range }) // not in a blacklisted IPv4 or IPv6 cidr range
) { ) {
try { try {
// To return test failure, pass back an error in callback // To return test failure, pass back an error in callback

@ -37,7 +37,7 @@ Errors.log404 = function (route) {
if (!route) { if (!route) {
return; return;
} }
route = route.slice(0, 512).replace(/\/$/, ''); // remove trailing slashes route = route.slice(0, 512).replace(/\/$/, ''); // remove trailing slashes
analytics.increment('errors:404'); analytics.increment('errors:404');
counters[route] = counters[route] || 0; counters[route] = counters[route] || 0;
counters[route] += 1; counters[route] += 1;

@ -94,7 +94,7 @@ Settings.set = async function (hash, values, quiet) {
plugins.hooks.fire('action:settings.set', { plugins.hooks.fire('action:settings.set', {
plugin: hash, plugin: hash,
settings: { ...values, ...sortedListData }, // Add back sorted list data to values hash settings: { ...values, ...sortedListData }, // Add back sorted list data to values hash
}); });
pubsub.publish(`action:settings.set.${hash}`, values); pubsub.publish(`action:settings.set.${hash}`, values);

@ -73,7 +73,7 @@ module.exports = function (middleware) {
await plugins.hooks.fire('response:middleware.authenticate', { await plugins.hooks.fire('response:middleware.authenticate', {
req: req, req: req,
res: res, res: res,
next: function () {}, // no-op for backwards compatibility next: function () {}, // no-op for backwards compatibility
}); });
if (!res.headersSent) { if (!res.headersSent) {

@ -371,7 +371,7 @@ Notifications.merge = async function (notifications) {
notifications = mergeIds.reduce((notifications, mergeId) => { notifications = mergeIds.reduce((notifications, mergeId) => {
const isolated = notifications.filter(n => n && n.hasOwnProperty('mergeId') && n.mergeId.split('|')[0] === mergeId); const isolated = notifications.filter(n => n && n.hasOwnProperty('mergeId') && n.mergeId.split('|')[0] === mergeId);
if (isolated.length <= 1) { if (isolated.length <= 1) {
return notifications; // Nothing to merge return notifications; // Nothing to merge
} }
// Each isolated mergeId may have multiple differentiators, so process each separately // Each isolated mergeId may have multiple differentiators, so process each separately

@ -8,8 +8,8 @@ const utils = require('../utils');
const Hooks = module.exports; const Hooks = module.exports;
Hooks.deprecatedHooks = { Hooks.deprecatedHooks = {
'filter:email.send': 'static:email.send', // 👋 @ 1.19.0 'filter:email.send': 'static:email.send', // 👋 @ 1.19.0
'filter:router.page': 'response:router.page', // 👋 @ 2.0.0 'filter:router.page': 'response:router.page', // 👋 @ 2.0.0
}; };
Hooks.internals = { Hooks.internals = {

@ -19,7 +19,7 @@ const socketHelpers = require('../socket.io/helpers');
module.exports = function (Posts) { module.exports = function (Posts) {
Posts.getQueuedPosts = async (filter = {}, options = {}) => { Posts.getQueuedPosts = async (filter = {}, options = {}) => {
options = { metadata: true, ...options }; // defaults options = { metadata: true, ...options }; // defaults
let postData = _.cloneDeep(cache.get('post-queue')); let postData = _.cloneDeep(cache.get('post-queue'));
if (!postData) { if (!postData) {
const ids = await db.getSortedSetRange('post:queue', 0, -1); const ids = await db.getSortedSetRange('post:queue', 0, -1);

@ -206,7 +206,7 @@ module.exports = function (Posts) {
let current = voteStatus.upvoted ? 'upvote' : 'downvote'; let current = voteStatus.upvoted ? 'upvote' : 'downvote';
if (unvote) { // e.g. unvoting, removing a upvote or downvote if (unvote) { // e.g. unvoting, removing a upvote or downvote
hook = 'unvote'; hook = 'unvote';
} else { // e.g. User *has not* voted, clicks upvote or downvote } else { // e.g. User *has not* voted, clicks upvote or downvote
current = 'unvote'; current = 'unvote';
} }
// action:post.upvote // action:post.upvote

@ -137,9 +137,7 @@ Auth.reloadRoutes = async function (params) {
res.locals.strategy = strategy; res.locals.strategy = strategy;
next(); next();
})(req, res, next); })(req, res, next);
}, }, Auth.middleware.validateAuth, (req, res, next) => {
Auth.middleware.validateAuth,
(req, res, next) => {
async.waterfall([ async.waterfall([
async.apply(req.login.bind(req), res.locals.user), async.apply(req.login.bind(req), res.locals.user),
async.apply(controllers.authentication.onSuccessfulLogin, req, req.uid), async.apply(controllers.authentication.onSuccessfulLogin, req, req.uid),

@ -203,7 +203,7 @@ function addRemountableRoutes(app, router, middleware, mounts) {
const original = mount; const original = mount;
mount = mounts[original]; mount = mounts[original];
if (!mount) { // do not mount at all if (!mount) { // do not mount at all
winston.warn(`[router] Not mounting /${original}`); winston.warn(`[router] Not mounting /${original}`);
return; return;
} }

@ -11,9 +11,9 @@ module.exports = function () {
const middlewares = [middleware.ensureLoggedIn, middleware.admin.checkPrivileges]; const middlewares = [middleware.ensureLoggedIn, middleware.admin.checkPrivileges];
// setupApiRoute(router, 'put', '/', [ // setupApiRoute(router, 'put', '/', [
// ...middlewares, // ...middlewares,
// middleware.checkRequired.bind(null, ['path']), // middleware.checkRequired.bind(null, ['path']),
// middleware.assert.folder // middleware.assert.folder
// ], controllers.write.files.upload); // ], controllers.write.files.upload);
setupApiRoute(router, 'delete', '/', [ setupApiRoute(router, 'delete', '/', [
...middlewares, ...middlewares,

@ -11,7 +11,7 @@ module.exports = function () {
const middlewares = [middleware.ensureLoggedIn]; const middlewares = [middleware.ensureLoggedIn];
setupApiRoute(router, 'post', '/', [...middlewares], controllers.write.flags.create); setupApiRoute(router, 'post', '/', [...middlewares], controllers.write.flags.create);
// setupApiRoute(router, 'delete', ...); // does not exist // setupApiRoute(router, 'delete', ...); // does not exist
setupApiRoute(router, 'get', '/:flagId', [...middlewares, middleware.assert.flag], controllers.write.flags.get); setupApiRoute(router, 'get', '/:flagId', [...middlewares, middleware.assert.flag], controllers.write.flags.get);
setupApiRoute(router, 'put', '/:flagId', [...middlewares, middleware.assert.flag], controllers.write.flags.update); setupApiRoute(router, 'put', '/:flagId', [...middlewares, middleware.assert.flag], controllers.write.flags.update);

@ -30,7 +30,7 @@ module.exports = function () {
setupApiRoute(router, 'put', '/:tid/follow', [...middlewares, middleware.assert.topic], controllers.write.topics.follow); setupApiRoute(router, 'put', '/:tid/follow', [...middlewares, middleware.assert.topic], controllers.write.topics.follow);
setupApiRoute(router, 'delete', '/:tid/follow', [...middlewares, middleware.assert.topic], controllers.write.topics.unfollow); setupApiRoute(router, 'delete', '/:tid/follow', [...middlewares, middleware.assert.topic], controllers.write.topics.unfollow);
setupApiRoute(router, 'put', '/:tid/ignore', [...middlewares, middleware.assert.topic], controllers.write.topics.ignore); setupApiRoute(router, 'put', '/:tid/ignore', [...middlewares, middleware.assert.topic], controllers.write.topics.ignore);
setupApiRoute(router, 'delete', '/:tid/ignore', [...middlewares, middleware.assert.topic], controllers.write.topics.unfollow); // intentional, unignore == unfollow setupApiRoute(router, 'delete', '/:tid/ignore', [...middlewares, middleware.assert.topic], controllers.write.topics.unfollow); // intentional, unignore == unfollow
setupApiRoute(router, 'put', '/:tid/tags', [...middlewares, middleware.checkRequired.bind(null, ['tags']), middleware.assert.topic], controllers.write.topics.addTags); setupApiRoute(router, 'put', '/:tid/tags', [...middlewares, middleware.checkRequired.bind(null, ['tags']), middleware.assert.topic], controllers.write.topics.addTags);
setupApiRoute(router, 'delete', '/:tid/tags', [...middlewares, middleware.assert.topic], controllers.write.topics.deleteTags); setupApiRoute(router, 'delete', '/:tid/tags', [...middlewares, middleware.assert.topic], controllers.write.topics.deleteTags);

@ -15,7 +15,7 @@ SocketFlags.create = async function (socket, data) {
SocketFlags.update = async function (socket, data) { SocketFlags.update = async function (socket, data) {
sockets.warnDeprecated(socket, 'PUT /api/v3/flags/:flagId'); sockets.warnDeprecated(socket, 'PUT /api/v3/flags/:flagId');
if (!data || !(data.flagId && data.data)) { // check only req'd in socket.io if (!data || !(data.flagId && data.data)) { // check only req'd in socket.io
throw new Error('[[error:invalid-data]]'); throw new Error('[[error:invalid-data]]');
} }

@ -28,7 +28,7 @@ module.exports = function (SocketPosts) {
canDelete: privileges.posts.canDelete(data.pid, socket.uid), canDelete: privileges.posts.canDelete(data.pid, socket.uid),
canPurge: privileges.posts.canPurge(data.pid, socket.uid), canPurge: privileges.posts.canPurge(data.pid, socket.uid),
canFlag: privileges.posts.canFlag(data.pid, socket.uid), canFlag: privileges.posts.canFlag(data.pid, socket.uid),
flagged: flags.exists('post', data.pid, socket.uid), // specifically, whether THIS calling user flagged flagged: flags.exists('post', data.pid, socket.uid), // specifically, whether THIS calling user flagged
bookmarked: posts.hasBookmarked(data.pid, socket.uid), bookmarked: posts.hasBookmarked(data.pid, socket.uid),
postSharing: social.getActivePostSharing(), postSharing: social.getActivePostSharing(),
history: posts.diffs.exists(data.pid), history: posts.diffs.exists(data.pid),

@ -84,8 +84,8 @@ module.exports = function (Topics) {
}; };
async function getTids(params) { async function getTids(params) {
const counts = { '': 0, new: 0, watched: 0, unreplied: 0 }; const counts = { '': 0, new: 0, watched: 0, unreplied: 0 };
const tidsByFilter = { '': [], new: [], watched: [], unreplied: [] }; const tidsByFilter = { '': [], new: [], watched: [], unreplied: [] };
if (params.uid <= 0) { if (params.uid <= 0) {
return { counts: counts, tids: [], tidsByFilter: tidsByFilter }; return { counts: counts, tids: [], tidsByFilter: tidsByFilter };

@ -8,9 +8,9 @@ module.exports = {
timestamp: Date.UTC(2017, 8, 6), timestamp: Date.UTC(2017, 8, 6),
method: async function () { method: async function () {
const matches = [ const matches = [
'112e541b40023d6530dd44df4b0d9c5d', // digest @ 75917e25b3b5ad7bed8ed0c36433fb35c9ab33eb '112e541b40023d6530dd44df4b0d9c5d', // digest @ 75917e25b3b5ad7bed8ed0c36433fb35c9ab33eb
'110b8805f70395b0282fd10555059e9f', // digest @ 9b02bb8f51f0e47c6e335578f776ffc17bc03537 '110b8805f70395b0282fd10555059e9f', // digest @ 9b02bb8f51f0e47c6e335578f776ffc17bc03537
'9538e7249edb369b2a25b03f2bd3282b', // digest @ 3314ab4b83138c7ae579ac1f1f463098b8c2d414 '9538e7249edb369b2a25b03f2bd3282b', // digest @ 3314ab4b83138c7ae579ac1f1f463098b8c2d414
]; ];
const fieldset = await meta.configs.getFields(['email:custom:digest']); const fieldset = await meta.configs.getFields(['email:custom:digest']);
const hash = fieldset['email:custom:digest'] ? crypto.createHash('md5').update(fieldset['email:custom:digest']).digest('hex') : null; const hash = fieldset['email:custom:digest'] ? crypto.createHash('md5').update(fieldset['email:custom:digest']).digest('hex') : null;

@ -95,7 +95,7 @@ module.exports = function (User) {
const sid = uuidMapping[uuid]; const sid = uuidMapping[uuid];
const sessionObj = await getSessionFromStore(sid); const sessionObj = await getSessionFromStore(sid);
const expired = !sessionObj || !sessionObj.hasOwnProperty('passport') || const expired = !sessionObj || !sessionObj.hasOwnProperty('passport') ||
!sessionObj.passport.hasOwnProperty('user') || !sessionObj.passport.hasOwnProperty('user') ||
parseInt(sessionObj.passport.user, 10) !== parseInt(uid, 10); parseInt(sessionObj.passport.user, 10) !== parseInt(uid, 10);
if (expired) { if (expired) {
expiredUUIDs.push(uuid); expiredUUIDs.push(uuid);

@ -65,9 +65,9 @@ UserEmail.expireValidation = async (uid) => {
UserEmail.sendValidationEmail = async function (uid, options) { UserEmail.sendValidationEmail = async function (uid, options) {
/* /*
* Options: * Options:
* - email, overrides email retrieval * - email, overrides email retrieval
* - force, sends email even if it is too soon to send another * - force, sends email even if it is too soon to send another
*/ */
if (meta.config.sendValidationEmail !== 1) { if (meta.config.sendValidationEmail !== 1) {

@ -230,9 +230,9 @@ User.addInterstitials = function (callback) {
plugins.hooks.register('core', { plugins.hooks.register('core', {
hook: 'filter:register.interstitial', hook: 'filter:register.interstitial',
method: [ method: [
User.interstitials.email, // Email address (for password reset + digest) User.interstitials.email, // Email address (for password reset + digest)
User.interstitials.gdpr, // GDPR information collection/processing consent + email consent User.interstitials.gdpr, // GDPR information collection/processing consent + email consent
User.interstitials.tou, // Forum Terms of Use User.interstitials.tou, // Forum Terms of Use
], ],
}); });

@ -36,7 +36,7 @@ Interstitials.email = async (data) => {
uid: userData.uid, uid: userData.uid,
email: formData.email, email: formData.email,
registration: false, registration: false,
allowed: true, // change this value to disallow allowed: true, // change this value to disallow
error: '[[error:invalid-email]]', error: '[[error:invalid-email]]',
}), }),
]); ]);
@ -79,7 +79,7 @@ Interstitials.email = async (data) => {
uid: null, uid: null,
email: formData.email, email: formData.email,
registration: true, registration: true,
allowed: true, // change this value to disallow allowed: true, // change this value to disallow
error: '[[error:invalid-email]]', error: '[[error:invalid-email]]',
}); });

@ -91,7 +91,7 @@ UserReset.commit = async function (code, password) {
// don't verify email if password reset is due to expiry // don't verify email if password reset is due to expiry
const isPasswordExpired = userData.passwordExpiry && userData.passwordExpiry < Date.now(); const isPasswordExpired = userData.passwordExpiry && userData.passwordExpiry < Date.now();
if (!isPasswordExpired) { if (!isPasswordExpired) {
data['email:confirmed'] = 1; data['email:confirmed'] = 1;
await groups.join('verified-users', uid); await groups.join('verified-users', uid);
await groups.leave('unverified-users', uid); await groups.leave('unverified-users', uid);
} }

@ -168,7 +168,7 @@ function setupExpressApp(app) {
app.use((req, res, next) => { app.use((req, res, next) => {
als.run({ uid: req.uid }, next); als.run({ uid: req.uid }, next);
}); });
app.use(middleware.autoLocale); // must be added after auth middlewares are added app.use(middleware.autoLocale); // must be added after auth middlewares are added
const toobusy = require('toobusy-js'); const toobusy = require('toobusy-js');
toobusy.maxLag(meta.config.eventLoopLagThreshold); toobusy.maxLag(meta.config.eventLoopLagThreshold);

@ -33,7 +33,7 @@ describe('API', async () => {
let jar; let jar;
let csrfToken; let csrfToken;
let setup = false; let setup = false;
const unauthenticatedRoutes = ['/api/login', '/api/register']; // Everything else will be called with the admin user const unauthenticatedRoutes = ['/api/login', '/api/register']; // Everything else will be called with the admin user
const mocks = { const mocks = {
head: {}, head: {},
@ -73,19 +73,19 @@ describe('API', async () => {
{ {
in: 'path', in: 'path',
name: 'uuid', name: 'uuid',
example: '', // to be defined below... example: '', // to be defined below...
}, },
], ],
'/posts/{pid}/diffs/{timestamp}': [ '/posts/{pid}/diffs/{timestamp}': [
{ {
in: 'path', in: 'path',
name: 'pid', name: 'pid',
example: '', // to be defined below... example: '', // to be defined below...
}, },
{ {
in: 'path', in: 'path',
name: 'timestamp', name: 'timestamp',
example: '', // to be defined below... example: '', // to be defined below...
}, },
], ],
}, },
@ -116,7 +116,7 @@ describe('API', async () => {
for (let x = 0; x < 4; x++) { for (let x = 0; x < 4; x++) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await user.create({ username: 'deleteme', password: '123456' }); // for testing of DELETE /users (uids 5, 6) and DELETE /user/:uid/account (uid 7) await user.create({ username: 'deleteme', password: '123456' }); // for testing of DELETE /users (uids 5, 6) and DELETE /user/:uid/account (uid 7)
} }
await groups.join('administrators', adminUid); await groups.join('administrators', adminUid);
@ -299,7 +299,7 @@ describe('API', async () => {
function generateTests(api, paths, prefix) { function generateTests(api, paths, prefix) {
// Iterate through all documented paths, make a call to it, // Iterate through all documented paths, make a call to it,
// and compare the result body with what is defined in the spec // 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];
let schema; let schema;
@ -393,9 +393,9 @@ describe('API', async () => {
method: method, method: method,
jar: !unauthenticatedRoutes.includes(path) ? jar : undefined, jar: !unauthenticatedRoutes.includes(path) ? jar : undefined,
json: true, json: true,
followRedirect: false, // all responses are significant (e.g. 302) followRedirect: false, // all responses are significant (e.g. 302)
simple: false, // don't throw on non-200 (e.g. 302) simple: false, // don't throw on non-200 (e.g. 302)
resolveWithFullResponse: true, // send full request back (to check statusCode) resolveWithFullResponse: true, // send full request back (to check statusCode)
headers: headers, headers: headers,
qs: qs, qs: qs,
body: body, body: body,
@ -572,7 +572,7 @@ describe('API', async () => {
// Compare the response to the schema // Compare the response to the schema
Object.keys(response).forEach((prop) => { Object.keys(response).forEach((prop) => {
if (additionalProperties) { // All bets are off if (additionalProperties) { // All bets are off
return; return;
} }

@ -60,7 +60,7 @@ describe('Groups', () => {
// Also create a hidden group // Also create a hidden group
await Groups.join('Hidden', 'Test'); await Groups.join('Hidden', 'Test');
// create another group that starts with test for search/sort // create another group that starts with test for search/sort
await Groups.create({ name: 'Test2', description: 'Foobar!' }); await Groups.create({ name: 'Test2', description: 'Foobar!' });
testUid = await User.create({ testUid = await User.create({
username: 'testuser', username: 'testuser',

@ -19,7 +19,7 @@ describe('i18n', () => {
}); });
it('should contain folders named after the language code', async () => { it('should contain folders named after the language code', async () => {
const valid = /(?:README.md|^[a-z]{2}(?:-[A-Z]{2})?$|^[a-z]{2}(?:-x-[a-z]+)?$)/; // good luck const valid = /(?:README.md|^[a-z]{2}(?:-[A-Z]{2})?$|^[a-z]{2}(?:-x-[a-z]+)?$)/; // good luck
folders.forEach((folder) => { folders.forEach((folder) => {
assert(valid.test(folder)); assert(valid.test(folder));

@ -17,17 +17,17 @@ const helpers = require('./helpers');
const socketModules = require('../src/socket.io/modules'); const socketModules = require('../src/socket.io/modules');
describe('Messaging Library', () => { describe('Messaging Library', () => {
let fooUid; // the admin let fooUid; // the admin
let bazUid; // the user with chat restriction enabled let bazUid; // the user with chat restriction enabled
let herpUid; let herpUid;
let roomId; let roomId;
before((done) => { before((done) => {
// Create 3 users: 1 admin, 2 regular // Create 3 users: 1 admin, 2 regular
async.series([ async.series([
async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin
async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user
async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user
], (err, uids) => { ], (err, uids) => {
if (err) { if (err) {
return done(err); return done(err);

@ -19,9 +19,9 @@ describe('meta', () => {
Groups.cache.reset(); Groups.cache.reset();
// Create 3 users: 1 admin, 2 regular // Create 3 users: 1 admin, 2 regular
async.series([ async.series([
async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin async.apply(User.create, { username: 'foo', password: 'barbar' }), // admin
async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user async.apply(User.create, { username: 'baz', password: 'quuxquux' }), // restricted user
async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user async.apply(User.create, { username: 'herp', password: 'derpderp' }), // regular user
], (err, uids) => { ], (err, uids) => {
if (err) { if (err) {
return done(err); return done(err);

@ -1514,7 +1514,7 @@ describe('Post\'s', () => {
const events = await topics.events.get(tid1, 1); const events = await topics.events.get(tid1, 1);
assert(events); assert(events);
assert.strictEqual(events.length, 1); // should still equal 1 assert.strictEqual(events.length, 1); // should still equal 1
}); });
it('should not show backlink events if the feature is disabled', async () => { it('should not show backlink events if the feature is disabled', async () => {

@ -716,7 +716,7 @@ describe('socket.io', () => {
event: async.apply(events.getEvents, '', 0, 0), event: async.apply(events.getEvents, '', 0, 0),
}, (err, data) => { }, (err, data) => {
assert.ifError(err); assert.ifError(err);
assert.strictEqual(data.count, 1); // should still equal 1 assert.strictEqual(data.count, 1); // should still equal 1
// Event validity // Event validity
assert.strictEqual(data.event.length, 1); assert.strictEqual(data.event.length, 1);

@ -175,7 +175,7 @@ describe('Topic thumbs', () => {
const score = await db.sortedSetScore(`topic:${tid}:thumbs`, relativeThumbPaths[0]); const score = await db.sortedSetScore(`topic:${tid}:thumbs`, relativeThumbPaths[0]);
assert(isFinite(score)); // exists in set assert(isFinite(score)); // exists in set
assert.strictEqual(score, 2); assert.strictEqual(score, 2);
}); });
@ -188,7 +188,7 @@ describe('Topic thumbs', () => {
const score = await db.sortedSetScore(`topic:${tid}:thumbs`, relativeThumbPaths[0]); const score = await db.sortedSetScore(`topic:${tid}:thumbs`, relativeThumbPaths[0]);
assert(isFinite(score)); // exists in set assert(isFinite(score)); // exists in set
assert.strictEqual(score, 0); assert.strictEqual(score, 0);
}); });

@ -243,54 +243,6 @@ describe('Upload Controllers', () => {
}); });
}); });
// 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) {
// assert.ifError(err);
// 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) {
// 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) {
// assert.ifError(err);
// assert.equal(res.statusCode, 500);
// assert.equal(body.error, '[[error:invalid-file]]');
// done();
// }
// );
// });
// it('should upload topic thumb', function (done) {
// 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) {
// assert.ifError(err);
// 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) => {
socketUser.updateCover({ uid: 1 }, { uid: 1, file: { path: '../../text.txt' } }, (err) => { socketUser.updateCover({ uid: 1 }, { uid: 1, file: { path: '../../text.txt' } }, (err) => {
assert.equal(err.message, '[[error:invalid-data]]'); assert.equal(err.message, '[[error:invalid-data]]');

@ -869,7 +869,7 @@ describe('User', () => {
assert.ifError(err); assert.ifError(err);
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
if (key === 'email') { if (key === 'email') {
assert.strictEqual(userData.email, 'just@for.updated'); // email remains the same until confirmed assert.strictEqual(userData.email, 'just@for.updated'); // email remains the same until confirmed
} else if (key !== 'password') { } else if (key !== 'password') {
assert.equal(data[key], userData[key]); assert.equal(data[key], userData[key]);
} else { } else {
@ -1500,9 +1500,9 @@ describe('User', () => {
function (next) { function (next) {
User.digest.getSubscribers('day', (err, subs) => { User.digest.getSubscribers('day', (err, subs) => {
assert.ifError(err); assert.ifError(err);
assert.strictEqual(subs.includes(uidIndex.daysub.toString()), true); // daysub does get emailed assert.strictEqual(subs.includes(uidIndex.daysub.toString()), true); // daysub does get emailed
assert.strictEqual(subs.includes(uidIndex.weeksub.toString()), false); // weeksub does not get emailed assert.strictEqual(subs.includes(uidIndex.weeksub.toString()), false); // weeksub does not get emailed
assert.strictEqual(subs.includes(uidIndex.offsub.toString()), false); // offsub doesn't get emailed assert.strictEqual(subs.includes(uidIndex.offsub.toString()), false); // offsub doesn't get emailed
next(); next();
}); });
@ -1516,9 +1516,9 @@ describe('User', () => {
function (next) { function (next) {
User.digest.getSubscribers('week', (err, subs) => { User.digest.getSubscribers('week', (err, subs) => {
assert.ifError(err); assert.ifError(err);
assert.strictEqual(subs.includes(uidIndex.weeksub.toString()), true); // weeksub gets emailed assert.strictEqual(subs.includes(uidIndex.weeksub.toString()), true); // weeksub gets emailed
assert.strictEqual(subs.includes(uidIndex.daysub.toString()), false); // daysub gets emailed assert.strictEqual(subs.includes(uidIndex.daysub.toString()), false); // daysub gets emailed
assert.strictEqual(subs.includes(uidIndex.offsub.toString()), false); // offsub does not get emailed assert.strictEqual(subs.includes(uidIndex.offsub.toString()), false); // offsub does not get emailed
next(); next();
}); });

@ -259,6 +259,7 @@ describe('Utility Methods', () => {
}); });
it('should return passed in value if invalid', (done) => { it('should return passed in value if invalid', (done) => {
// eslint-disable-next-line no-loss-of-precision
const bigInt = -111111111111111111; const bigInt = -111111111111111111;
const result = utils.toISOString(bigInt); const result = utils.toISOString(bigInt);
assert.equal(bigInt, result); assert.equal(bigInt, result);

Loading…
Cancel
Save