mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-28 02:09:52 +01:00
Merge commit '73a50d17180dcd6cb42ef9cf305a480f92b4af05' into v2.x
This commit is contained in:
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,3 +1,45 @@
|
||||
#### v2.8.8 (2023-03-09)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.7 (3f8248d6)
|
||||
* update changelog for v2.8.7 (2ca38e7b)
|
||||
* incrementing version number - v2.8.6 (af6ce447)
|
||||
* incrementing version number - v2.8.5 (bff5ce2d)
|
||||
* incrementing version number - v2.8.4 (a46b2bbc)
|
||||
* 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
|
||||
|
||||
* stop topic navigation hotkeys from firing if in a mousetrap-enabled form element (22fc8fe3)
|
||||
* stop topic navigation hotkeys from firing if in a mousetrap-enabled form element (17d0b40e)
|
||||
* tag filtering when changing filter to watched topics (1545223e)
|
||||
* get cid from pid instead of passing in (f054a4f4)
|
||||
* closes #11331, allow 0 length content if set to 0 in acp (8c762d32)
|
||||
|
||||
#### v2.8.7 (2023-03-01)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"connect-pg-simple": "8.0.0",
|
||||
"connect-redis": "6.1.3",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cron": "2.1.0",
|
||||
"cron": "2.3.0",
|
||||
"cropperjs": "1.5.13",
|
||||
"csurf": "1.11.0",
|
||||
"daemon": "1.1.0",
|
||||
@@ -192,4 +192,4 @@
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,6 +265,9 @@ TopicObjectSlim:
|
||||
name:
|
||||
type: string
|
||||
description: The topic thumbnail filename
|
||||
path:
|
||||
type: string
|
||||
description: Path to topic thumbnail without upload_url prefix
|
||||
url:
|
||||
type: string
|
||||
description: Relative path to the topic thumbnail
|
||||
|
||||
@@ -31,6 +31,8 @@ get:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
description: Path to a topic thumbnail
|
||||
@@ -155,6 +157,8 @@ delete:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
description: Path to a topic thumbnail
|
||||
@@ -38,4 +38,4 @@ put:
|
||||
$ref: ../../../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
properties: {}
|
||||
|
||||
@@ -26,7 +26,7 @@ module.exports = function (module) {
|
||||
|
||||
async function getSortedSetUnion(params) {
|
||||
if (!Array.isArray(params.sets) || !params.sets.length) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
let limit = params.stop - params.start + 1;
|
||||
if (limit <= 0) {
|
||||
|
||||
@@ -32,6 +32,9 @@ SELECT COUNT(DISTINCT z."value") c
|
||||
|
||||
async function getSortedSetUnion(params) {
|
||||
const { sets } = params;
|
||||
if (!sets || !sets.length) {
|
||||
return [];
|
||||
}
|
||||
const start = params.hasOwnProperty('start') ? params.start : 0;
|
||||
const stop = params.hasOwnProperty('stop') ? params.stop : -1;
|
||||
let weights = params.weights || [];
|
||||
|
||||
@@ -9,11 +9,12 @@ const topics = require('../topics');
|
||||
const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const meta = require('../meta');
|
||||
const helpers = require('../controllers/helpers');
|
||||
const controllerHelpers = require('../controllers/helpers');
|
||||
const privileges = require('../privileges');
|
||||
const db = require('../database');
|
||||
const utils = require('../utils');
|
||||
const controllers404 = require('../controllers/404');
|
||||
const routeHelpers = require('./helpers');
|
||||
|
||||
const terms = {
|
||||
daily: 'day',
|
||||
@@ -23,18 +24,18 @@ const terms = {
|
||||
};
|
||||
|
||||
module.exports = function (app, middleware) {
|
||||
app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic);
|
||||
app.get('/category/:category_id.rss', middleware.maintenanceMode, generateForCategory);
|
||||
app.get('/topics.rss', middleware.maintenanceMode, generateForTopics);
|
||||
app.get('/recent.rss', middleware.maintenanceMode, generateForRecent);
|
||||
app.get('/top.rss', middleware.maintenanceMode, generateForTop);
|
||||
app.get('/top/:term.rss', middleware.maintenanceMode, generateForTop);
|
||||
app.get('/popular.rss', middleware.maintenanceMode, generateForPopular);
|
||||
app.get('/popular/:term.rss', middleware.maintenanceMode, generateForPopular);
|
||||
app.get('/recentposts.rss', middleware.maintenanceMode, generateForRecentPosts);
|
||||
app.get('/category/:category_id/recentposts.rss', middleware.maintenanceMode, generateForCategoryRecentPosts);
|
||||
app.get('/user/:userslug/topics.rss', middleware.maintenanceMode, generateForUserTopics);
|
||||
app.get('/tags/:tag.rss', middleware.maintenanceMode, generateForTag);
|
||||
app.get('/topic/:topic_id.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTopic));
|
||||
app.get('/category/:category_id.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForCategory));
|
||||
app.get('/topics.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTopics));
|
||||
app.get('/recent.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForRecent));
|
||||
app.get('/top.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTop));
|
||||
app.get('/top/:term.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTop));
|
||||
app.get('/popular.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForPopular));
|
||||
app.get('/popular/:term.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForPopular));
|
||||
app.get('/recentposts.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForRecentPosts));
|
||||
app.get('/category/:category_id/recentposts.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForCategoryRecentPosts));
|
||||
app.get('/user/:userslug/topics.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForUserTopics));
|
||||
app.get('/tags/:tag.rss', middleware.maintenanceMode, routeHelpers.tryRoute(generateForTag));
|
||||
};
|
||||
|
||||
async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) {
|
||||
@@ -46,16 +47,16 @@ async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) {
|
||||
}
|
||||
|
||||
if (uid <= 0 || !token) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
const userToken = await db.getObjectField(`user:${uid}`, 'rss_token');
|
||||
if (userToken !== token) {
|
||||
await user.auth.logAttempt(uid, req.ip);
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
const userPrivileges = await privileges.categories.get(cid, uid);
|
||||
if (!userPrivileges.read) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -230,7 +231,7 @@ async function generateSorted(options, req, res, next) {
|
||||
const { cid } = req.query;
|
||||
if (cid) {
|
||||
if (!await privileges.categories.can('topics:read', cid, uid)) {
|
||||
return helpers.notAllowed(req, res);
|
||||
return controllerHelpers.notAllowed(req, res);
|
||||
}
|
||||
params.cids = [cid];
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ module.exports = function (Topics) {
|
||||
}
|
||||
|
||||
Topics.getTagData = async function (tags) {
|
||||
if (!tags.length) {
|
||||
if (!tags || !tags.length) {
|
||||
return [];
|
||||
}
|
||||
tags.forEach((tag) => {
|
||||
|
||||
@@ -52,6 +52,7 @@ Thumbs.get = async function (tids) {
|
||||
const name = path.basename(thumb);
|
||||
return hasTimestampPrefix.test(name) ? name.slice(14) : name;
|
||||
})(),
|
||||
path: thumb,
|
||||
url: thumb.startsWith('http') ? thumb : path.posix.join(upload_url, thumb),
|
||||
})));
|
||||
|
||||
@@ -151,6 +152,9 @@ Thumbs.delete = async function (id, relativePaths) {
|
||||
Promise.all(toRemove.map(async relativePath => posts.uploads.dissociate(mainPid, relativePath.slice(1)))),
|
||||
]);
|
||||
}
|
||||
if (toRemove.length) {
|
||||
cache.del(set);
|
||||
}
|
||||
};
|
||||
|
||||
Thumbs.deleteAll = async (id) => {
|
||||
|
||||
@@ -70,7 +70,9 @@ module.exports = function (User) {
|
||||
|
||||
let line = '';
|
||||
usersData.forEach((user, index) => {
|
||||
line += `${fields.map(field => user[field]).join(',')}`;
|
||||
line += `${fields
|
||||
.map(field => (isFinite(user[field]) ? `'${user[field]}'` : user[field]))
|
||||
.join(',')}`;
|
||||
if (showIps) {
|
||||
userIPs = ips[index] ? ips[index].join(',') : '';
|
||||
line += `,"${userIPs}"\n`;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="alert alert-info">[[modules:thumbs.modal.no-thumbs]]</div>
|
||||
{{{ end }}}
|
||||
{{{ each thumbs }}}
|
||||
<div class="media" data-id="{./id}" data-path="{./url}">
|
||||
<div class="media" data-id="{./id}" data-path="{./path}">
|
||||
<div class="media-left">
|
||||
<img class="media-object" src="{./url}" alt="" />
|
||||
</div>
|
||||
|
||||
@@ -996,6 +996,11 @@ describe('Sorted Set methods', () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty array if sets is empty', async () => {
|
||||
const result = await db.getSortedSetRevUnion({ sets: [], start: 0, stop: -1 });
|
||||
assert.deepStrictEqual(result, []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortedSetIncrBy()', () => {
|
||||
|
||||
@@ -82,6 +82,7 @@ describe('Topic thumbs', () => {
|
||||
assert.deepStrictEqual(thumbs, [{
|
||||
id: topicObj.topicData.tid,
|
||||
name: 'test.png',
|
||||
path: `${relativeThumbPaths[0]}`,
|
||||
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
|
||||
}]);
|
||||
});
|
||||
@@ -92,6 +93,7 @@ describe('Topic thumbs', () => {
|
||||
[{
|
||||
id: topicObj.topicData.tid,
|
||||
name: 'test.png',
|
||||
path: `${relativeThumbPaths[0]}`,
|
||||
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
|
||||
}],
|
||||
[],
|
||||
@@ -200,16 +202,19 @@ describe('Topic thumbs', () => {
|
||||
{
|
||||
id: tid,
|
||||
name: 'test.png',
|
||||
path: relativeThumbPaths[0],
|
||||
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[0]}`,
|
||||
},
|
||||
{
|
||||
id: tid,
|
||||
name: 'example.org',
|
||||
path: 'https://example.org',
|
||||
url: 'https://example.org',
|
||||
},
|
||||
{
|
||||
id: tid,
|
||||
name: 'test2.png',
|
||||
path: relativeThumbPaths[1],
|
||||
url: `${nconf.get('relative_path')}${nconf.get('upload_url')}${relativeThumbPaths[1]}`,
|
||||
},
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user