Changeset 737ea05 in Klonkt
- Timestamp:
- 07/01/2026 07:26:13 PM (2 months ago)
- Branches:
- main
- Children:
- 9e1b1bb
- Parents:
- 1c2dcba
- Files:
-
- 7 edited
-
CHANGELOG.de.md (modified) (1 diff)
-
CHANGELOG.md (modified) (1 diff)
-
CHANGELOG.nl.md (modified) (1 diff)
-
src/config/database.js (modified) (1 diff)
-
src/services/ActivityPubService.js (modified) (3 diffs)
-
src/services/i18n.js (modified) (3 diffs)
-
src/views/pages/fedi-notifications.ejs (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG.de.md
r1c2dcba r737ea05 8 8 ### Hinzugefügt 9 9 - **Einen Beitrag im Fediverse melden.** Von einem Fediverse-Beitrag aus kannst du ihn jetzt den 10 Moderatoren seines Heimatservers melden, mit optionaler Begründung. 10 Moderatoren seines Heimatservers melden, mit optionaler Begründung — und meldet jemand deine Seite, 11 erscheint die Meldung in deinen Fediverse-Benachrichtigungen. 11 12 - **Sprache eines Beitrags festlegen.** Wähle, in welcher Sprache du einen Beitrag geschrieben hast — 12 13 im Fediverse funktionieren damit der Sprachfilter der Timeline und die Übersetzen-Schaltfläche. -
CHANGELOG.md
r1c2dcba r737ea05 8 8 ### Added 9 9 - **Report a post to the fediverse.** From a fediverse post you can now report it to the moderators 10 of its own home server, with an optional reason. 10 of its own home server, with an optional reason — and if someone reports your site, the report 11 shows up in your fediverse notifications. 11 12 - **Set a post's language.** Choose the language you wrote a post in — on the fediverse it enables 12 13 timeline language filtering and the translate button. -
CHANGELOG.nl.md
r1c2dcba r737ea05 8 8 ### Toegevoegd 9 9 - **Rapporteer een post op de fediverse.** Vanaf een fediverse-post kun je die nu melden bij de 10 moderators van de eigen server van die post, met een optionele reden. 10 moderators van de eigen server van die post, met een optionele reden — en meldt iemand jouw site, 11 dan verschijnt die melding in je fediverse-meldingen. 11 12 - **Stel de taal van een post in.** Kies in welke taal je een post schreef — op de fediverse 12 13 werkt daarmee het taalfilter van de tijdlijn en de vertaal-knop. -
src/config/database.js
r1c2dcba r737ea05 347 347 ); 348 348 CREATE INDEX IF NOT EXISTS idx_poll_votes_post ON poll_votes(post_id); 349 CREATE TABLE IF NOT EXISTS ap_reports ( 350 id INTEGER PRIMARY KEY AUTOINCREMENT, 351 slug TEXT NOT NULL, -- our site the report is about (its owner moderates) 352 actor_uri TEXT, -- the reporter's actor URI 353 actor_name TEXT, actor_handle TEXT, actor_icon TEXT, 354 content TEXT, -- the reason (plain text) 355 objects TEXT, -- JSON array of reported object URIs (our actor + statuses) 356 seen INTEGER DEFAULT 0, 357 created_at DATETIME DEFAULT CURRENT_TIMESTAMP 358 ); 359 CREATE INDEX IF NOT EXISTS idx_ap_reports_slug ON ap_reports(slug, created_at); 349 360 `); 350 361 // "Feature" a followed account: its posts show in the local Cirkel. -
src/services/ActivityPubService.js
r1c2dcba r737ea05 936 936 // Blocked actor/domain → silently drop (202, don't reveal the block). 937 937 if (claimedActor && isBlockedAny(claimedActor)) { console.log('[AP] inbox dropped (blocked)', claimedActor, 'from', ip); return 202; } 938 const GATED = ['Create', 'Like', 'Announce', 'Follow', 'Delete', 'Undo', 'Accept', 'Reject', 'Add', 'Remove', 'Update' ];938 const GATED = ['Create', 'Like', 'Announce', 'Follow', 'Delete', 'Undo', 'Accept', 'Reject', 'Add', 'Remove', 'Update', 'Flag']; 939 939 if (GATED.includes(type)) { 940 940 if (!verified || !claimedActor || verified.id !== claimedActor) { … … 942 942 return 401; 943 943 } 944 } 945 946 // A moderation report (Flag) about our content — store it for the targeted site's owner 947 // (each Klonkt site is moderated by its own owner). Signature is enforced (GATED). 948 if (type === 'Flag') { 949 const objs = Array.isArray(act.object) ? act.object : (act.object ? [act.object] : []); 950 const objectUris = objs.map((o) => (typeof o === 'string' ? o : (o && o.id))).filter(Boolean); 951 let targetSlug = null; 952 const noteIds = []; 953 for (const u of objectUris) { 954 const s = slugFromActorUrl(u); // one of our actors? 955 if (s) { targetSlug = targetSlug || s; continue; } 956 const pid = postIdFromNoteUrl(u, base); // one of our notes? 957 if (pid) noteIds.push(pid); 958 } 959 if (!targetSlug && noteIds.length) { 960 try { const r = db.prepare('SELECT s.slug FROM posts p JOIN sites s ON s.id = p.site_id WHERE p.id = ? LIMIT 1').get(noteIds[0]); if (r) targetSlug = r.slug; } catch { /* ignore */ } 961 } 962 if (!targetSlug) return 202; // not about us / can't tell → drop 963 const ai = actorInfo(await resolveActor(claimedActor).catch(() => null), claimedActor); 964 try { 965 db.prepare('INSERT INTO ap_reports (slug, actor_uri, actor_name, actor_handle, actor_icon, content, objects, created_at) VALUES (?,?,?,?,?,?,?,CURRENT_TIMESTAMP)') 966 .run(targetSlug, claimedActor || null, ai.name, ai.handle, ai.icon, HtmlSanitizerService.toPlainText(act.content || '').slice(0, 3000), JSON.stringify(objectUris.slice(0, 20))); 967 console.log('[AP] report received for', targetSlug, 'from', claimedActor); 968 } catch { /* ignore */ } 969 return 202; 944 970 } 945 971 … … 2110 2136 }); 2111 2137 } catch { /* ignore */ } 2138 try { 2139 for (const r of db.prepare('SELECT actor_uri, actor_name, actor_handle, actor_icon, content, created_at FROM ap_reports WHERE slug = ? ORDER BY created_at DESC LIMIT 50').all(slug)) { 2140 out.push({ type: 'report', name: r.actor_name, handle: r.actor_handle, url: r.actor_uri, icon: r.actor_icon, content: r.content, created_at: r.created_at }); 2141 } 2142 } catch { /* ignore */ } 2112 2143 out.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); 2113 2144 return out.slice(0, limit || 60); -
src/services/i18n.js
r1c2dcba r737ea05 28 28 'nav.language': 'Taal', 29 29 'nav.notifications': 'Meldingen', 30 'notif.title': 'Meldingen', 'notif.empty': 'Nog geen meldingen.', 'notif.someone': 'Iemand', 'notif.followed': 'volgt je nu', 'notif.liked': 'likete je post', 'notif.boosted': 'boostte je post', 'notif.replied': 'reageerde op', ' blk.title': 'Blokkeren', 'blk.lead': 'Blokkeer een account of een heel domein — hun reacties, likes en posts verdwijnen en nieuwe worden geweigerd.', 'blk.block_btn': 'Blokkeren', 'blk.empty': 'Niks geblokkeerd.', 'blk.unblock': 'Deblokkeren', 'tl.block': 'Blokkeer',30 'notif.title': 'Meldingen', 'notif.empty': 'Nog geen meldingen.', 'notif.someone': 'Iemand', 'notif.followed': 'volgt je nu', 'notif.liked': 'likete je post', 'notif.boosted': 'boostte je post', 'notif.replied': 'reageerde op', 'notif.reported': 'rapporteerde je bij hun server', 'blk.title': 'Blokkeren', 'blk.lead': 'Blokkeer een account of een heel domein — hun reacties, likes en posts verdwijnen en nieuwe worden geweigerd.', 'blk.block_btn': 'Blokkeren', 'blk.empty': 'Niks geblokkeerd.', 'blk.unblock': 'Deblokkeren', 'tl.block': 'Blokkeer', 31 31 'notif.reply': '{actor} reageerde op je reactie', 'notif.comment': '{actor} reageerde op je post', 'notif.like': '{actor} vindt je post leuk', 32 32 'switch.agenda': 'Agenda', … … 959 959 'nav.language': 'Language', 960 960 'nav.notifications': 'Notifications', 961 'notif.title': 'Notifications', 'notif.empty': 'No notifications yet.', 'notif.someone': 'Someone', 'notif.followed': 'followed you', 'notif.liked': 'liked your post', 'notif.boosted': 'boosted your post', 'notif.replied': 'replied to', ' blk.title': 'Blocking', 'blk.lead': 'Block an account or a whole domain — their replies, likes and posts disappear and new ones are refused.', 'blk.block_btn': 'Block', 'blk.empty': 'Nothing blocked.', 'blk.unblock': 'Unblock', 'tl.block': 'Block',961 'notif.title': 'Notifications', 'notif.empty': 'No notifications yet.', 'notif.someone': 'Someone', 'notif.followed': 'followed you', 'notif.liked': 'liked your post', 'notif.boosted': 'boosted your post', 'notif.replied': 'replied to', 'notif.reported': 'reported you to their server', 'blk.title': 'Blocking', 'blk.lead': 'Block an account or a whole domain — their replies, likes and posts disappear and new ones are refused.', 'blk.block_btn': 'Block', 'blk.empty': 'Nothing blocked.', 'blk.unblock': 'Unblock', 'tl.block': 'Block', 962 962 'notif.reply': '{actor} replied to your comment', 'notif.comment': '{actor} commented on your post', 'notif.like': '{actor} liked your post', 963 963 'switch.agenda': 'Agenda', … … 1881 1881 'nav.language': 'Sprache', 1882 1882 'nav.notifications': 'Benachrichtigungen', 1883 'notif.title': 'Benachrichtigungen', 'notif.empty': 'Noch keine Benachrichtigungen.', 'notif.someone': 'Jemand', 'notif.followed': 'folgt dir jetzt', 'notif.liked': 'gefällt dein Beitrag', 'notif.boosted': 'teilte deinen Beitrag', 'notif.replied': 'antwortete auf', ' blk.title': 'Blockieren', 'blk.lead': 'Blockiere ein Konto oder eine ganze Domain — ihre Antworten, Likes und Beiträge verschwinden und neue werden abgelehnt.', 'blk.block_btn': 'Blockieren', 'blk.empty': 'Nichts blockiert.', 'blk.unblock': 'Entsperren', 'tl.block': 'Blockieren',1883 'notif.title': 'Benachrichtigungen', 'notif.empty': 'Noch keine Benachrichtigungen.', 'notif.someone': 'Jemand', 'notif.followed': 'folgt dir jetzt', 'notif.liked': 'gefällt dein Beitrag', 'notif.boosted': 'teilte deinen Beitrag', 'notif.replied': 'antwortete auf', 'notif.reported': 'hat dich bei ihrem Server gemeldet', 'blk.title': 'Blockieren', 'blk.lead': 'Blockiere ein Konto oder eine ganze Domain — ihre Antworten, Likes und Beiträge verschwinden und neue werden abgelehnt.', 'blk.block_btn': 'Blockieren', 'blk.empty': 'Nichts blockiert.', 'blk.unblock': 'Entsperren', 'tl.block': 'Blockieren', 1884 1884 'notif.reply': '{actor} hat auf deinen Kommentar geantwortet', 'notif.comment': '{actor} hat deinen Beitrag kommentiert', 'notif.like': '{actor} gefällt dein Beitrag', 1885 1885 'switch.agenda': 'Termine', -
src/views/pages/fedi-notifications.ejs
r1c2dcba r737ea05 7 7 <ul class="nt-list"> 8 8 <% items.forEach(function(n){ 9 var _ic = n.type === 'follow' ? 'follow' : (n.type === 'like' ? 'like' : (n.type === 'announce' ? 'boost' : 'reply'));9 var _ic = n.type === 'follow' ? 'follow' : (n.type === 'like' ? 'like' : (n.type === 'announce' ? 'boost' : (n.type === 'report' ? 'report' : 'reply'))); 10 10 %> 11 11 <li class="nt-item nt-<%= _ic %>"> … … 14 14 <% } else if (_ic === 'boost') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg> 15 15 <% } else if (_ic === 'follow') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg> 16 <% } else if (_ic === 'report') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg> 16 17 <% } else { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><% } %> 17 18 </span> … … 26 27 <% } else if (n.type === 'like') { %><%= t('notif.liked') %> 27 28 <% } else if (n.type === 'announce') { %><%= t('notif.boosted') %> 29 <% } else if (n.type === 'report') { %><%= t('notif.reported') %> 28 30 <% } else { %><%= t('notif.replied') %><% } %> 29 31 <% if (n.post_slug) { %><a class="nt-post" href="/<%= n.post_slug %>"><%= n.post_title || n.post_slug %></a><% } %> 30 32 </div> 31 <% if (n.type === 'reply' && n.content) { %><div class="nt-content"><%- n.content %></div><% } %> 33 <% if (n.type === 'report' && n.content) { %><div class="nt-content"><%= n.content %></div> 34 <% } else if (n.type === 'reply' && n.content) { %><div class="nt-content"><%- n.content %></div><% } %> 32 35 </div> 33 36 </li> … … 55 58 .nt-boost .nt-icon { background: color-mix(in srgb, #2fa85a 16%, transparent); color: #2fa85a; } 56 59 .nt-follow .nt-icon, .nt-reply .nt-icon { background: color-mix(in srgb, var(--accent, #888) 16%, transparent); color: var(--accent, #06c); } 60 .nt-report .nt-icon { background: color-mix(in srgb, #c0392b 16%, transparent); color: #c0392b; } 57 61 .nt-body { flex: 1; min-width: 0; } 58 62 .nt-line { display: flex; align-items: baseline; gap: .4rem; }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)