Files
NodeBB/src/controllers/mods.js

225 lines
7.4 KiB
JavaScript
Raw Normal View History

2017-02-18 01:56:23 -07:00
'use strict';
2016-10-13 13:12:38 -04:00
const _ = require('lodash');
2019-08-21 23:02:50 -04:00
const user = require('../user');
const groups = require('../groups');
const posts = require('../posts');
2019-08-21 23:02:50 -04:00
const flags = require('../flags');
const analytics = require('../analytics');
const plugins = require('../plugins');
const pagination = require('../pagination');
const privileges = require('../privileges');
2019-08-21 23:02:50 -04:00
const utils = require('../utils');
const helpers = require('./helpers');
2019-08-21 23:02:50 -04:00
const modsController = module.exports;
2017-05-09 14:31:32 -04:00
modsController.flags = {};
2016-10-13 13:12:38 -04:00
2021-07-21 17:08:51 -04:00
modsController.flags.list = async function (req, res) {
2020-08-18 21:03:59 -04:00
const validFilters = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick', 'page', 'perPage'];
const validSorts = ['newest', 'oldest', 'reports', 'upvotes', 'downvotes', 'replies'];
2018-03-09 12:57:52 -05:00
2020-08-18 21:03:59 -04:00
const results = await Promise.all([
2019-08-21 23:02:50 -04:00
user.isAdminOrGlobalMod(req.uid),
user.getModeratedCids(req.uid),
plugins.hooks.fire('filter:flags.validateFilters', { filters: validFilters }),
plugins.hooks.fire('filter:flags.validateSort', { sorts: validSorts }),
2019-08-21 23:02:50 -04:00
]);
2020-08-18 21:03:59 -04:00
const [isAdminOrGlobalMod, moderatedCids,, { sorts }] = results;
let [,, { filters }] = results;
2019-08-21 23:02:50 -04:00
if (!(isAdminOrGlobalMod || !!moderatedCids.length)) {
return helpers.notAllowed(req, res);
2019-08-21 23:02:50 -04:00
}
2019-08-21 23:02:50 -04:00
if (!isAdminOrGlobalMod && moderatedCids.length) {
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
res.locals.cids = moderatedCids.map(cid => String(cid));
2019-08-21 23:02:50 -04:00
}
2017-07-11 15:53:30 -04:00
2020-08-18 21:03:59 -04:00
// Parse query string params for filters, eliminate non-valid filters
2021-02-04 00:01:39 -07:00
filters = filters.reduce((memo, cur) => {
if (req.query.hasOwnProperty(cur)) {
if (typeof req.query[cur] === 'string' && req.query[cur].trim() !== '') {
memo[cur] = req.query[cur].trim();
} else if (Array.isArray(req.query[cur]) && req.query[cur].length) {
memo[cur] = req.query[cur];
}
2019-08-21 23:02:50 -04:00
}
2017-05-09 14:31:32 -04:00
2019-08-21 23:02:50 -04:00
return memo;
}, {});
2017-05-09 14:31:32 -04:00
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
let hasFilter = !!Object.keys(filters).length;
2019-08-21 23:02:50 -04:00
if (res.locals.cids) {
if (!filters.cid) {
// If mod and no cid filter, add filter for their modded categories
filters.cid = res.locals.cids;
} else if (Array.isArray(filters.cid)) {
// Remove cids they do not moderate
filters.cid = filters.cid.filter(cid => res.locals.cids.includes(String(cid)));
} else if (!res.locals.cids.includes(String(filters.cid))) {
filters.cid = res.locals.cids;
hasFilter = false;
}
}
2019-08-21 23:02:50 -04:00
// Pagination doesn't count as a filter
2020-08-18 21:03:59 -04:00
if (
(Object.keys(filters).length === 1 && filters.hasOwnProperty('page')) ||
(Object.keys(filters).length === 2 && filters.hasOwnProperty('page') && filters.hasOwnProperty('perPage'))
) {
2019-08-21 23:02:50 -04:00
hasFilter = false;
}
2018-03-09 12:57:52 -05:00
2020-08-18 21:03:59 -04:00
// Parse sort from query string
let sort;
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
if (req.query.sort) {
2020-08-18 21:03:59 -04:00
sort = sorts.includes(req.query.sort) ? req.query.sort : null;
}
if (sort === 'newest') {
sort = undefined;
}
2020-08-18 21:03:59 -04:00
hasFilter = hasFilter || !!sort;
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
const [flagsData, analyticsData, selectData] = await Promise.all([
2020-08-18 21:03:59 -04:00
flags.list({
filters: filters,
sort: sort,
uid: req.uid,
query: req.query,
2020-08-18 21:03:59 -04:00
}),
2019-08-21 23:02:50 -04:00
analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30),
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
helpers.getSelectedCategory(filters.cid),
2019-08-21 23:02:50 -04:00
]);
res.render('flags/list', {
flags: flagsData.flags,
analytics: analyticsData,
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
selectedCategory: selectData.selectedCategory,
2019-08-21 23:02:50 -04:00
hasFilter: hasFilter,
filters: filters,
expanded: !!(filters.assignee || filters.reporterId || filters.targetUid),
2020-08-18 21:03:59 -04:00
sort: sort || 'newest',
2019-08-21 23:02:50 -04:00
title: '[[pages:flags]]',
pagination: pagination.create(flagsData.page, flagsData.pageCount, req.query),
breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:flags]]' }]),
2019-08-21 23:02:50 -04:00
});
2016-10-13 13:12:38 -04:00
};
2019-08-21 23:02:50 -04:00
modsController.flags.detail = async function (req, res, next) {
const results = await utils.promiseParallel({
isAdminOrGlobalMod: user.isAdminOrGlobalMod(req.uid),
moderatedCids: user.getModeratedCids(req.uid),
flagData: flags.get(req.params.flagId),
privileges: Promise.all(['global', 'admin'].map(async type => privileges[type].get(req.uid))),
2019-08-21 23:02:50 -04:00
});
results.privileges = { ...results.privileges[0], ...results.privileges[1] };
if (!results.flagData || (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length))) {
2021-11-18 16:42:18 -05:00
return next(); // 404
2019-08-21 23:02:50 -04:00
}
2018-05-30 13:01:35 -04:00
async function getAssignees(flagData) {
let uids = [];
const [admins, globalMods] = await Promise.all([
groups.getMembers('administrators', 0, -1),
groups.getMembers('Global Moderators', 0, -1),
]);
if (flagData.type === 'user') {
uids = await privileges.admin.getUidsWithPrivilege('admin:users');
uids = _.uniq(admins.concat(uids));
} else if (flagData.type === 'post') {
const cid = await posts.getCidByPid(flagData.targetId);
uids = _.uniq(admins.concat(globalMods));
if (cid) {
const modUids = (await privileges.categories.getUidsWithPrivilege([cid], 'moderate'))[0];
uids = _.uniq(uids.concat(modUids));
}
}
const userData = await user.getUsersData(uids);
return userData.filter(u => u && u.userslug);
}
const assignees = await getAssignees(results.flagData);
results.flagData.history = results.isAdminOrGlobalMod ? (await flags.getHistory(req.params.flagId)) : null;
2019-08-21 23:02:50 -04:00
if (results.flagData.type === 'user') {
results.flagData.type_path = 'uid';
} else if (results.flagData.type === 'post') {
results.flagData.type_path = 'post';
}
res.render('flags/detail', Object.assign(results.flagData, {
assignees: assignees,
2021-02-04 00:01:39 -07:00
type_bool: ['post', 'user', 'empty'].reduce((memo, cur) => {
2019-08-21 23:02:50 -04:00
if (cur !== 'empty') {
2021-02-04 02:07:29 -07:00
memo[cur] = results.flagData.type === cur && (
!results.flagData.target ||
!!Object.keys(results.flagData.target).length
);
2019-08-21 23:02:50 -04:00
} else {
memo[cur] = !Object.keys(results.flagData.target).length;
}
return memo;
}, {}),
states: Object.fromEntries(flags._states),
2021-02-03 23:59:08 -07:00
title: `[[pages:flag-details, ${req.params.flagId}]]`,
privileges: results.privileges,
breadcrumbs: helpers.buildBreadcrumbs([
{ text: '[[pages:flags]]', url: '/flags' },
2021-02-03 23:59:08 -07:00
{ text: `[[pages:flag-details, ${req.params.flagId}]]` },
]),
2019-08-21 23:02:50 -04:00
}));
};
2017-10-31 16:04:25 -04:00
2019-08-21 23:02:50 -04:00
modsController.postQueue = async function (req, res, next) {
if (!req.loggedIn) {
2019-08-21 23:02:50 -04:00
return next();
}
const { id } = req.params;
2021-02-06 14:10:15 -07:00
const { cid } = req.query;
const page = parseInt(req.query.page, 10) || 1;
const postsPerPage = 20;
let postData = await posts.getQueuedPosts({ id: id });
const [isAdmin, isGlobalMod, moderatedCids, categoriesData] = await Promise.all([
user.isAdministrator(req.uid),
user.isGlobalModerator(req.uid),
user.getModeratedCids(req.uid),
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
2021-02-07 15:09:52 -05:00
helpers.getSelectedCategory(cid),
]);
2020-10-04 22:11:41 -04:00
postData = postData.filter(p => p &&
(!categoriesData.selectedCids.length || categoriesData.selectedCids.includes(p.category.cid)) &&
(isAdmin || isGlobalMod || moderatedCids.includes(Number(p.category.cid)) || req.uid === p.user.uid));
({ posts: postData } = await plugins.hooks.fire('filter:post-queue.get', {
2020-08-28 11:50:13 -04:00
posts: postData,
req: req,
}));
const pageCount = Math.max(1, Math.ceil(postData.length / postsPerPage));
const start = (page - 1) * postsPerPage;
const stop = start + postsPerPage - 1;
postData = postData.slice(start, stop + 1);
const crumbs = [{ text: '[[pages:post-queue]]', url: id ? '/post-queue' : undefined }];
if (id && postData.length) {
const text = postData[0].data.tid ? '[[post-queue:reply]]' : '[[post-queue:topic]]';
crumbs.push({ text: text });
}
res.render('post-queue', {
title: '[[pages:post-queue]]',
posts: postData,
isAdmin: isAdmin,
canAccept: isAdmin || isGlobalMod || !!moderatedCids.length,
...categoriesData,
2021-02-03 23:59:08 -07:00
allCategoriesUrl: `post-queue${helpers.buildQueryString(req.query, 'cid', '')}`,
pagination: pagination.create(page, pageCount),
breadcrumbs: helpers.buildBreadcrumbs(crumbs),
singlePost: !!id,
});
2017-10-31 16:04:25 -04:00
};