mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-03 11:01:20 +01:00
fix: allow break string and summary limits to be defined and applied
This commit is contained in:
@@ -206,5 +206,7 @@
|
||||
"activitypubProbeTimeout": 2000,
|
||||
"activitypubContentPruneDays": 30,
|
||||
"activitypubUserPruneDays": 7,
|
||||
"activitypubFilter": 0
|
||||
"activitypubFilter": 0,
|
||||
"activitypubSummaryLimit": 500,
|
||||
"activitypubBreakString": "[...]"
|
||||
}
|
||||
|
||||
@@ -50,9 +50,10 @@
|
||||
|
||||
"section-federation": "Federation",
|
||||
"federation/general": "General",
|
||||
"federation/content": "Content",
|
||||
"federation/rules": "Categorization",
|
||||
"federation/relays": "Relays",
|
||||
"federation/pruning": "Content Pruning",
|
||||
"federation/pruning": "Storage",
|
||||
"federation/safety": "Trust & Safety",
|
||||
|
||||
"section-appearance": "Appearance",
|
||||
|
||||
@@ -44,5 +44,11 @@
|
||||
"count": "This NodeBB is currently aware of <strong>%1</strong> server(s)",
|
||||
"server.filter-help": "Specify servers you would like to bar from federating with your NodeBB. Alternatively, you may opt to selectively <em>allow</em> federation with specific servers, instead. Both options are supported, although they are mutually exclusive.",
|
||||
"server.filter-help-hostname": "Enter just the instance hostname below (e.g. <code>example.org</code>), separated by line breaks.",
|
||||
"server.filter-allow-list": "Use this as an Allow List instead"
|
||||
"server.filter-allow-list": "Use this as an Allow List instead",
|
||||
|
||||
"content.outgoing": "Outgoing",
|
||||
"content.summary-limit": "Character count after which a summary is generated",
|
||||
"content.summary-limit-help": "When content is federated out that exceeds this character count, a <code>summary</code> is generated, comprising of all complete sentences prior to this limit. (Default: 500)",
|
||||
"content.break-string": "Note/Article Delimiter",
|
||||
"content.break-string-help": "This delimiter can be manually inserted by power users when composing new topics. It instructs NodeBB to use content up until that point as part of the <code>summary</code>. If this string is not used, then the character count fallback applies. (Default: <code>[...]</code>)"
|
||||
}
|
||||
@@ -8,6 +8,7 @@ const sanitize = require('sanitize-html');
|
||||
const tokenizer = require('sbd');
|
||||
|
||||
const db = require('../database');
|
||||
const meta = require('../meta');
|
||||
const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const posts = require('../posts');
|
||||
@@ -710,7 +711,7 @@ Mocks.notes.public = async (post) => {
|
||||
|
||||
// Special handling for main posts (as:Article w/ as:Note preview)
|
||||
const plaintext = posts.sanitizePlaintext(content);
|
||||
const isArticle = post.pid === post.topic.mainPid && plaintext.length > 500;
|
||||
const isArticle = post.pid === post.topic.mainPid && plaintext.length > meta.config.activitypubSummaryLimit;
|
||||
|
||||
if (post.isMainPost) {
|
||||
const thumbs = await topics.thumbs.get(post.tid);
|
||||
@@ -755,17 +756,16 @@ Mocks.notes.public = async (post) => {
|
||||
// attachment,
|
||||
// };
|
||||
|
||||
const breakString = '[...]';
|
||||
if (post.content.includes(breakString)) {
|
||||
const index = post.content.indexOf(breakString);
|
||||
summary = post.content.slice(0, index + breakString.length);
|
||||
if (post.content.includes(meta.config.activitypubBreakString)) {
|
||||
const index = post.content.indexOf(meta.config.activitypubBreakString);
|
||||
summary = post.content.slice(0, index + meta.config.activitypubBreakString.length);
|
||||
} else {
|
||||
const sentences = tokenizer.sentences(post.content, { newline_boundaries: true });
|
||||
// Append sentences to summary until it contains just under 500 characters of content
|
||||
const limit = 500;
|
||||
// Append sentences to summary until until just under configured character limit
|
||||
const limit = meta.config.activitypubSummaryLimit;
|
||||
let remaining = limit;
|
||||
let finished = false;
|
||||
summary = sentences.reduce((memo, sentence) => {
|
||||
summary = sentences.reduce((memo, sentence, index) => {
|
||||
if (finished) {
|
||||
return memo;
|
||||
}
|
||||
@@ -776,7 +776,7 @@ Mocks.notes.public = async (post) => {
|
||||
});
|
||||
remaining = remaining - clean.length;
|
||||
if (remaining > 0) {
|
||||
memo += ` ${sentence}`;
|
||||
memo += `${index > 0 ? ' ' : ''}${sentence}`;
|
||||
} else { // There was more but summary generation is complete
|
||||
finished = true;
|
||||
memo += ' [...]';
|
||||
|
||||
@@ -10,6 +10,12 @@ federationController.general = function (req, res) {
|
||||
});
|
||||
};
|
||||
|
||||
federationController.content = function (req, res) {
|
||||
res.render(`admin/federation/content`, {
|
||||
title: '[[admin/menu:federation/content]]',
|
||||
});
|
||||
};
|
||||
|
||||
federationController.rules = async function (req, res) {
|
||||
const rules = await activitypub.rules.list();
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ module.exports = function (Posts) {
|
||||
}
|
||||
|
||||
if (!type.startsWith('activitypub.')) {
|
||||
postData.content = postData.content.replace('[...]', '');
|
||||
postData.content = postData.content.replace(meta.config.activitypubBreakString, '');
|
||||
}
|
||||
({ postData } = await plugins.hooks.fire('filter:parse.post', { postData, type }));
|
||||
postData.content = translator.escape(postData.content);
|
||||
|
||||
@@ -53,6 +53,7 @@ module.exports = function (app, name, middleware, controllers) {
|
||||
helpers.setupAdminPageRoute(app, `/${name}/settings/advanced`, middlewares, controllers.admin.settings.advanced);
|
||||
|
||||
helpers.setupAdminPageRoute(app, `/${name}/federation/general`, middlewares, controllers.admin.federation.general);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/federation/content`, middlewares, controllers.admin.federation.content);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/federation/rules`, middlewares, controllers.admin.federation.rules);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/federation/relays`, middlewares, controllers.admin.federation.relays);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/federation/pruning`, middlewares, controllers.admin.federation.pruning);
|
||||
|
||||
29
src/views/admin/federation/content.tpl
Normal file
29
src/views/admin/federation/content.tpl
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="acp-page-container">
|
||||
<!-- IMPORT admin/partials/settings/header.tpl -->
|
||||
|
||||
<div class="row settings m-0">
|
||||
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
|
||||
<div id="outgoing" class="mb-4">
|
||||
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/activitypub:content.outgoing]]</h5>
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="activitypubSummaryLimit">[[admin/settings/activitypub:content.summary-limit]]</label>
|
||||
<input type="number" id="activitypubSummaryLimit" name="activitypubSummaryLimit" data-field="activitypubSummaryLimit" title="[[admin/settings/activitypub:content.summary-limit]]" class="form-control" />
|
||||
<div class="form-text">
|
||||
[[admin/settings/activitypub:content.summary-limit-help]]
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="activitypubBreakString">[[admin/settings/activitypub:content.break-string]]</label>
|
||||
<input type="text" id="activitypubBreakString" name="activitypubBreakString" data-field="activitypubBreakString" title="[[admin/settings/activitypub:content.break-string]]" class="form-control" />
|
||||
<div class="form-text">
|
||||
[[admin/settings/activitypub:content.break-string-help]]
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IMPORT admin/partials/settings/toc.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,6 +104,7 @@
|
||||
<div id="collapseFederation" class="accordion-collapse collapse" data-bs-parent="#accordionACP">
|
||||
<div class="accordion-body p-0 d-grid">
|
||||
<a class="btn btn-ghost btn-sm text-start" id="federation-general" href="{relative_path}/admin/federation/general">[[admin/menu:federation/general]]</a>
|
||||
<a class="btn btn-ghost btn-sm text-start" id="federation-content" href="{relative_path}/admin/federation/content">[[admin/menu:federation/content]]</a>
|
||||
<a class="btn btn-ghost btn-sm text-start" id="federation-rules" href="{relative_path}/admin/federation/rules">[[admin/menu:federation/rules]]</a>
|
||||
<a class="btn btn-ghost btn-sm text-start" id="federation-relays" href="{relative_path}/admin/federation/relays">[[admin/menu:federation/relays]]</a>
|
||||
<a class="btn btn-ghost btn-sm text-start" id="federation-pruning" href="{relative_path}/admin/federation/pruning">[[admin/menu:federation/pruning]]</a>
|
||||
|
||||
@@ -4,6 +4,7 @@ const assert = require('assert');
|
||||
const nconf = require('nconf');
|
||||
|
||||
const db = require('../mocks/databasemock');
|
||||
const meta = require('../../src/meta');
|
||||
const user = require('../../src/user');
|
||||
const categories = require('../../src/categories');
|
||||
const topics = require('../../src/topics');
|
||||
@@ -82,6 +83,45 @@ describe('Mocking', () => {
|
||||
const { content } = await posts.parsePost(clone);
|
||||
assert(!content.includes('[...]'));
|
||||
});
|
||||
|
||||
describe('Altered magic break string', () => {
|
||||
let string;
|
||||
before(() => {
|
||||
string = meta.config.activitypubBreakString;
|
||||
meta.config.activitypubBreakString = 'Mauris';
|
||||
});
|
||||
|
||||
after(() => {
|
||||
meta.config.activitypubBreakString = string;
|
||||
});
|
||||
|
||||
it('should work with a customized break string', async function () {
|
||||
const mocked = await activitypub.mocks.notes.public(this.withBreakPost);
|
||||
assert.strictEqual(mocked.summary, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.\
|
||||
Aliquam vel augue, id luctus nulla. Mauris');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Altered summary limit', () => {
|
||||
let string;
|
||||
let limit;
|
||||
before(() => {
|
||||
string = meta.config.activitypubBreakString;
|
||||
meta.config.activitypubBreakString = 'lkjsdnfkjsdfkjsdhfkd';
|
||||
limit = meta.config.activitypubSummaryLimit;
|
||||
meta.config.activitypubSummaryLimit = 60;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
meta.config.activitypubBreakString = string;
|
||||
meta.config.activitypubSummaryLimit = limit;
|
||||
});
|
||||
|
||||
it('should work with a customized summary limit', async function () {
|
||||
const mocked = await activitypub.mocks.notes.public(this.withBreakPost);
|
||||
assert.strictEqual(mocked.summary, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. [...]');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user