Compare commits

...

26 Commits

Author SHA1 Message Date
Barış Soner Uşaklı
648d9c78bb chore: up mentions 2025-12-26 23:32:49 -05:00
Misty Release Bot
2f0526b8a4 chore: update changelog for v4.7.2 2025-12-24 18:38:30 +00:00
Misty Release Bot
bab4304e04 chore: incrementing version number - v4.7.2 2025-12-24 18:38:30 +00:00
Barış Soner Uşaklı
1f9f2dff2f fix: update data-isowner when changing is ownership
fixes multiple ownership toggles
2025-12-23 14:29:28 -05:00
Barış Soner Uşaklı
59dd1ca607 chore: up body-parser 2025-12-19 17:38:19 -05:00
Julian Lam
d03137128c fix: bump 2factor 2025-12-18 11:39:31 -05:00
b2cc
da79582148 * Docker: add function to entrypoint to auto-install plugins on reboot (fixes #13735) (#13749)
* * Docker: add function to entrypoint to auto-install plugins on reboot (fixes #13735)

Added a function to install additional NodeBB plugins if specified. This fixes #13735

* fix: case on

---------

Co-authored-by: Jakub Bliźniuk <opliko.reg@protonmail.com>
2025-12-17 17:00:43 -05:00
Barış Uşaklı
550411fb58 test: change redis connection (#13844) 2025-12-17 16:56:07 -05:00
Barış Soner Uşaklı
1305faa838 test: add await to check tests 2025-12-17 14:35:35 -05:00
Barış Soner Uşaklı
d505301fa0 chore: up mentions 2025-12-17 13:02:43 -05:00
Barış Soner Uşaklı
9f8d50706e test: add back logs for failing test 2025-12-17 12:46:33 -05:00
Misty Release Bot
8668cfb38c chore: update changelog for v4.7.1 2025-12-17 15:18:53 +00:00
Misty Release Bot
e6deb625f2 chore: incrementing version number - v4.7.1 2025-12-17 15:18:53 +00:00
Julian Lam
b1fc5bfdaa fix: wrong increment value 2025-12-17 09:57:45 -05:00
Julian Lam
9f94a72117 fix: increment progress on upgrade script 2025-12-17 09:57:45 -05:00
Julian Lam
9f72996416 feat: stop extraneous vote and tids_read data from being saved for remote users 2025-12-17 09:57:45 -05:00
Shlomo
5ae8d553ed fix: disallow inline viewing of unsafe files (#13833) 2025-12-15 13:16:38 -05:00
Barış Soner Uşaklı
90a151348e fix: moving topic to cid=-1 will remove it from list 2025-12-13 17:19:16 -05:00
Barış Soner Uşaklı
f49f540bfa fix: show errors when saving settings 2025-12-11 21:25:42 -05:00
Barış Soner Uşaklı
b19281b061 revert: spec change 2025-12-08 10:18:38 -05:00
Barış Soner Uşaklı
9d6665505e chore: up widget-essentials 2025-12-08 09:43:50 -05:00
Barış Soner Uşaklı
11b01dfccb test: fix tests 2025-12-06 20:44:51 -05:00
Konrad Moskal
2e00c0ff42 Modify delete post diff response format (#13761)
* Modify delete post diff response format

Updated the delete operation response to return JSON content.

* fix: timestamp open api schema
2025-12-06 20:12:27 -05:00
Barış Soner Uşaklı
193aaf55d5 fix: closes #13666, update category label
on topic move if we are not on category page
2025-12-06 20:08:05 -05:00
Nephilim
ebf2a2c5af fix: respect user pagination settings in infinite scroll (#13765) (#13788)
- Changed hardcoded topicsPerPage value of 20 to use settings.topicsPerPage
- Allows infinite scroll to respect user's configured page size preference
- Consistent with pagination handling in other controllers (category.js, recent.js, etc)
- Validates against admin's maxTopicsPerPage setting
- Fixes issue where all users were limited to 20 topics per request regardless of settings
2025-12-05 12:26:53 -05:00
Jakub Bliźniuk
254370c5be ci: drop ARM v7 from docker builds (#13808)
Removed optional ARM v7 (32 bit) platform from the workflow due to lack of support from Node and very limited usefulness.

As the platform had been flaky in the past, this part of the workflow was already optional and didn't cause it to fail. So this is just the next step here.
2025-12-04 18:11:04 -05:00
19 changed files with 281 additions and 49 deletions

View File

@@ -26,9 +26,6 @@ jobs:
- os: ubuntu-24.04-arm
platforms: linux/arm64
required: true
- os: ubuntu-24.04-arm
platforms: linux/arm/v7
required: false
continue-on-error: ${{ !matrix.required }}
runs-on: ${{ matrix.os }}
steps:
@@ -131,4 +128,4 @@ jobs:
$(printf '${{ env.IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.IMAGE }}:${{ steps.meta.outputs.version }}
docker buildx imagetools inspect ${{ env.IMAGE }}:${{ steps.meta.outputs.version }}

View File

@@ -1,3 +1,125 @@
#### v4.7.2 (2025-12-24)
##### Chores
* up body-parser (59dd1ca6)
* up mentions (d505301f)
* incrementing version number - v4.7.1 (afb88805)
* update changelog for v4.7.1 (8668cfb3)
* incrementing version number - v4.7.0 (e82d40f8)
* incrementing version number - v4.6.3 (9fc5b0f3)
* incrementing version number - v4.6.2 (f98747db)
* incrementing version number - v4.6.1 (f47aa678)
* incrementing version number - v4.6.0 (ee395bc5)
* incrementing version number - v4.5.2 (ad2da639)
* incrementing version number - v4.5.1 (69f4b61f)
* incrementing version number - v4.5.0 (f05c5d06)
* incrementing version number - v4.4.6 (074043ad)
* incrementing version number - v4.4.5 (6f106923)
* incrementing version number - v4.4.4 (d323af44)
* incrementing version number - v4.4.3 (d354c2eb)
* incrementing version number - v4.4.2 (55c510ae)
* incrementing version number - v4.4.1 (5ae79b4e)
* incrementing version number - v4.4.0 (0a75eee3)
* incrementing version number - v4.3.2 (b92b5d80)
* incrementing version number - v4.3.1 (308e6b9f)
* incrementing version number - v4.3.0 (bff291db)
* incrementing version number - v4.2.2 (17fecc24)
* incrementing version number - v4.2.1 (852a270c)
* incrementing version number - v4.2.0 (87581958)
* incrementing version number - v4.1.1 (b2afbb16)
* incrementing version number - v4.1.0 (36c80850)
* incrementing version number - v4.0.6 (4a52fb2e)
* incrementing version number - v4.0.5 (1792a62b)
* incrementing version number - v4.0.4 (b1125cce)
* incrementing version number - v4.0.3 (2b65c735)
* incrementing version number - v4.0.2 (73fe5fcf)
* incrementing version number - v4.0.1 (a461b758)
* incrementing version number - v4.0.0 (c1eaee45)
##### Bug Fixes
* update data-isowner when changing is ownership (1f9f2dff)
* bump 2factor (d0313712)
##### Tests
* change redis connection (#13844) (550411fb)
* add await to check tests (1305faa8)
* add back logs for failing test (9f8d5070)
#### v4.7.1 (2025-12-17)
##### Chores
* up widget-essentials (9d666550)
* remove log (2142b680)
* up harmony (59f649b8)
* incrementing version number - v4.7.0 (e82d40f8)
* update changelog for v4.7.0 (1c0a43dc)
* incrementing version number - v4.6.3 (9fc5b0f3)
* incrementing version number - v4.6.2 (f98747db)
* incrementing version number - v4.6.1 (f47aa678)
* incrementing version number - v4.6.0 (ee395bc5)
* incrementing version number - v4.5.2 (ad2da639)
* incrementing version number - v4.5.1 (69f4b61f)
* incrementing version number - v4.5.0 (f05c5d06)
* incrementing version number - v4.4.6 (074043ad)
* incrementing version number - v4.4.5 (6f106923)
* incrementing version number - v4.4.4 (d323af44)
* incrementing version number - v4.4.3 (d354c2eb)
* incrementing version number - v4.4.2 (55c510ae)
* incrementing version number - v4.4.1 (5ae79b4e)
* incrementing version number - v4.4.0 (0a75eee3)
* incrementing version number - v4.3.2 (b92b5d80)
* incrementing version number - v4.3.1 (308e6b9f)
* incrementing version number - v4.3.0 (bff291db)
* incrementing version number - v4.2.2 (17fecc24)
* incrementing version number - v4.2.1 (852a270c)
* incrementing version number - v4.2.0 (87581958)
* incrementing version number - v4.1.1 (b2afbb16)
* incrementing version number - v4.1.0 (36c80850)
* incrementing version number - v4.0.6 (4a52fb2e)
* incrementing version number - v4.0.5 (1792a62b)
* incrementing version number - v4.0.4 (b1125cce)
* incrementing version number - v4.0.3 (2b65c735)
* incrementing version number - v4.0.2 (73fe5fcf)
* incrementing version number - v4.0.1 (a461b758)
* incrementing version number - v4.0.0 (c1eaee45)
##### Continuous Integration
* drop ARM v7 from docker builds (#13808) (254370c5)
##### New Features
* stop extraneous vote and tids_read data from being saved for remote users (9f729964)
* add hreflang to buildLinkTag (ba85474d)
* #13790, allow ssl setup in psql (5bd1f7b7)
##### Bug Fixes
* wrong increment value (b1fc5bfd)
* increment progress on upgrade script (9f94a721)
* disallow inline viewing of unsafe files (#13833) (5ae8d553)
* moving topic to cid=-1 will remove it from list (90a15134)
* show errors when saving settings (f49f540b)
* closes #13666, update category label (193aaf55)
* respect user pagination settings in infinite scroll (#13765) (#13788) (ebf2a2c5)
* remove hardcoded name for sentinel, #13794 (53e22acf)
##### Other Changes
* fix missing comma (9fb41c69)
##### Reverts
* spec change (b19281b0)
##### Tests
* fix tests (11b01dfc)
#### v4.7.0 (2025-11-26)
##### Chores

View File

@@ -12,6 +12,7 @@ set_defaults() {
export SETUP="${SETUP:-}"
export PACKAGE_MANAGER="${PACKAGE_MANAGER:-npm}"
export OVERRIDE_UPDATE_LOCK="${OVERRIDE_UPDATE_LOCK:-false}"
export NODEBB_ADDITIONAL_PLUGINS="${NODEBB_ADDITIONAL_PLUGINS:-}"
}
# Function to check if a directory exists and is writable
@@ -172,6 +173,33 @@ debug_log() {
echo "DEBUG: $message"
}
install_additional_plugins() {
if [[ ! -z ${NODEBB_ADDITIONAL_PLUGINS} ]]; then
export START_BUILD="true"
for plugin in "${NODEBB_ADDITIONAL_PLUGINS[@]}"; do
echo "Installing additional plugin ${plugin}..."
case "$PACKAGE_MANAGER" in
yarn) yarn install || {
echo "Failed to install plugin ${plugin} with yarn"
exit 1
} ;;
npm) npm install || {
echo "Failed to install plugin ${plugin} with npm"
exit 1
} ;;
pnpm) pnpm install || {
echo "Failed to install plugin ${plugin} with pnpm"
exit 1
} ;;
*)
echo "Unknown package manager: $PACKAGE_MANAGER"
exit 1
;;
esac
done
fi
}
# Main function
main() {
set_defaults
@@ -182,12 +210,14 @@ main() {
debug_log "PACKAGE_MANAGER: $PACKAGE_MANAGER"
debug_log "CONFIG location: $CONFIG"
debug_log "START_BUILD: $START_BUILD"
debug_log "NODEBB_ADDITIONAL_PLUGINS: ${NODEBB_ADDITIONAL_PLUGINS}"
if [ -n "$SETUP" ]; then
start_setup_session "$CONFIG"
fi
if [ -f "$CONFIG" ]; then
install_additional_plugins
start_forum "$CONFIG" "$START_BUILD"
else
start_installation_session "$NODEBB_INIT_VERB" "$CONFIG"

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
"version": "4.7.0",
"version": "4.7.2",
"homepage": "https://www.nodebb.org",
"repository": {
"type": "git",
@@ -45,7 +45,7 @@
"autoprefixer": "10.4.22",
"bcryptjs": "3.0.3",
"benchpressjs": "2.5.5",
"body-parser": "2.2.0",
"body-parser": "2.2.1",
"bootbox": "6.0.4",
"bootstrap": "5.3.8",
"bootswatch": "5.3.8",
@@ -96,14 +96,14 @@
"mousetrap": "1.6.5",
"multer": "2.0.2",
"nconf": "0.13.0",
"nodebb-plugin-2factor": "7.6.0",
"nodebb-plugin-2factor": "7.6.1",
"nodebb-plugin-composer-default": "10.3.1",
"nodebb-plugin-dbsearch": "6.3.4",
"nodebb-plugin-emoji": "6.0.5",
"nodebb-plugin-emoji-android": "4.1.1",
"nodebb-plugin-link-preview": "2.1.5",
"nodebb-plugin-markdown": "13.2.2",
"nodebb-plugin-mentions": "4.8.3",
"nodebb-plugin-mentions": "4.8.5",
"nodebb-plugin-spam-be-gone": "2.3.2",
"nodebb-plugin-web-push": "0.7.6",
"nodebb-rewards-essentials": "1.0.2",
@@ -111,7 +111,7 @@
"nodebb-theme-lavender": "7.1.19",
"nodebb-theme-peace": "2.2.49",
"nodebb-theme-persona": "14.1.18",
"nodebb-widget-essentials": "7.0.40",
"nodebb-widget-essentials": "7.0.41",
"nodemailer": "7.0.10",
"nprogress": "0.2.0",
"passport": "0.7.0",

View File

@@ -102,7 +102,7 @@ define('forum/account/settings', [
if (languageChanged && parseInt(app.user.uid, 10) === parseInt(ajaxify.data.theirid, 10)) {
window.location.reload();
}
});
}).catch(alerts.error);
}
function toggleCustomRoute() {

View File

@@ -284,8 +284,20 @@ define('forum/category/tools', [
topic.find('[component="topic/locked"]').toggleClass('hidden', !data.isLocked);
}
function onTopicMoved(data) {
getTopicEl(data.tid).remove();
async function onTopicMoved(data) {
if (ajaxify.data.template.category || String(data.toCid) === '-1') {
getTopicEl(data.tid).remove();
} else {
const category = await api.get(`/categories/${data.toCid}`);
const html = await app.parseAndTranslate('partials/topics_list', {
topics: [{
...data,
category,
}],
});
const categoryLabelSelector = `[component="category/topic"][data-tid="${data.tid}"] [component="topic/category"]`;
$(categoryLabelSelector).replaceWith(html.find(categoryLabelSelector));
}
}
function onTopicPurged(data) {

View File

@@ -81,6 +81,7 @@ define('forum/groups/details', [
case 'toggleOwnership':
api[isOwner ? 'del' : 'put'](`/groups/${ajaxify.data.group.slug}/ownership/${uid}`, {}).then(() => {
ownerFlagEl.toggleClass('invisible');
userRow.attr('data-isowner', isOwner ? '0' : '1');
}).catch(alerts.error);
break;

View File

@@ -113,7 +113,7 @@ module.exports = function (utils, Benchpress, relative_path) {
}
const href = tag === 'a' ? `href="${relative_path}/category/${category.slug}"` : '';
return `<${tag} ${href} class="badge px-1 text-truncate text-decoration-none ${className}" style="color: ${category.color};background-color: ${category.bgColor};border-color: ${category.bgColor}!important; max-width: 70vw;">
return `<${tag} component="topic/category" ${href} class="badge px-1 text-truncate text-decoration-none ${className}" style="color: ${category.color};background-color: ${category.bgColor};border-color: ${category.bgColor}!important; max-width: 70vw;">
${category.icon && category.icon !== 'fa-nbb-none' ? `<i class="fa fa-fw ${category.icon}"></i>` : ''}
${category.name}
</${tag}>`;

View File

@@ -267,7 +267,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => {
if (!hasTid && options.cid) {
// New topic, have category announce it
activitypub.out.announce.topic(tid);
await activitypub.out.announce.topic(tid);
}
return { tid, count };

View File

@@ -126,7 +126,7 @@ categoriesAPI.getTopics = async (caller, data) => {
throw new Error('[[error:no-privileges]]');
}
const infScrollTopicsPerPage = 20;
const infScrollTopicsPerPage = settings.topicsPerPage;
const sort = data.sort || data.categoryTopicSort || meta.config.categoryTopicSort || 'recently_replied';
let start = Math.max(0, parseInt(data.after || 0, 10));

View File

@@ -309,6 +309,7 @@ topicsAPI.move = async (caller, { tid, cid }) => {
throw new Error('[[error:no-privileges]]');
}
const topicData = await topics.getTopicFields(tid, ['tid', 'cid', 'mainPid', 'slug', 'deleted']);
topicData.toCid = cid;
if (!cids.includes(topicData.cid)) {
cids.push(topicData.cid);
}

View File

@@ -58,13 +58,12 @@ connection.connect = async function (options) {
winston.error(err.stack);
reject(err);
});
cxn.on('ready', () => {
cxn.connect().then(() => {
// back-compat with node_redis
cxn.batch = cxn.multi;
resolve(cxn);
});
cxn.connect().then(() => {
winston.info('Connected to Redis successfully');
resolve(cxn);
}).catch((err) => {
winston.error('Error connecting to Redis:', err);
});

View File

@@ -273,10 +273,19 @@ middleware.buildSkinAsset = helpers.try(async (req, res, next) => {
middleware.addUploadHeaders = function addUploadHeaders(req, res, next) {
// Trim uploaded files' timestamps when downloading + force download if html
let basename = path.basename(req.path);
const extname = path.extname(req.path);
if (req.path.startsWith('/uploads/files/') && middleware.regexes.timestampedUpload.test(basename)) {
basename = basename.slice(14);
res.header('Content-Disposition', `${extname.startsWith('.htm') ? 'attachment' : 'inline'}; filename="${basename}"`);
const extname = path.extname(req.path).toLowerCase();
const unsafeExtensions = [
'.html', '.htm', '.xhtml', '.mht', '.mhtml', '.stm', '.shtm', '.shtml',
'.svg', '.svgz',
'.xml', '.xsl', '.xslt',
];
const isInlineSafe = !unsafeExtensions.includes(extname);
const dispositionType = isInlineSafe ? 'inline' : 'attachment';
if (req.path.startsWith('/uploads/files/')) {
if (middleware.regexes.timestampedUpload.test(basename)) {
basename = basename.slice(14);
}
res.header('Content-Disposition', `${dispositionType}; filename="${basename}"`);
}
next();

View File

@@ -177,16 +177,18 @@ module.exports = function (Posts) {
}
const now = Date.now();
if (type === 'upvote' && !unvote) {
await db.sortedSetAdd(`uid:${uid}:upvote`, now, pid);
} else {
await db.sortedSetRemove(`uid:${uid}:upvote`, pid);
}
if (utils.isNumber(uid)) {
if (type === 'upvote' && !unvote) {
await db.sortedSetAdd(`uid:${uid}:upvote`, now, pid);
} else {
await db.sortedSetRemove(`uid:${uid}:upvote`, pid);
}
if (type === 'upvote' || unvote) {
await db.sortedSetRemove(`uid:${uid}:downvote`, pid);
} else {
await db.sortedSetAdd(`uid:${uid}:downvote`, now, pid);
if (type === 'upvote' || unvote) {
await db.sortedSetRemove(`uid:${uid}:downvote`, pid);
} else {
await db.sortedSetAdd(`uid:${uid}:downvote`, now, pid);
}
}
const postData = await Posts.getPostFields(pid, ['pid', 'uid', 'tid']);

View File

@@ -290,7 +290,7 @@ module.exports = function (Topics) {
};
Topics.markAsRead = async function (tids, uid) {
if (!Array.isArray(tids) || !tids.length) {
if (!Array.isArray(tids) || !tids.length || !utils.isNumber(uid)) {
return false;
}

View File

@@ -0,0 +1,24 @@
'use strict';
const db = require('../../database');
const batch = require('../../batch');
module.exports = {
name: 'Remove extraneous upvote and tids_read data for remote users',
timestamp: Date.UTC(2025, 11, 11),
method: async function () {
const { progress } = this;
await batch.processSortedSet('usersRemote:lastCrawled', async (uids) => {
const readKeys = uids.map(uid => `uid:${uid}:tids_read`);
const voteKeys = uids.map(uid => `uid:${uid}:upvote`);
const combined = readKeys.concat(voteKeys);
await db.deleteAll(combined);
progress.incr(uids.length);
}, {
batch: 500,
progress,
});
},
};

View File

@@ -164,8 +164,9 @@ describe('FEPs', () => {
});
pid = id;
({ activity } = await helpers.mocks.create(note));
console.log('before inbox create', activitypub._sent);
await activitypub.inbox.create({ body: activity });
console.log('after inbox create', activitypub._sent);
const activities = Array.from(activitypub._sent);
const test1 = activities.some((activity) => {
@@ -174,14 +175,13 @@ describe('FEPs', () => {
activity.object && activity.object.type === 'Create' &&
activity.object.object && activity.object.object.type === 'Note';
});
assert(test1);
const test2 = activities.some((activity) => {
[, activity] = activity;
return activity.type === 'Announce' &&
activity.object && activity.object.type === 'Note';
});
assert(test1 && test2);
assert(test2);
});
it('should federate out an Announce(Create(Note)) on reply', async () => {

View File

@@ -432,6 +432,7 @@ describe('Notes', () => {
describe('Create', () => {
let uid;
let cid;
before(async () => {
uid = await user.create({ username: utils.generateUUID() });
@@ -451,6 +452,17 @@ describe('Notes', () => {
assert.strictEqual(cid, -1);
});
it('should not append to the tids_read sorted set', async () => {
const { note, id } = helpers.mocks.note();
const { activity } = helpers.mocks.create(note);
await db.sortedSetAdd(`followersRemote:${note.attributedTo}`, Date.now(), uid);
await activitypub.inbox.create({ body: activity });
const exists = await db.exists(`uid:${note.attributedTo}:tids_read`);
assert(!exists);
});
it('should create a new topic in a remote category if addressed (category same-origin)', async () => {
const { id: remoteCid } = helpers.mocks.group();
const { note, id } = helpers.mocks.note({
@@ -467,40 +479,63 @@ describe('Notes', () => {
});
it('should create a new topic in cid -1 if a non-same origin remote category is addressed', async function () {
this.timeout(30000);
const start = Date.now();
const { id: remoteCid } = helpers.mocks.group({
id: `https://example.com/${utils.generateUUID()}`,
});
console.log('1', Date.now() - start);
const { note, id } = helpers.mocks.note({
audience: [remoteCid],
});
console.log('2', Date.now() - start);
const { activity } = helpers.mocks.create(note);
console.log('3', Date.now() - start);
try {
await activitypub.inbox.create({ body: activity });
} catch (err) {
console.log('error in test', err.stack);
assert(false);
}
console.log('4', Date.now() - start);
assert(await posts.exists(id));
console.log('5', Date.now() - start);
const cid = await posts.getCidByPid(id);
console.log('6', Date.now() - start);
assert.strictEqual(cid, -1);
});
});
describe('(Like)', () => {
let pid;
let voterUid;
before(async () => {
({ cid } = await categories.create({ name: utils.generateUUID() }));
const { postData } = await topics.post({
uid,
cid,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
pid = postData.pid;
const object = await activitypub.mocks.notes.public(postData);
const { activity } = helpers.mocks.like({ object });
voterUid = activity.actor;
await activitypub.inbox.like({ body: activity });
});
it('should increment a like for the post', async () => {
const voted = await posts.hasVoted(pid, voterUid);
const count = await posts.getPostField(pid, 'upvotes');
assert(voted);
assert.strictEqual(count, 1);
});
it('should not append to the uid upvotes zset', async () => {
const exists = await db.exists(`uid:${voterUid}:upvote`);
assert(!exists);
});
});
});
describe('Announce', () => {
let cid;
before(async () => {
({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
({ cid } = await categories.create({ name: utils.generateUUID() }));
});
describe('(Create)', () => {

View File

@@ -107,7 +107,7 @@ describe('helpers', () => {
imageClass: 'auto',
name: 'Category 1',
}, 'a', ''),
`<a href="${nconf.get('relative_path')}/category/undefined" class="badge px-1 text-truncate text-decoration-none " style="color: #00ff00;background-color: #ff0000;border-color: #ff0000!important; max-width: 70vw;">\n\t\t\t\n\t\t\tCategory 1\n\t\t</a>`
`<a component="topic/category" href="${nconf.get('relative_path')}/category/undefined" class="badge px-1 text-truncate text-decoration-none " style="color: #00ff00;background-color: #ff0000;border-color: #ff0000!important; max-width: 70vw;">\n\t\t\t\n\t\t\tCategory 1\n\t\t</a>`
);
assert.strictEqual(
helpers.buildCategoryLabel({
@@ -118,7 +118,7 @@ describe('helpers', () => {
name: 'Category 1',
icon: 'fa-book',
}, 'span', 'rounded-1'),
`<span class="badge px-1 text-truncate text-decoration-none rounded-1" style="color: #00ff00;background-color: #ff0000;border-color: #ff0000!important; max-width: 70vw;">\n\t\t\t<i class="fa fa-fw fa-book"></i>\n\t\t\tCategory 1\n\t\t</span>`,
`<span component="topic/category" class="badge px-1 text-truncate text-decoration-none rounded-1" style="color: #00ff00;background-color: #ff0000;border-color: #ff0000!important; max-width: 70vw;">\n\t\t\t<i class="fa fa-fw fa-book"></i>\n\t\t\tCategory 1\n\t\t</span>`,
);
done();
});