feat: allow user auto-categorization rule

This commit is contained in:
Julian Lam
2025-09-08 14:57:51 -04:00
parent 10f665e3e3
commit 1d6a9fe738
5 changed files with 39 additions and 3 deletions

View File

@@ -22,8 +22,9 @@
"rules-intro": "Content discovered via ActivityPub can be automatically categorized based on certain rules (e.g. hashtag)",
"rules.modal.title": "How it works",
"rules.modal.instructions": "Any incoming content is checked against these categorization rules, and matching content is automatically moved into the category of choice.<br /><br /><strong>N.B.</strong> Content that is already categorized (i.e. in a remote category) will not pass through these rules.",
"rules.modal.values-multiple": "To match multiple values, separate entries with a comma (e.g. <code>one,two,three</code>)",
"rules.add": "Add New Rule",
"rules.help-hashtag": "Topics containing this case-insensitive hashtag will match. Do not enter the <code>#</code> symbol",
"rules.help-user": "Topics created by the entered user will match. Enter a handle or full ID (e.g. <code>bob@example.org</code> or <code>https://example.org/users/bob</code>.",
"rules.type": "Type",
"rules.value": "Value",
"rules.cid": "Category",

View File

@@ -6,7 +6,8 @@ define('admin/settings/activitypub', [
'categorySelector',
'api',
'alerts',
], function (Benchpress, bootbox, categorySelector, api, alerts) {
'translator',
], function (Benchpress, bootbox, categorySelector, api, alerts, translator) {
const Module = {};
Module.init = function () {
@@ -95,6 +96,21 @@ define('admin/settings/activitypub', [
modal.find('input').focus();
});
// help text
const updateHelp = async (key, el) => {
const text = await translator.translate(`[[admin/settings/activitypub:rules.help-${key}]]`);
el.innerHTML = text;
};
const helpTextEl = modal.get(0).querySelector('#help-text');
const typeEl = modal.get(0).querySelector('#type');
updateHelp(modal.get(0).querySelector('#type option').value, helpTextEl);
if (typeEl && helpTextEl) {
typeEl.addEventListener('change', function () {
updateHelp(this.value, helpTextEl);
});
}
// category switcher
categorySelector.init(modal.find('[component="category-selector"]'), {
onSelect: function (selectedCategory) {

View File

@@ -417,6 +417,13 @@ async function assignCategory(post) {
}
break;
}
case 'user': {
if (post.uid === value) {
activitypub.helpers.log(`[activitypub] - Rule match: user ${value}; cid: ${target}`);
return target;
}
}
}
}

View File

@@ -3,6 +3,8 @@
const db = require('../database');
const utils = require('../utils');
const activitypub = require('.');
const Rules = module.exports;
Rules.list = async () => {
@@ -19,6 +21,15 @@ Rules.list = async () => {
Rules.add = async (type, value, cid) => {
const uuid = utils.generateUUID();
// normalize user rule values into a uid
if (type === 'user' && value.indexOf('@') !== -1) {
const response = await activitypub.actors.assert(value);
if (!response) {
throw new Error('[[error:no-user]]');
}
value = await db.getObjectField('handle:uid', String(value).toLowerCase());
}
await Promise.all([
db.setObject(`rid:${uuid}`, { type, value, cid }),
db.sortedSetAdd('categorization:rid', Date.now(), uuid),

View File

@@ -8,13 +8,14 @@
<label class="form-label" for="type">Type</label>
<select class="form-control" name="type" id="type">
<option value="hashtag">Hashtag</option>
<option value="user">User</option>
<!--<option value="content">Content contains...</option>-->
</select>
</div>
<div class="mb-3">
<label class="form-label" for="value">Value</label>
<input type="text" id="value" name="value" title="Value" class="form-control" placeholder="forum">
<p class="form-text">[[admin/settings/activitypub:rules.modal.values-multiple]]</p>
<p class="form-text" id="help-text"></p>
</div>
<div class="mb-3">
<label class="form-label">Category</label>