Merge branch 'master' into bootstrap5

This commit is contained in:
Barış Soner Uşaklı
2022-08-26 18:39:39 -04:00
6 changed files with 205 additions and 25 deletions

View File

@@ -1,3 +1,21 @@
#### v2.4.5 (2022-08-22)
##### Chores
* incrementing version number - v2.4.4 (d5525c87)
* update changelog for v2.4.4 (77e492b8)
* 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
* wrap passport.authenticate to pass in keepSessionInfo if not already set (9b96c33d)
* parseInt caller.uid closes #10849 (bc37a5c5)
#### v2.4.4 (2022-08-18)
##### Chores

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
"version": "2.4.4",
"version": "2.4.5",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",

View File

@@ -177,6 +177,12 @@ define('forum/topic', [
Topic.applyDropup.call(this);
}
});
hooks.onPage('action:topic.tools.load', ({ element }) => {
Topic.applyDropup.call(element.get(0).parentNode);
});
hooks.onPage('action:post.tools.load', ({ element }) => {
Topic.applyDropup.call(element.get(0).parentNode);
});
}
function addRepliesHandler() {

View File

@@ -32,7 +32,6 @@ define('forum/topic/postTools', [
function renderMenu() {
$('[component="topic"]').on('show.bs.dropdown', '.moderator-tools', function () {
const self = this;
const $this = $(this);
const dropdownMenu = $this.find('.dropdown-menu');
if (dropdownMenu.html()) {
@@ -50,14 +49,14 @@ define('forum/topic/postTools', [
const html = await app.parseAndTranslate('partials/topic/post-menu-list', data);
const clipboard = require('clipboard');
// eslint-disable-next-line import/no-unresolved
const topic = require('forum/topic');
dropdownMenu.html(html);
topic.applyDropup.call(self);
// dropdownMenu.get(0).classList.toggle('hidden', false);
new clipboard('[data-clipboard-text]');
hooks.fire('action:post.tools.load');
hooks.fire('action:post.tools.load', {
element: dropdownMenu,
});
});
});
}

View File

@@ -180,12 +180,15 @@ define('forum/topic/threadTools', [
return;
}
dropdownMenu.toggleClass('hidden', true);
socket.emit('topics.loadTopicTools', { tid: ajaxify.data.tid, cid: ajaxify.data.cid }, function (err, data) {
if (err) {
return alerts.error(err);
}
app.parseAndTranslate('partials/topic/topic-menu-list', data, function (html) {
dropdownMenu.html(html);
dropdownMenu.toggleClass('hidden', false);
hooks.fire('action:topic.tools.load', {
element: dropdownMenu,
});

View File

@@ -2548,21 +2548,45 @@ describe('User', () => {
describe('hideEmail/hideFullname', () => {
const COMMON_PW = '123456';
let uid;
let jar;
let regularUserUid;
const hidingUser = {
username: 'hiddenemail',
email: 'should@be.hidden',
fullname: 'baris soner usakli',
password: COMMON_PW,
};
const regularUser = {
username: 'regularUser',
email: 'regular@example.com',
fullname: 'regular user',
password: COMMON_PW,
};
let hidingUserJar;
let adminUid;
let adminJar;
let globalModJar;
let regularUserJar;
before(async () => {
uid = await User.create({
username: 'hiddenemail',
email: 'should@be.hidden',
fullname: 'baris soner usakli',
});
regularUserUid = await User.create({
username: 'regularUser',
adminUid = await User.create({
username: 'adminhideemail',
password: COMMON_PW,
});
({ jar } = await helpers.loginUser('regularUser', COMMON_PW));
await groups.join('administrators', adminUid);
({ jar: adminJar } = await helpers.loginUser('adminhideemail', COMMON_PW));
// Edge case: In a grepped test, this user should not be created as the first user to have its email not confirmed
hidingUser.uid = await User.create(hidingUser);
({ jar: hidingUserJar } = await helpers.loginUser(hidingUser.username, COMMON_PW));
const globalModUid = await User.create({
username: 'globalmodhideemail',
password: COMMON_PW,
});
await groups.join('Global Moderators', globalModUid);
({ jar: globalModJar } = await helpers.loginUser('globalmodhideemail', COMMON_PW));
regularUser.uid = await User.create(regularUser);
({ jar: regularUserJar } = await helpers.loginUser(regularUser.username, COMMON_PW));
});
after((done) => {
@@ -2571,22 +2595,152 @@ describe('User', () => {
done();
});
it('should hide email and fullname', async () => {
async function assertPrivacy({ expectVisible, jar, v3Api, emailOnly }) {
const path = v3Api ? `v3/users/${hidingUser.uid}` : `user/${hidingUser.username}`;
const response = await requestAsync(`${nconf.get('url')}/api/${path}`, { json: true, jar });
const { response: userData } = v3Api ? response : { response };
assert.strictEqual(userData.email, expectVisible ? hidingUser.email : '');
if (!emailOnly) {
assert.strictEqual(userData.fullname, expectVisible ? hidingUser.fullname : '');
}
}
it('should hide unconfirmed emails on profile pages', async () => {
await assertPrivacy({ v3Api: false, emailOnly: true });
await assertPrivacy({ v3Api: false, jar: hidingUserJar, emailOnly: true });
await assertPrivacy({ v3Api: false, jar: adminJar, emailOnly: true });
await assertPrivacy({ v3Api: false, jar: globalModJar, emailOnly: true });
await assertPrivacy({ v3Api: false, jar: regularUserJar, emailOnly: true });
// Let's confirm for afterwards
await User.email.confirmByUid(hidingUser.uid);
});
it('should hide from guests by default', async () => {
await assertPrivacy({ v3Api: false });
});
it('should hide from unprivileged users by default', async () => {
await assertPrivacy({ v3Api: false, jar: regularUserJar });
await assertPrivacy({ v3Api: true, jar: regularUserJar });
});
it('should be visible to self by default', async () => {
await assertPrivacy({ v3Api: false, jar: hidingUserJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: hidingUserJar, expectVisible: true });
});
it('should be visible to privileged users by default', async () => {
await assertPrivacy({ v3Api: false, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: false, jar: globalModJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: globalModJar, expectVisible: true });
});
it('should hide from guests (system-wide: hide, by-user: hide)', async () => {
meta.config.hideEmail = 1;
meta.config.hideFullname = 1;
// Explicitly set user's privacy settings to hide its email and fullname
const data = { uid: hidingUser.uid, settings: { showemail: 0, showfullname: 0 } };
await apiUser.updateSettings({ uid: hidingUser.uid }, data);
await assertPrivacy({ v3Api: false });
});
it('should hide from unprivileged users (system-wide: hide, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: regularUserJar });
await assertPrivacy({ v3Api: true, jar: regularUserJar });
});
it('should be visible to self (system-wide: hide, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: hidingUserJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: hidingUserJar, expectVisible: true });
});
it('should be visible to privileged users (system-wide: hide, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: false, jar: globalModJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: globalModJar, expectVisible: true });
});
it('should hide from guests (system-wide: show, by-user: hide)', async () => {
meta.config.hideEmail = 0;
meta.config.hideFullname = 0;
await assertPrivacy({ v3Api: false });
});
it('should hide from unprivileged users (system-wide: show, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: regularUserJar });
await assertPrivacy({ v3Api: true, jar: regularUserJar });
});
it('should be visible to self (system-wide: show, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: hidingUserJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: hidingUserJar, expectVisible: true });
});
it('should be visible to privileged users (system-wide: show, by-user: hide)', async () => {
await assertPrivacy({ v3Api: false, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: false, jar: globalModJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: globalModJar, expectVisible: true });
});
it('should be visible to guests (system-wide: show, by-user: show)', async () => {
meta.config.hideEmail = 0;
meta.config.hideFullname = 0;
// Set user's individual privacy settings to show its email and fullname
const data = { uid: hidingUser.uid, settings: { showemail: 1, showfullname: 1 } };
await apiUser.updateSettings({ uid: hidingUser.uid }, data);
await assertPrivacy({ v3Api: false, expectVisible: true });
});
it('should be visible to unprivileged users (system-wide: show, by-user: show)', async () => {
await assertPrivacy({ v3Api: false, jar: regularUserJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: regularUserJar, expectVisible: true });
});
// System-wide "hide" prioritized over individual users' settings
it('should hide from guests (system-wide: hide, by-user: show)', async () => {
meta.config.hideEmail = 1;
meta.config.hideFullname = 1;
const userData1 = await requestAsync(`${nconf.get('url')}/api/user/hiddenemail`, { json: true });
assert.strictEqual(userData1.fullname, '');
assert.strictEqual(userData1.email, '');
await assertPrivacy({ v3Api: false });
});
const { response } = await requestAsync(`${nconf.get('url')}/api/v3/users/${uid}`, { json: true, jar: jar });
assert.strictEqual(response.fullname, '');
assert.strictEqual(response.email, '');
it('should hide from unprivileged users (system-wide: hide, by-user: show)', async () => {
await assertPrivacy({ v3Api: false, jar: regularUserJar });
await assertPrivacy({ v3Api: true, jar: regularUserJar });
});
it('should be visible to self (system-wide: hide, by-user: show)', async () => {
await assertPrivacy({ v3Api: false, jar: hidingUserJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: hidingUserJar, expectVisible: true });
});
it('should be visible to privileged users (system-wide: hide, by-user: show)', async () => {
await assertPrivacy({ v3Api: false, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: adminJar, expectVisible: true });
await assertPrivacy({ v3Api: false, jar: globalModJar, expectVisible: true });
await assertPrivacy({ v3Api: true, jar: globalModJar, expectVisible: true });
});
it('should handle array of user data (system-wide: hide)', async () => {
const userData = await User.hidePrivateData([hidingUser, regularUser], hidingUser.uid);
assert.strictEqual(userData[0].fullname, hidingUser.fullname);
assert.strictEqual(userData[0].email, hidingUser.email);
assert.strictEqual(userData[1].fullname, '');
assert.strictEqual(userData[1].email, '');
});
it('should hide fullname in topic list and topic', (done) => {
Topics.post({
uid: uid,
uid: hidingUser.uid,
title: 'Topic hidden',
content: 'lorem ipsum',
cid: testCid,