Merge branch 'master' into develop

isekai-main
Julian Lam 2 years ago
commit 97d8b53fd3

@ -3,6 +3,7 @@
[![Workflow](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml/badge.svg)](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml) [![Workflow](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml/badge.svg)](https://github.com/NodeBB/NodeBB/actions/workflows/test.yaml)
[![Coverage Status](https://coveralls.io/repos/github/NodeBB/NodeBB/badge.svg?branch=master)](https://coveralls.io/github/NodeBB/NodeBB?branch=master) [![Coverage Status](https://coveralls.io/repos/github/NodeBB/NodeBB/badge.svg?branch=master)](https://coveralls.io/github/NodeBB/NodeBB?branch=master)
[![Code Climate](https://codeclimate.com/github/NodeBB/NodeBB/badges/gpa.svg)](https://codeclimate.com/github/NodeBB/NodeBB) [![Code Climate](https://codeclimate.com/github/NodeBB/NodeBB/badges/gpa.svg)](https://codeclimate.com/github/NodeBB/NodeBB)
[![](https://dcbadge.vercel.app/api/server/p6YKPXu7er?style=flat)](https://discord.gg/p6YKPXu7er)
[**NodeBB Forum Software**](https://nodebb.org) is powered by Node.js and supports either Redis, MongoDB, or a PostgreSQL database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB takes the best of the modern web: real-time streaming discussions, mobile responsiveness, and rich RESTful read/write APIs, while staying true to the original bulletin board/forum format → categorical hierarchies, local user accounts, and asynchronous messaging. [**NodeBB Forum Software**](https://nodebb.org) is powered by Node.js and supports either Redis, MongoDB, or a PostgreSQL database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB takes the best of the modern web: real-time streaming discussions, mobile responsiveness, and rich RESTful read/write APIs, while staying true to the original bulletin board/forum format → categorical hierarchies, local user accounts, and asynchronous messaging.

@ -99,9 +99,9 @@
"nodebb-plugin-spam-be-gone": "1.0.2", "nodebb-plugin-spam-be-gone": "1.0.2",
"nodebb-rewards-essentials": "0.2.1", "nodebb-rewards-essentials": "0.2.1",
"nodebb-theme-lavender": "6.0.0", "nodebb-theme-lavender": "6.0.0",
"nodebb-theme-persona": "12.1.9", "nodebb-theme-persona": "12.1.10",
"nodebb-theme-slick": "2.0.2", "nodebb-theme-slick": "2.0.2",
"nodebb-theme-vanilla": "12.1.18", "nodebb-theme-vanilla": "12.1.19",
"nodebb-widget-essentials": "6.0.0", "nodebb-widget-essentials": "6.0.0",
"nodemailer": "6.8.0", "nodemailer": "6.8.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",

@ -2,7 +2,6 @@
define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, bootbox, alerts) { define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, bootbox, alerts) {
const MemberList = {}; const MemberList = {};
let searchInterval;
let groupName; let groupName;
let templateName; let templateName;
@ -89,25 +88,22 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b
} }
function handleMemberSearch() { function handleMemberSearch() {
$('[component="groups/members/search"]').on('keyup', function () { const searchEl = $('[component="groups/members/search"]');
const query = $(this).val(); searchEl.on('keyup', utils.debounce(function () {
if (searchInterval) { const query = searchEl.val();
clearInterval(searchInterval); socket.emit('groups.searchMembers', {
searchInterval = 0; groupName: groupName,
} query: query,
}, function (err, results) {
searchInterval = setTimeout(function () { if (err) {
socket.emit('groups.searchMembers', { groupName: groupName, query: query }, function (err, results) { return alerts.error(err);
if (err) { }
return alerts.error(err); parseAndTranslate(results.users, function (html) {
} $('[component="groups/members"] tbody').html(html);
parseAndTranslate(results.users, function (html) { $('[component="groups/members"]').attr('data-nextstart', 20);
$('[component="groups/members"] tbody').html(html);
$('[component="groups/members"]').attr('data-nextstart', 20);
});
}); });
}, 250); });
}); }, 250));
} }
function handleMemberInfiniteScroll() { function handleMemberInfiniteScroll() {

@ -29,11 +29,15 @@ searchController.search = async function (req, res, next) {
'search:tags': privileges.global.can('search:tags', req.uid), 'search:tags': privileges.global.can('search:tags', req.uid),
}); });
req.query.in = req.query.in || meta.config.searchDefaultIn || 'titlesposts'; req.query.in = req.query.in || meta.config.searchDefaultIn || 'titlesposts';
const allowed = (req.query.in === 'users' && userPrivileges['search:users']) || let allowed = (req.query.in === 'users' && userPrivileges['search:users']) ||
(req.query.in === 'tags' && userPrivileges['search:tags']) || (req.query.in === 'tags' && userPrivileges['search:tags']) ||
(req.query.in === 'categories') || (req.query.in === 'categories') ||
(['titles', 'titlesposts', 'posts'].includes(req.query.in) && userPrivileges['search:content']); (['titles', 'titlesposts', 'posts'].includes(req.query.in) && userPrivileges['search:content']);
({ allowed } = await plugins.hooks.fire('filter:search.isAllowed', {
uid: req.uid,
query: req.query,
allowed,
}));
if (!allowed) { if (!allowed) {
return helpers.notAllowed(req, res); return helpers.notAllowed(req, res);
} }

@ -171,7 +171,7 @@ Auth.reloadRoutes = async function (params) {
router.post('/register', middlewares, controllers.authentication.register); router.post('/register', middlewares, controllers.authentication.register);
router.post('/register/complete', middlewares, controllers.authentication.registerComplete); router.post('/register/complete', middlewares, controllers.authentication.registerComplete);
router.post('/register/abort', controllers.authentication.registerAbort); router.post('/register/abort', Auth.middleware.applyCSRF, controllers.authentication.registerAbort);
router.post('/login', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.login); router.post('/login', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.login);
router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout); router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout);
}; };

@ -15,7 +15,6 @@ const search = module.exports;
search.search = async function (data) { search.search = async function (data) {
const start = process.hrtime(); const start = process.hrtime();
data.searchIn = data.searchIn || 'titlesposts';
data.sortBy = data.sortBy || 'relevance'; data.sortBy = data.sortBy || 'relevance';
let result; let result;
@ -27,6 +26,10 @@ search.search = async function (data) {
result = await categories.search(data); result = await categories.search(data);
} else if (data.searchIn === 'tags') { } else if (data.searchIn === 'tags') {
result = await topics.searchAndLoadTags(data); result = await topics.searchAndLoadTags(data);
} else if (data.searchIn) {
result = await plugins.hooks.fire('filter:search.searchIn', {
data,
});
} else { } else {
throw new Error('[[error:unknown-search-filter]]'); throw new Error('[[error:unknown-search-filter]]');
} }
@ -108,6 +111,7 @@ async function searchInContent(data) {
returnData.posts = await posts.getPostSummaryByPids(metadata.pids, data.uid, {}); returnData.posts = await posts.getPostSummaryByPids(metadata.pids, data.uid, {});
await plugins.hooks.fire('filter:search.contentGetResult', { result: returnData, data: data }); await plugins.hooks.fire('filter:search.contentGetResult', { result: returnData, data: data });
delete metadata.pids; delete metadata.pids;
delete metadata.data;
return Object.assign(returnData, metadata); return Object.assign(returnData, metadata);
} }

@ -4,9 +4,7 @@ module.exports = {
name: 'Navigation item visibility groups', name: 'Navigation item visibility groups',
timestamp: Date.UTC(2018, 10, 10), timestamp: Date.UTC(2018, 10, 10),
method: async function () { method: async function () {
const navigationAdmin = require('../../navigation/admin'); const data = await navigationAdminGet();
const data = await navigationAdmin.get();
data.forEach((navItem) => { data.forEach((navItem) => {
if (navItem && navItem.properties) { if (navItem && navItem.properties) {
navItem.groups = []; navItem.groups = [];
@ -23,6 +21,38 @@ module.exports = {
} }
} }
}); });
await navigationAdmin.save(data); await navigationAdminSave(data);
}, },
}; };
// use navigation.get/save as it was in 1.11.0 so upgrade script doesn't crash on latest nbb
// see https://github.com/NodeBB/NodeBB/pull/11013
async function navigationAdminGet() {
const db = require('../../database');
const data = await db.getSortedSetRange('navigation:enabled', 0, -1);
return data.filter(Boolean).map((item) => {
item = JSON.parse(item);
item.groups = item.groups || [];
if (item.groups && !Array.isArray(item.groups)) {
item.groups = [item.groups];
}
return item;
});
}
async function navigationAdminSave(data) {
const db = require('../../database');
const translator = require('../../translator');
const order = Object.keys(data);
const items = data.map((item, index) => {
Object.keys(item).forEach((key) => {
if (item.hasOwnProperty(key) && typeof item[key] === 'string' && (key === 'title' || key === 'text')) {
item[key] = translator.escape(item[key]);
}
});
item.order = order[index];
return JSON.stringify(item);
});
await db.delete('navigation:enabled');
await db.sortedSetAdd('navigation:enabled', order, items);
}

@ -183,7 +183,7 @@ describe('Search', () => {
it('should fail if searchIn is wrong', (done) => { it('should fail if searchIn is wrong', (done) => {
search.search({ search.search({
query: 'plug', query: 'plug',
searchIn: 'invalidfilter', searchIn: '',
}, (err) => { }, (err) => {
assert.equal(err.message, '[[error:unknown-search-filter]]'); assert.equal(err.message, '[[error:unknown-search-filter]]');
done(); done();
@ -216,6 +216,7 @@ describe('Search', () => {
it('should not find anything', (done) => { it('should not find anything', (done) => {
search.search({ search.search({
query: 'xxxxxxxxxxxxxx', query: 'xxxxxxxxxxxxxx',
searchIn: 'titles',
}, (err, data) => { }, (err, data) => {
assert.ifError(err); assert.ifError(err);
assert(Array.isArray(data.posts)); assert(Array.isArray(data.posts));

Loading…
Cancel
Save