mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-04 05:39:51 +01:00
Merge branch 'develop' into bootstrap5
This commit is contained in:
116
CHANGELOG.md
116
CHANGELOG.md
@@ -1,3 +1,119 @@
|
||||
#### v2.8.5 (2023-01-27)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.4 (a46b2bbc)
|
||||
* update changelog for v2.8.4 (c13f0e21)
|
||||
* incrementing version number - v2.8.3 (c20b20a7)
|
||||
* incrementing version number - v2.8.2 (050e43f8)
|
||||
* incrementing version number - v2.8.1 (727f879e)
|
||||
* incrementing version number - v2.8.0 (8e77673d)
|
||||
* incrementing version number - v2.7.0 (96cc0617)
|
||||
* incrementing version number - v2.6.1 (7e52a7a5)
|
||||
* incrementing version number - v2.6.0 (e7fcf482)
|
||||
* incrementing version number - v2.5.8 (dec0e7de)
|
||||
* incrementing version number - v2.5.7 (5836bf4a)
|
||||
* incrementing version number - v2.5.6 (c7bd7dbf)
|
||||
* incrementing version number - v2.5.5 (3509ed94)
|
||||
* incrementing version number - v2.5.4 (e83260ca)
|
||||
* incrementing version number - v2.5.3 (7e922936)
|
||||
* incrementing version number - v2.5.2 (babcd17e)
|
||||
* incrementing version number - v2.5.1 (ce3aa950)
|
||||
* incrementing version number - v2.5.0 (01d276cb)
|
||||
* incrementing version number - v2.4.5 (dd3e1a28)
|
||||
* incrementing version number - v2.4.4 (d5525c87)
|
||||
* incrementing version number - v2.4.3 (9c647c6c)
|
||||
* incrementing version number - v2.4.2 (3aa7b855)
|
||||
* incrementing version number - v2.4.1 (60cbd148)
|
||||
* incrementing version number - v2.4.0 (4834cde3)
|
||||
* incrementing version number - v2.3.1 (d2425942)
|
||||
* incrementing version number - v2.3.0 (046ea120)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* import resolution within plugin modules (#11219) (f6c96948)
|
||||
|
||||
#### v2.8.4 (2023-01-26)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.3 (c20b20a7)
|
||||
* update changelog for v2.8.3 (eb2841ee)
|
||||
* incrementing version number - v2.8.2 (050e43f8)
|
||||
* incrementing version number - v2.8.1 (727f879e)
|
||||
* incrementing version number - v2.8.0 (8e77673d)
|
||||
* incrementing version number - v2.7.0 (96cc0617)
|
||||
* incrementing version number - v2.6.1 (7e52a7a5)
|
||||
* incrementing version number - v2.6.0 (e7fcf482)
|
||||
* incrementing version number - v2.5.8 (dec0e7de)
|
||||
* incrementing version number - v2.5.7 (5836bf4a)
|
||||
* incrementing version number - v2.5.6 (c7bd7dbf)
|
||||
* incrementing version number - v2.5.5 (3509ed94)
|
||||
* incrementing version number - v2.5.4 (e83260ca)
|
||||
* incrementing version number - v2.5.3 (7e922936)
|
||||
* incrementing version number - v2.5.2 (babcd17e)
|
||||
* incrementing version number - v2.5.1 (ce3aa950)
|
||||
* incrementing version number - v2.5.0 (01d276cb)
|
||||
* incrementing version number - v2.4.5 (dd3e1a28)
|
||||
* incrementing version number - v2.4.4 (d5525c87)
|
||||
* incrementing version number - v2.4.3 (9c647c6c)
|
||||
* incrementing version number - v2.4.2 (3aa7b855)
|
||||
* incrementing version number - v2.4.1 (60cbd148)
|
||||
* incrementing version number - v2.4.0 (4834cde3)
|
||||
* incrementing version number - v2.3.1 (d2425942)
|
||||
* incrementing version number - v2.3.0 (046ea120)
|
||||
|
||||
#### v2.8.3 (2023-01-25)
|
||||
|
||||
##### Chores
|
||||
|
||||
* remove extraneous lines from changelog (48c9f447)
|
||||
* incrementing version number - v2.8.2 (050e43f8)
|
||||
* update changelog for v2.8.2 (66aa3169)
|
||||
* incrementing version number - v2.8.1 (727f879e)
|
||||
* incrementing version number - v2.8.0 (8e77673d)
|
||||
* incrementing version number - v2.7.0 (96cc0617)
|
||||
* incrementing version number - v2.6.1 (7e52a7a5)
|
||||
* incrementing version number - v2.6.0 (e7fcf482)
|
||||
* incrementing version number - v2.5.8 (dec0e7de)
|
||||
* incrementing version number - v2.5.7 (5836bf4a)
|
||||
* incrementing version number - v2.5.6 (c7bd7dbf)
|
||||
* incrementing version number - v2.5.5 (3509ed94)
|
||||
* incrementing version number - v2.5.4 (e83260ca)
|
||||
* incrementing version number - v2.5.3 (7e922936)
|
||||
* incrementing version number - v2.5.2 (babcd17e)
|
||||
* incrementing version number - v2.5.1 (ce3aa950)
|
||||
* incrementing version number - v2.5.0 (01d276cb)
|
||||
* incrementing version number - v2.4.5 (dd3e1a28)
|
||||
* incrementing version number - v2.4.4 (d5525c87)
|
||||
* incrementing version number - v2.4.3 (9c647c6c)
|
||||
* incrementing version number - v2.4.2 (3aa7b855)
|
||||
* incrementing version number - v2.4.1 (60cbd148)
|
||||
* incrementing version number - v2.4.0 (4834cde3)
|
||||
* incrementing version number - v2.3.1 (d2425942)
|
||||
* incrementing version number - v2.3.0 (046ea120)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* import resolution within plugin modules (#11200) (89e059a0)
|
||||
* #11195, allow users with admin:users privilege to delete users in acp (0bffd3d9)
|
||||
* #11194, allow access to sub dashboard pages (7d04e952)
|
||||
* #11136, tests, and returning the proper number of arrays (459bc523)
|
||||
* #11136, only show mods of active categories when getModeratorUids is called (39e009c0)
|
||||
* closes #11173, clear require cache if wrong dependency is installed (747cb1f0)
|
||||
* **deps:**
|
||||
* downgrade swagger-parser to v9 (00e48803)
|
||||
* pinning sub dependency json-schema-ref-parser to 9.0.9 (9c250b78)
|
||||
|
||||
##### Reverts
|
||||
|
||||
* a788bd1344825ad4759e39d6e98d8bf3695bd639 (fecd84d1)
|
||||
* 9c250b78b05ca2abf31a79971ed0c60ca07664ec, fix: comment out broken test for now (a788bd13)
|
||||
|
||||
##### Tests
|
||||
|
||||
* fix broken test (f295174e)
|
||||
|
||||
#### v2.8.2 (2023-01-13)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"@adactive/bootstrap-tagsinput": "0.8.2",
|
||||
"@isaacs/ttlcache": "1.2.1",
|
||||
"@popperjs/core": "2.11.6",
|
||||
"ace-builds": "1.14.0",
|
||||
"ace-builds": "1.15.0",
|
||||
"archiver": "5.3.1",
|
||||
"async": "3.2.4",
|
||||
"autoprefixer": "10.4.13",
|
||||
@@ -60,7 +60,7 @@
|
||||
"csurf": "1.11.0",
|
||||
"daemon": "1.1.0",
|
||||
"diff": "5.1.0",
|
||||
"esbuild": "0.16.16",
|
||||
"esbuild": "0.17.5",
|
||||
"express": "4.18.2",
|
||||
"express-session": "1.17.3",
|
||||
"express-useragent": "1.0.15",
|
||||
@@ -84,7 +84,7 @@
|
||||
"lru-cache": "7.14.1",
|
||||
"material-design-lite": "1.3.0",
|
||||
"mime": "3.0.0",
|
||||
"mkdirp": "1.0.4",
|
||||
"mkdirp": "2.1.3",
|
||||
"mongodb": "4.13.0",
|
||||
"morgan": "1.10.0",
|
||||
"mousetrap": "1.6.5",
|
||||
@@ -99,24 +99,24 @@
|
||||
"nodebb-plugin-mentions": "4.0.3",
|
||||
"nodebb-plugin-ntfy": "1.0.15",
|
||||
"nodebb-plugin-spam-be-gone": "2.0.5",
|
||||
"nodebb-rewards-essentials": "0.2.1",
|
||||
"nodebb-rewards-essentials": "0.2.2",
|
||||
"nodebb-theme-harmony": "1.0.0-beta.56",
|
||||
"nodebb-theme-lavender": "7.0.8",
|
||||
"nodebb-theme-peace": "2.0.18",
|
||||
"nodebb-theme-persona": "13.0.49",
|
||||
"nodebb-widget-essentials": "7.0.6",
|
||||
"nodemailer": "6.8.0",
|
||||
"nodemailer": "6.9.1",
|
||||
"nprogress": "0.2.0",
|
||||
"passport": "0.6.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-local": "1.0.0",
|
||||
"pg": "8.8.0",
|
||||
"pg-cursor": "2.7.4",
|
||||
"pg": "8.9.0",
|
||||
"pg-cursor": "2.8.0",
|
||||
"postcss": "8.4.21",
|
||||
"postcss-clean": "1.2.0",
|
||||
"progress-webpack-plugin": "1.0.16",
|
||||
"prompt": "1.3.0",
|
||||
"ioredis": "5.2.4",
|
||||
"ioredis": "5.3.0",
|
||||
"request": "2.88.2",
|
||||
"request-promise-native": "1.0.9",
|
||||
"rimraf": "3.0.2",
|
||||
@@ -151,17 +151,17 @@
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apidevtools/swagger-parser": "9.0.0",
|
||||
"@commitlint/cli": "17.4.1",
|
||||
"@commitlint/config-angular": "17.4.0",
|
||||
"@apidevtools/swagger-parser": "9.0.1",
|
||||
"@commitlint/cli": "17.4.2",
|
||||
"@commitlint/config-angular": "17.4.2",
|
||||
"coveralls": "3.1.1",
|
||||
"eslint": "8.31.0",
|
||||
"eslint": "8.32.0",
|
||||
"eslint-config-nodebb": "0.2.1",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"grunt": "1.5.3",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"husky": "8.0.3",
|
||||
"jsdom": "21.0.0",
|
||||
"jsdom": "21.1.0",
|
||||
"lint-staged": "13.1.0",
|
||||
"mocha": "10.2.0",
|
||||
"mocha-lcov-reporter": "1.3.0",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"no-user": "User does not exist",
|
||||
"no-teaser": "Teaser does not exist",
|
||||
"no-flag": "Flag does not exist",
|
||||
"no-chat-room": "Chat room does not exist",
|
||||
"no-privileges": "You do not have enough privileges for this action.",
|
||||
|
||||
"category-disabled": "Category disabled",
|
||||
@@ -182,6 +183,9 @@
|
||||
"chat-deleted-already": "This chat message has already been deleted.",
|
||||
"chat-restored-already": "This chat message has already been restored.",
|
||||
"chat-room-does-not-exist": "Chat room does not exist.",
|
||||
"cant-add-users-to-chat-room": "Can't add users to chat room.",
|
||||
"cant-remove-users-from-chat-room": "Can't remove users from chat room.",
|
||||
"chat-room-name-too-long": "Chat room name too long.",
|
||||
|
||||
"already-voting-for-this-post": "You have already voted for this post.",
|
||||
"reputation-system-disabled": "Reputation system is disabled.",
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
"category-not-selected": "Није одабрана категорија",
|
||||
"too-many-posts": "Можете објављивати поруке само једном у %1 секунди - сачекајте пре него што покушате поново",
|
||||
"too-many-posts-newbie": "Као нови корисник, можете објављивати поруке само једном у %1 секунди док не достигнете %2 углед - сачекајте пре него што покушате поново",
|
||||
"already-posting": "You are already posting",
|
||||
"already-posting": "Већ објављујете",
|
||||
"tag-too-short": "Унесите дужу ознаку. Ознаке морају садржати најмање %1 знак(ов)а.",
|
||||
"tag-too-long": "Унесите краћу ознаку. Ознаке не смеју бити дуже од %1 знак(ов)а.",
|
||||
"not-enough-tags": "Нема довољно ознака. Теме морају имати најмање %1 ознаке/а.",
|
||||
|
||||
@@ -5,7 +5,6 @@ const _ = require('lodash');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const groups = require('../groups');
|
||||
const plugins = require('../plugins');
|
||||
const privileges = require('../privileges');
|
||||
const cache = require('../cache');
|
||||
@@ -99,39 +98,7 @@ Categories.getModerators = async function (cid) {
|
||||
};
|
||||
|
||||
Categories.getModeratorUids = async function (cids) {
|
||||
// Only check active categories
|
||||
const disabled = (await Categories.getCategoriesFields(cids, ['disabled'])).map(obj => obj.disabled);
|
||||
// cids = cids.filter((_, idx) => !disabled[idx]);
|
||||
|
||||
const groupNames = cids.reduce((memo, cid) => {
|
||||
memo.push(`cid:${cid}:privileges:moderate`);
|
||||
memo.push(`cid:${cid}:privileges:groups:moderate`);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
const memberSets = await groups.getMembersOfGroups(groupNames);
|
||||
// Every other set is actually a list of user groups, not uids, so convert those to members
|
||||
const sets = memberSets.reduce((memo, set, idx) => {
|
||||
if (idx % 2) {
|
||||
memo.groupNames.push(set);
|
||||
} else {
|
||||
memo.uids.push(set);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { groupNames: [], uids: [] });
|
||||
|
||||
const uniqGroups = _.uniq(_.flatten(sets.groupNames));
|
||||
const groupUids = await groups.getMembersOfGroups(uniqGroups);
|
||||
const map = _.zipObject(uniqGroups, groupUids);
|
||||
const moderatorUids = cids.map((cid, index) => {
|
||||
if (disabled[index]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))));
|
||||
});
|
||||
return moderatorUids;
|
||||
return await privileges.categories.getUidsWithPrivilege(cids, 'moderate');
|
||||
};
|
||||
|
||||
Categories.getCategories = async function (cids, uid) {
|
||||
|
||||
@@ -45,10 +45,11 @@ notificationsController.get = async function (req, res, next) {
|
||||
{ separator: true },
|
||||
]).concat(filters.moderatorFilters);
|
||||
}
|
||||
const selectedFilter = allFilters.find((filterData) => {
|
||||
|
||||
allFilters.forEach((filterData) => {
|
||||
filterData.selected = filterData.filter === filter;
|
||||
return filterData.selected;
|
||||
});
|
||||
const selectedFilter = allFilters.find(filterData => filterData.selected);
|
||||
if (!selectedFilter) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ authenticationController.doLogin = async function (req, uid) {
|
||||
return;
|
||||
}
|
||||
const loginAsync = util.promisify(req.login).bind(req);
|
||||
await loginAsync({ uid: uid }, { keepSessionInfo: req.res.locals !== false });
|
||||
await loginAsync({ uid: uid }, { keepSessionInfo: req.res.locals.reroll !== false });
|
||||
await authenticationController.onSuccessfulLogin(req, uid);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
const user = require('../user');
|
||||
const groups = require('../groups');
|
||||
const posts = require('../posts');
|
||||
const flags = require('../flags');
|
||||
const analytics = require('../analytics');
|
||||
@@ -110,7 +113,6 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
isAdminOrGlobalMod: user.isAdminOrGlobalMod(req.uid),
|
||||
moderatedCids: user.getModeratedCids(req.uid),
|
||||
flagData: flags.get(req.params.flagId),
|
||||
assignees: user.getAdminsandGlobalModsandModerators(),
|
||||
privileges: Promise.all(['global', 'admin'].map(async type => privileges[type].get(req.uid))),
|
||||
});
|
||||
results.privileges = { ...results.privileges[0], ...results.privileges[1] };
|
||||
@@ -119,6 +121,28 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
return next(); // 404
|
||||
}
|
||||
|
||||
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);
|
||||
if (!cid) {
|
||||
return [];
|
||||
}
|
||||
uids = (await privileges.categories.getUidsWithPrivilege([cid], 'moderate'))[0];
|
||||
uids = _.uniq(admins.concat(globalMods).concat(uids));
|
||||
}
|
||||
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;
|
||||
|
||||
if (results.flagData.type === 'user') {
|
||||
@@ -128,7 +152,7 @@ modsController.flags.detail = async function (req, res, next) {
|
||||
}
|
||||
|
||||
res.render('flags/detail', Object.assign(results.flagData, {
|
||||
assignees: results.assignees,
|
||||
assignees: assignees,
|
||||
type_bool: ['post', 'user', 'empty'].reduce((memo, cur) => {
|
||||
if (cur !== 'empty') {
|
||||
memo[cur] = results.flagData.type === cur && (
|
||||
|
||||
@@ -40,14 +40,24 @@ async function linkModules() {
|
||||
await Promise.all(Object.keys(modules).map(async (relPath) => {
|
||||
const srcPath = path.join(__dirname, '../../', modules[relPath]);
|
||||
const destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
|
||||
const destDir = path.dirname(destPath);
|
||||
|
||||
const [stats] = await Promise.all([
|
||||
fs.promises.stat(srcPath),
|
||||
mkdirp(path.dirname(destPath)),
|
||||
mkdirp(destDir),
|
||||
]);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await file.linkDirs(srcPath, destPath, true);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
// Get the relative path to the destination directory
|
||||
const relPath = path.relative(destDir, srcPath)
|
||||
// and convert to a posix path
|
||||
.split(path.sep).join(path.posix.sep);
|
||||
|
||||
// Instead of copying file, create a new file re-exporting it
|
||||
// This way, imports in modules are resolved correctly
|
||||
await fs.promises.writeFile(destPath, `module.exports = require('${relPath}');`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ module.exports = function (middleware) {
|
||||
const loginAsync = util.promisify(req.login).bind(req);
|
||||
await loginAsync(user, { keepSessionInfo: true });
|
||||
await controllers.authentication.onSuccessfulLogin(req, user.uid);
|
||||
req.uid = user.uid;
|
||||
req.uid = parseInt(user.uid, 10);
|
||||
req.loggedIn = req.uid > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,3 +211,8 @@ privsAdmin.groupPrivileges = async function (groupName) {
|
||||
const groupPrivilegeList = await privsAdmin.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(0, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsAdmin.getUidsWithPrivilege = async function (privilege) {
|
||||
const uidsByCid = await helpers.getUidsWithPrivilege([0], privilege);
|
||||
return uidsByCid[0];
|
||||
};
|
||||
|
||||
@@ -224,3 +224,7 @@ privsCategories.groupPrivileges = async function (cid, groupName) {
|
||||
const groupPrivilegeList = await privsCategories.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(cid, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsCategories.getUidsWithPrivilege = async function (cids, privilege) {
|
||||
return await helpers.getUidsWithPrivilege(cids, privilege);
|
||||
};
|
||||
|
||||
@@ -134,3 +134,8 @@ privsGlobal.groupPrivileges = async function (groupName) {
|
||||
const groupPrivilegeList = await privsGlobal.getGroupPrivilegeList();
|
||||
return await helpers.userOrGroupPrivileges(0, groupName, groupPrivilegeList);
|
||||
};
|
||||
|
||||
privsGlobal.getUidsWithPrivilege = async function (privilege) {
|
||||
const uidsByCid = await helpers.getUidsWithPrivilege([0], privilege);
|
||||
return uidsByCid[0];
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ const validator = require('validator');
|
||||
|
||||
const groups = require('../groups');
|
||||
const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const plugins = require('../plugins');
|
||||
const translator = require('../translator');
|
||||
|
||||
@@ -189,4 +190,38 @@ helpers.userOrGroupPrivileges = async function (cid, uidOrGroup, privilegeList)
|
||||
return _.zipObject(privilegeList, isMembers);
|
||||
};
|
||||
|
||||
helpers.getUidsWithPrivilege = async (cids, privilege) => {
|
||||
const disabled = (await categories.getCategoriesFields(cids, ['disabled'])).map(obj => obj.disabled);
|
||||
|
||||
const groupNames = cids.reduce((memo, cid) => {
|
||||
memo.push(`cid:${cid}:privileges:${privilege}`);
|
||||
memo.push(`cid:${cid}:privileges:groups:${privilege}`);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
const memberSets = await groups.getMembersOfGroups(groupNames);
|
||||
// Every other set is actually a list of user groups, not uids, so convert those to members
|
||||
const sets = memberSets.reduce((memo, set, idx) => {
|
||||
if (idx % 2) {
|
||||
memo.groupNames.push(set);
|
||||
} else {
|
||||
memo.uids.push(set);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { groupNames: [], uids: [] });
|
||||
|
||||
const uniqGroups = _.uniq(_.flatten(sets.groupNames));
|
||||
const groupUids = await groups.getMembersOfGroups(uniqGroups);
|
||||
const map = _.zipObject(uniqGroups, groupUids);
|
||||
const uidsByCid = cids.map((cid, index) => {
|
||||
if (disabled[index]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))));
|
||||
});
|
||||
return uidsByCid;
|
||||
};
|
||||
|
||||
require('../promisify')(helpers);
|
||||
|
||||
@@ -87,14 +87,15 @@ function unpin(tid, topicData) {
|
||||
}
|
||||
|
||||
async function sendNotifications(uids, topicsData) {
|
||||
const usernames = await Promise.all(uids.map(uid => user.getUserField(uid, 'username')));
|
||||
const uidToUsername = Object.fromEntries(uids.map((uid, idx) => [uid, usernames[idx]]));
|
||||
const userData = await user.getUsersData(uids);
|
||||
const uidToUserData = Object.fromEntries(uids.map((uid, idx) => [uid, userData[idx]]));
|
||||
|
||||
const postsData = await posts.getPostsData(topicsData.map(({ mainPid }) => mainPid));
|
||||
const postsData = await posts.getPostsData(topicsData.map(t => t && t.mainPid));
|
||||
postsData.forEach((postData, idx) => {
|
||||
postData.user = {};
|
||||
postData.user.username = uidToUsername[postData.uid];
|
||||
postData.topic = topicsData[idx];
|
||||
if (postData) {
|
||||
postData.user = uidToUserData[topicsData[idx].uid];
|
||||
postData.topic = topicsData[idx];
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(topicsData.map(
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{{{ end }}}
|
||||
{{{ each topics }}}
|
||||
<tr>
|
||||
<td><a href="{config.relative_path}/topics/{../slug}">{../title}</a></td>
|
||||
<td><a href="{config.relative_path}/topic/{../slug}">{../title}</a></td>
|
||||
<td>[[topic:posted_by, {../user.username}]]</td>
|
||||
<td><span class="timeago" data-title="{../timestampISO}"></span></td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user