Changeset 3d7312a in Klonkt
- Timestamp:
- 06/24/2026 12:44:21 PM (3 months ago)
- Branches:
- main
- Children:
- 594cc50
- Parents:
- 82079ad
- Location:
- src
- Files:
-
- 1 added
- 6 edited
-
assets/css/style.css (modified) (1 diff)
-
routes/posts.js (modified) (2 diffs)
-
services/ActivityPubService.js (modified) (1 diff)
-
services/i18n.js (modified) (3 diffs)
-
views/pages/authorize-interaction.ejs (added)
-
views/pages/post.ejs (modified) (1 diff)
-
views/shell.ejs (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/css/style.css
r82079ad r3d7312a 4417 4417 .post-fediverse .fedi-reply-toggle::-webkit-details-marker { display: none; } 4418 4418 .post-fediverse details[open] .fedi-reply-toggle { margin-bottom: .5rem; } 4419 4420 /* Reply-via-fediverse CTA on post pages */ 4421 .post-fediverse-cta { margin: 1.75rem 0; } 4422 .fedi-remote-reply-btn { display: inline-flex; align-items: center; gap: .4rem; } -
src/routes/posts.js
r82079ad r3d7312a 86 86 'tag', 'type', 'user', 'users', 'artiesten', 'leden', 'favorieten', 'feed.xml', 'atom.xml', 'sitemap.xml', 87 87 'manifest.webmanifest', 'sw.js', 'favicon.ico', 'favicon.svg', 'assets', 88 'authorize_interaction', 88 89 ]); 89 90 … … 509 510 return { newerPost, olderPost }; 510 511 } 512 513 // ==================== REMOTE INTERACTION (reply to a fediverse post as your site) ==================== 514 // Standard fediverse "reply from your own server" landing endpoint. A post page 515 // elsewhere bounces the visitor here with ?uri=<remote post>; the site owner 516 // composes a reply that federates back to that post. 517 router.get('/authorize_interaction', requireSiteManager, async (req, res) => { 518 const site = res.locals.site; 519 const uri = (req.query.uri || '').toString(); 520 let target = null; 521 try { target = await ActivityPubService.resolveRemoteNote(uri); } catch { /* ignore */ } 522 renderPage(req, res, 'pages/authorize-interaction', { 523 pageTitle: 'Reageer via de fediverse', 524 bodyClass: 'on-special', 525 uri, 526 target, 527 siteTitle: site ? site.title : '', 528 }); 529 }); 530 531 router.post('/authorize_interaction', requireSiteManager, async (req, res) => { 532 const site = res.locals.site; 533 const uri = (req.body.uri || '').toString(); 534 const text = (req.body.text || '').toString(); 535 if (site && uri && text.trim()) { 536 try { 537 const parent = await ActivityPubService.resolveRemoteNote(uri); 538 if (parent) await ActivityPubService.deliverReply(site, { postId: '', postSlug: null, parent, text }); 539 } catch (e) { console.warn('[AP] remote reply failed:', e.message); } 540 } 541 // Send them to the post they replied to so they can see the thread. 542 res.redirect(uri && /^https?:\/\//i.test(uri) ? uri : (res.locals.siteUrlBase || '/')); 543 }); 511 544 512 545 // ==================== VIEW POST (last route — catches /:slug) ==================== -
src/services/ActivityPubService.js
r82079ad r3d7312a 477 477 } 478 478 479 // Resolve a remote post URL (any fediverse/Klonkt post) into a reply target. 480 // Returns a parent-shaped object usable by deliverReply(), or null. 481 export async function resolveRemoteNote(url) { 482 if (!/^https?:\/\//i.test(String(url || ''))) return null; 483 const note = await fetchActor(url).catch(() => null); // AP GET (content-negotiates) 484 if (!note || !note.id) return null; 485 const att = note.attributedTo; 486 const actorUri = typeof att === 'string' ? att : (att && att.id); 487 if (!actorUri) return null; 488 const actor = await fetchActor(actorUri).catch(() => null); 489 const ai = actorInfo(actor, actorUri); 490 return { 491 object_uri: note.id, 492 actor_uri: actorUri, 493 actor_url: ai.url, 494 actor_handle: ai.handle, 495 actor_name: ai.name, 496 actor_icon: ai.icon, 497 preview: HtmlSanitizerService.toPlainText(note.content || '').slice(0, 240), 498 }; 499 } 500 479 501 export default { 480 502 getOrCreateKeys, apWants, sendAP, actorId, noteId, 481 503 buildActor, buildNote, buildCreate, buildOutbox, buildFollowers, 482 504 followerCount, deliver, fetchActor, verifyRequest, handleInbox, deliverCreate, deliverDelete, 483 getInteractions, getInteractionById, buildReplyNote, getOutboxNote, deliverReply, 505 getInteractions, getInteractionById, buildReplyNote, getOutboxNote, deliverReply, resolveRemoteNote, 484 506 }; -
src/services/i18n.js
r82079ad r3d7312a 109 109 'fedi.heading': 'Vanuit de fediverse', 'fedi.likes': 'sterren', 'fedi.boosts': 'boosts', 'fedi.replies': 'Reacties uit de fediverse', 110 110 'fedi.reply': 'Reageer', 'fedi.reply_ph': 'Je antwoord aan de fediverse…', 'fedi.send': 'Versturen', 'fedi.you': 'Jij', 111 'fedi.remote_title': 'Reageer via de fediverse', 'fedi.remote_reply': 'Reageer via de fediverse', 'fedi.remote_prompt': 'Je fediverse-adres (bv. @jij@mastodon.social):', 'fedi.remote_notfound': 'Kon die post niet ophalen. Plak de volledige post-URL:', 'fedi.remote_load': 'Ophalen', 'fedi.remote_replying_to': 'Je reageert op', 'fedi.remote_as': 'Wordt verzonden als {site}.', 111 112 'comments.to_start': 'om de conversatie te starten.', 112 113 'comments.reply': 'Reageer', 'comments.delete': 'Verwijder', 'comments.cancel': 'Annuleren', … … 1103 1104 'fedi.heading': 'From the fediverse', 'fedi.likes': 'favourites', 'fedi.boosts': 'boosts', 'fedi.replies': 'Replies from the fediverse', 1104 1105 'fedi.reply': 'Reply', 'fedi.reply_ph': 'Your reply to the fediverse…', 'fedi.send': 'Send', 'fedi.you': 'You', 1106 'fedi.remote_title': 'Reply via the fediverse', 'fedi.remote_reply': 'Reply via the fediverse', 'fedi.remote_prompt': 'Your fediverse address (e.g. @you@mastodon.social):', 'fedi.remote_notfound': 'Could not fetch that post. Paste the full post URL:', 'fedi.remote_load': 'Fetch', 'fedi.remote_replying_to': 'Replying to', 'fedi.remote_as': 'Sent as {site}.', 1105 1107 'comments.to_start': 'to start the conversation.', 1106 1108 'comments.reply': 'Reply', 'comments.delete': 'Delete', 'comments.cancel': 'Cancel', … … 2095 2097 'fedi.heading': 'Aus dem Fediverse', 'fedi.likes': 'Favoriten', 'fedi.boosts': 'Boosts', 'fedi.replies': 'Antworten aus dem Fediverse', 2096 2098 'fedi.reply': 'Antworten', 'fedi.reply_ph': 'Deine Antwort an das Fediverse…', 'fedi.send': 'Senden', 'fedi.you': 'Du', 2099 'fedi.remote_title': 'Über das Fediverse antworten', 'fedi.remote_reply': 'Über das Fediverse antworten', 'fedi.remote_prompt': 'Deine Fediverse-Adresse (z.B. @du@mastodon.social):', 'fedi.remote_notfound': 'Beitrag konnte nicht geladen werden. Füge die vollständige Beitrags-URL ein:', 'fedi.remote_load': 'Laden', 'fedi.remote_replying_to': 'Antwort an', 'fedi.remote_as': 'Wird als {site} gesendet.', 2097 2100 'comments.to_start': 'um das Gespräch zu starten.', 2098 2101 'comments.reply': 'Antworten', 'comments.delete': 'Löschen', 'comments.cancel': 'Abbrechen', -
src/views/pages/post.ejs
r82079ad r3d7312a 135 135 </section> 136 136 <% } %> 137 138 <!-- Reply via the fediverse (remote interaction: bounces to the visitor's own server) --> 139 <% var _postAbsUrl = (typeof ogOrigin !== 'undefined' && ogOrigin ? ogOrigin : '') + (typeof _base !== 'undefined' && _base ? _base : '') + '/' + post.slug; %> 140 <div class="post-fediverse-cta"> 141 <button type="button" class="btn fedi-remote-reply-btn" 142 onclick="(function(){var d=prompt(<%- JSON.stringify(t('fedi.remote_prompt')) %>);if(!d)return;d=d.trim().replace(/^@?[^@\s]*@/,'').replace(/^https?:\/\//i,'').replace(/\/.*$/,'').trim();if(d)location.href='https://'+d+'/authorize_interaction?uri='+encodeURIComponent(<%- JSON.stringify(_postAbsUrl) %>);})()"> 143 🐘 <%= t('fedi.remote_reply') %> 144 </button> 145 </div> 137 146 138 147 <!-- Comments --> -
src/views/shell.ejs
r82079ad r3d7312a 175 175 176 176 <!-- v9 stylesheet (full palette system) --> 177 <link rel="stylesheet" href="/assets/css/style.css?v=3 8">177 <link rel="stylesheet" href="/assets/css/style.css?v=39"> 178 178 179 179 <!-- Audio player styles: loaded on every page so the mini-player works
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)