mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-04 11:31:23 +01:00
238 lines
7.3 KiB
JavaScript
238 lines
7.3 KiB
JavaScript
'use strict';
|
|
|
|
const _ = require('lodash');
|
|
const nconf = require('nconf');
|
|
const db = require('../../database');
|
|
const user = require('../../user');
|
|
const categories = require('../../categories');
|
|
const analytics = require('../../analytics');
|
|
const plugins = require('../../plugins');
|
|
const translator = require('../../translator');
|
|
const meta = require('../../meta');
|
|
const activitypub = require('../../activitypub');
|
|
const helpers = require('../helpers');
|
|
const pagination = require('../../pagination');
|
|
const utils = require('../../utils');
|
|
const cache = require('../../cache');
|
|
|
|
const categoriesController = module.exports;
|
|
|
|
categoriesController.get = async function (req, res, next) {
|
|
const [categoryData, parent, selectedData] = await Promise.all([
|
|
categories.getCategories([req.params.category_id]),
|
|
categories.getParents([req.params.category_id]),
|
|
helpers.getSelectedCategory(req.params.category_id),
|
|
]);
|
|
|
|
const category = categoryData[0];
|
|
if (!category) {
|
|
return next();
|
|
}
|
|
|
|
category.parent = parent[0];
|
|
|
|
const data = await plugins.hooks.fire('filter:admin.category.get', {
|
|
req: req,
|
|
res: res,
|
|
category: category,
|
|
customClasses: [],
|
|
});
|
|
data.category.name = translator.escape(String(data.category.name));
|
|
data.category.description = translator.escape(String(data.category.description));
|
|
|
|
res.render('admin/manage/category', {
|
|
category: data.category,
|
|
selectedCategory: selectedData.selectedCategory,
|
|
customClasses: data.customClasses,
|
|
postQueueEnabled: !!meta.config.postQueue,
|
|
});
|
|
};
|
|
|
|
categoriesController.getAll = async function (req, res) {
|
|
const rootCid = parseInt(req.query.cid, 10) || 0;
|
|
const rootChildren = await categories.getAllCidsFromSet(`cid:${rootCid}:children`);
|
|
async function getRootAndChildren() {
|
|
const childCids = _.flatten(await Promise.all(rootChildren.map(cid => categories.getChildrenCids(cid))));
|
|
return [rootCid].concat(rootChildren.concat(childCids));
|
|
}
|
|
|
|
// Categories list will be rendered on client side with recursion, etc.
|
|
const cids = await getRootAndChildren();
|
|
|
|
let rootParent = 0;
|
|
if (rootCid) {
|
|
rootParent = await categories.getCategoryField(rootCid, 'parentCid') || 0;
|
|
}
|
|
|
|
const fields = [
|
|
'cid', 'name', 'nickname', 'icon', 'parentCid', 'disabled', 'link',
|
|
'order', 'color', 'bgColor', 'backgroundImage', 'imageClass',
|
|
'subCategoriesPerPage', 'description', 'descriptionParsed',
|
|
];
|
|
let categoriesData = await categories.getCategoriesFields(cids, fields);
|
|
({ categories: categoriesData } = await plugins.hooks.fire('filter:admin.categories.get', { categories: categoriesData, fields: fields }));
|
|
|
|
categoriesData = categoriesData.map((category) => {
|
|
category.isLocal = utils.isNumber(category.cid);
|
|
return category;
|
|
});
|
|
|
|
let tree = categories.getTree(categoriesData, rootParent);
|
|
const cidsCount = rootCid && tree[0] ? tree[0].children.length : tree.length;
|
|
|
|
const pageCount = Math.max(1, Math.ceil(cidsCount / meta.config.categoriesPerPage));
|
|
const page = Math.min(parseInt(req.query.page, 10) || 1, pageCount);
|
|
const start = Math.max(0, (page - 1) * meta.config.categoriesPerPage);
|
|
const stop = start + meta.config.categoriesPerPage;
|
|
|
|
function trim(c) {
|
|
if (c.children) {
|
|
c.subCategoriesLeft = Math.max(0, c.children.length - c.subCategoriesPerPage);
|
|
c.hasMoreSubCategories = c.children.length > c.subCategoriesPerPage;
|
|
c.showMorePage = Math.ceil(c.subCategoriesPerPage / meta.config.categoriesPerPage);
|
|
c.children = c.children.slice(0, c.subCategoriesPerPage);
|
|
c.children.forEach(c => trim(c));
|
|
}
|
|
}
|
|
if (rootCid && tree[0] && Array.isArray(tree[0].children)) {
|
|
tree[0].children = tree[0].children.slice(start, stop);
|
|
tree[0].children.forEach(trim);
|
|
} else {
|
|
tree = tree.slice(start, stop);
|
|
tree.forEach(trim);
|
|
}
|
|
|
|
let selectedCategory;
|
|
if (rootCid) {
|
|
selectedCategory = await categories.getCategoryData(rootCid);
|
|
}
|
|
const crumbs = await buildBreadcrumbs(selectedCategory, '/admin/manage/categories');
|
|
res.render('admin/manage/categories', {
|
|
categoriesTree: tree,
|
|
selectedCategory: selectedCategory,
|
|
breadcrumbs: crumbs,
|
|
pagination: pagination.create(page, pageCount, req.query),
|
|
categoriesPerPage: meta.config.categoriesPerPage,
|
|
selectCategoryLabel: '[[admin/manage/categories:jump-to]]',
|
|
});
|
|
};
|
|
|
|
async function buildBreadcrumbs(categoryData, url) {
|
|
if (!categoryData) {
|
|
return;
|
|
}
|
|
const breadcrumbs = [
|
|
{
|
|
text: categoryData.name,
|
|
url: `${nconf.get('relative_path')}${url}?cid=${categoryData.cid}`,
|
|
cid: categoryData.cid,
|
|
},
|
|
];
|
|
const allCrumbs = await helpers.buildCategoryBreadcrumbs(categoryData.parentCid);
|
|
const crumbs = allCrumbs.filter(c => c.cid);
|
|
|
|
crumbs.forEach((c) => {
|
|
c.url = `${url}?cid=${c.cid}`;
|
|
});
|
|
crumbs.unshift({
|
|
text: '[[admin/manage/categories:top-level]]',
|
|
url: url,
|
|
});
|
|
|
|
return crumbs.concat(breadcrumbs);
|
|
}
|
|
|
|
categoriesController.buildBreadCrumbs = buildBreadcrumbs;
|
|
|
|
categoriesController.getAnalytics = async function (req, res) {
|
|
const [name, analyticsData, selectedData] = await Promise.all([
|
|
categories.getCategoryField(req.params.category_id, 'name'),
|
|
analytics.getCategoryAnalytics(req.params.category_id),
|
|
helpers.getSelectedCategory(req.params.category_id),
|
|
]);
|
|
res.render('admin/manage/category-analytics', {
|
|
name: name,
|
|
analytics: analyticsData,
|
|
selectedCategory: selectedData.selectedCategory,
|
|
});
|
|
};
|
|
|
|
categoriesController.getFederation = async function (req, res) {
|
|
const cid = req.params.category_id;
|
|
let [_following, pending, followers, name, { selectedCategory }] = await Promise.all([
|
|
db.getSortedSetMembers(`cid:${cid}:following`),
|
|
db.getSortedSetMembers(`followRequests:cid.${cid}`),
|
|
activitypub.notes.getCategoryFollowers(cid),
|
|
categories.getCategoryField(cid, 'name'),
|
|
helpers.getSelectedCategory(cid),
|
|
]);
|
|
|
|
const following = [..._following, ...pending].map(entry => ({
|
|
id: entry,
|
|
approved: !pending.includes(entry),
|
|
}));
|
|
|
|
await activitypub.actors.assert(followers);
|
|
followers = await user.getUsersFields(followers, ['userslug', 'picture']);
|
|
|
|
res.render('admin/manage/category-federation', {
|
|
cid: cid,
|
|
enabled: meta.config.activitypubEnabled,
|
|
name,
|
|
selectedCategory,
|
|
following,
|
|
followers,
|
|
});
|
|
};
|
|
|
|
categoriesController.addRemote = async function (req, res) {
|
|
let { handle, id } = req.body;
|
|
if (handle && !id) {
|
|
({ actorUri: id } = await activitypub.helpers.query(handle));
|
|
}
|
|
|
|
if (!id) {
|
|
return res.sendStatus(404);
|
|
}
|
|
|
|
await activitypub.actors.assertGroup(id);
|
|
const exists = await categories.exists(id);
|
|
|
|
if (!exists) {
|
|
return res.sendStatus(404);
|
|
}
|
|
|
|
const score = await db.sortedSetCard('cid:0:children');
|
|
const order = score + 1; // order is 1-based lol
|
|
await Promise.all([
|
|
db.sortedSetAdd('cid:0:children', order, id),
|
|
categories.setCategoryField(id, 'order', order),
|
|
]);
|
|
cache.del('cid:0:children');
|
|
|
|
res.sendStatus(200);
|
|
};
|
|
|
|
categoriesController.renameRemote = async (req, res) => {
|
|
if (utils.isNumber(req.params.cid)) {
|
|
return helpers.formatApiResponse(400, res);
|
|
}
|
|
|
|
const { name } = req.body;
|
|
await categories.setCategoryField(req.params.cid, 'nickname', name);
|
|
|
|
res.sendStatus(200);
|
|
};
|
|
|
|
categoriesController.removeRemote = async function (req, res) {
|
|
if (utils.isNumber(req.params.cid)) {
|
|
return helpers.formatApiResponse(400, res);
|
|
}
|
|
|
|
const parentCid = await categories.getCategoryField(req.params.cid, 'parentCid');
|
|
await db.sortedSetRemove(`cid:${parentCid || 0}:children`, req.params.cid);
|
|
cache.del(`cid:${parentCid || 0}:children`);
|
|
|
|
res.sendStatus(200);
|
|
};
|