feat: add federatedDescription property to a category.

The federated description will be appended to the category description when queried remotely.
The default string is translatable, and tells users that it identifies as a forum category and that topics can be created within by mentioning the category directly.

closes #13127
This commit is contained in:
Julian Lam
2025-03-06 11:44:50 -05:00
parent 8ca1d6e6cc
commit dfabadbeab
4 changed files with 21 additions and 5 deletions

View File

@@ -10,6 +10,9 @@
"handle": "Category Handle",
"handle.help": "Your category handle is used as a representation of this category across other networks, similar to a username. A category handle must not match an existing username or user group.",
"description": "Category Description",
"federatedDescription": "Federated Description",
"federatedDescription.help": "This text will be appended to the category description when queried by other websites/apps.",
"federatedDescription.default": "This is a forum category containing topical discussion. You can start new discussions by mentioning this category.",
"bg-color": "Background Colour",
"text-color": "Text Colour",
"bg-image-size": "Background Image Size",

View File

@@ -413,10 +413,11 @@ Mocks.actors.user = async (uid) => {
};
Mocks.actors.category = async (cid) => {
const {
let {
name, handle: preferredUsername, slug,
descriptionParsed: summary, backgroundImage,
} = await categories.getCategoryData(cid);
descriptionParsed: summary, federatedDescription, backgroundImage,
} = await categories.getCategoryFields(cid,
['name', 'handle', 'slug', 'description', 'descriptionParsed', 'federatedDescription', 'backgroundImage']);
const publicKey = await activitypub.getPublicKey('cid', cid);
let icon;
@@ -437,6 +438,9 @@ Mocks.actors.category = async (cid) => {
};
}
// Append federated desc.
const fallback = await translator.translate('[[admin/manage/categories:federatedDescription.default]]');
summary += `<hr /><p dir="auto">${federatedDescription || fallback}</p>\n`;
return {
'@context': [

View File

@@ -117,7 +117,7 @@ function modifyCategory(category, fields) {
db.parseIntFields(category, intFields, fields);
const escapeFields = ['name', 'color', 'bgColor', 'backgroundImage', 'imageClass', 'class', 'link'];
const escapeFields = ['name', 'description', 'federatedDescription', 'color', 'bgColor', 'backgroundImage', 'imageClass', 'class', 'link'];
escapeFields.forEach((field) => {
if (category.hasOwnProperty(field)) {
category[field] = validator.escape(String(category[field] || ''));
@@ -137,7 +137,6 @@ function modifyCategory(category, fields) {
}
if (category.description) {
category.description = validator.escape(String(category.description));
category.descriptionParsed = category.descriptionParsed || category.description;
}
}

View File

@@ -36,6 +36,16 @@
<textarea id="cid-{category.cid}-description" data-name="description" class="form-control category_description description" rows="4" />{category.description}</textarea>
</div>
<div class="mb-3">
<label class="form-label" for="cid-{category.cid}-federatedDescription">
[[admin/manage/categories:federatedDescription]]
</label>
<textarea id="cid-{category.cid}-federatedDescription" data-name="federatedDescription" class="form-control" rows="2" placeholder="[[admin/manage/categories:federatedDescription.default]]" />{category.federatedDescription}</textarea>
<p class="form-text">
[[admin/manage/categories:federatedDescription.help]]
</p>
</div>
<div class="mb-3 d-flex justify-content-between align-items-center gap-2">
<label class="form-label" for="cid-{category.cid}-parentCid">[[admin/manage/categories:parent-category]]</label>
<div id="parent-category-selector">