Changeset 3b43e4c in Klonkt for src/routes/activitypub.js
- Timestamp:
- 08/08/2026 02:33:28 AM (5 weeks ago)
- Branches:
- main
- Children:
- 06bae1e
- Parents:
- 50e80ac
- File:
-
- 1 edited
-
src/routes/activitypub.js (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/activitypub.js
r50e80ac r3b43e4c 317 317 const playbackAllowed = embedsAllowed 318 318 && Guardianship.externalPlaybackAllowed(auth.site.external_playback, isWard); 319 // De rest van de familie (shaer-ahy.1, 8-8): zelfde regel, zelfde plek -- 320 // de poort zit bij de serialisatie, wat dicht is wordt nooit geleverd. 321 const gate = (col) => Guardianship.wardGateAllowed(auth.site[col], isWard); 322 const imagesAllowed = gate('gate_images'); 323 const musicAllowed = gate('gate_music'); 324 const quotesAllowed = gate('gate_quote_cards'); 325 const emojiAllowed = gate('gate_custom_emoji'); 326 const messagesAllowed = gate('gate_messages'); 327 const composeAllowed = gate('gate_compose'); 328 const threadsAllowed = gate('external_threads'); 329 // Emoji dicht raakt ook de bylines: de plaatjes in een naam komen net zo 330 // goed van een vreemde server. De naam zelf blijft, met :shortcode: als tekst. 331 const gateAuthor = (a) => (a && !emojiAllowed ? { ...a, emojis: undefined } : a); 319 332 const rows = AP.getTimeline(auth.site.slug, 60); 320 333 // Eén query voor de hele pagina (shaer-9e9 fase 2): shaer:liked komt uit de … … 338 351 // Friends' media travels along (media_json → AS2 attachment), so the 339 352 // client renders their images/audio like own outbox posts. 340 attachment: AP. timelineAttachments(t.media_json),353 attachment: AP.gateAttachments(AP.timelineAttachments(t.media_json), { images: imagesAllowed, audio: musicAllowed }), 341 354 // The note's preserved tags, so the client can render them: FEP-9098 342 355 // Emoji tags (:shortcode: → image) and FEP-e232 Link tags (quotes / … … 344 357 // when the note has neither. 345 358 tag: (() => { 346 const tags = [...( AP.timelineEmojis(t.emoji_json) ||[]), ...(AP.timelineObjectLinks(t.link_json) || [])];359 const tags = [...(emojiAllowed ? (AP.timelineEmojis(t.emoji_json) || []) : []), ...(AP.timelineObjectLinks(t.link_json) || [])]; 347 360 return tags.length ? tags : undefined; 348 361 })(), … … 350 363 // renders an embedded quote card instead of a bare link. Omitted when the 351 364 // note has no quote or the quoted post could not be resolved. 352 'shaer:quote': AP.timelineQuote(t.quote_json),365 'shaer:quote': quotesAllowed ? AP.timelineQuote(t.quote_json) : undefined, 353 366 // The post author's display info (name / @handle / avatar), so every card 354 367 // gets a byline header like the quote card. attributedTo stays the bare 355 368 // actor URI; this is the resolved presentation Klonkt already stored. 356 'shaer:author': (t.author_name || t.author_handle || t.author_icon) ? {369 'shaer:author': gateAuthor((t.author_name || t.author_handle || t.author_icon) ? { 357 370 name: t.author_name || undefined, handle: t.author_handle || undefined, 358 371 icon: t.author_icon || undefined, url: t.author_url || undefined, 359 372 // FEP-9098: emojis in the display name (":shortcode:"), if any. 360 373 emojis: (() => { try { return t.author_emoji_json ? JSON.parse(t.author_emoji_json) : undefined; } catch { return undefined; } })(), 361 } : undefined ,374 } : undefined), 362 375 // When a followed account boosted this, who did ("X boosted"). Omitted for 363 376 // ordinary posts. 364 'shaer:booster': (t.reblog_name || t.reblog_handle || t.reblog_icon) ? {377 'shaer:booster': gateAuthor((t.reblog_name || t.reblog_handle || t.reblog_icon) ? { 365 378 name: t.reblog_name || undefined, handle: t.reblog_handle || undefined, 366 379 icon: t.reblog_icon || undefined, 367 380 // FEP-9098: emojis in the booster's display name (":shortcode:"), if any. 368 381 emojis: (() => { try { return t.reblog_emoji_json ? JSON.parse(t.reblog_emoji_json) : undefined; } catch { return undefined; } })(), 369 } : undefined ,382 } : undefined), 370 383 // Whether THIS account already liked/boosted the note, so the app's 371 384 // detail-view buttons show the current state (and can toggle/undo). … … 384 397 const me = AP.actorId(base, auth.site.slug); 385 398 const myHandle = (() => { try { return `@${auth.site.slug}@${new URL(base).host}`; } catch { return `@${auth.site.slug}`; } })(); 386 const messages = AP.getDirectMessages(auth.site.slug, 60).map((m) => ({ 399 // Messages dicht (shaer-3ow) sluit vreemden en vrienden, maar NOOIT het 400 // guardian-kanaal: de zwaai en het gesprek na een hulpvraag zijn precies 401 // het kanaal dat het kind veilig houdt, en een poort die dat afsnijdt 402 // beschermt niemand. De hulpvraag zelf gaat aan de innamekant al altijd voor. 403 const guardianUris = (() => { try { return new Set(Guardianship.listGuardians(auth.site.slug).map((g) => g.other_uri)); } catch { return new Set(); } })(); 404 const messages = AP.getDirectMessages(auth.site.slug, 60) 405 .filter((m) => messagesAllowed || m.help_request || guardianUris.has(m.actor_uri)) 406 .map((m) => ({ 387 407 id: `${m.object_uri}#create`, 388 408 type: 'Create', … … 402 422 // groups the note into a conversation. No FEP-e232 link tags here: a 403 423 // mention row keeps the resolved quote, not the raw tags. 404 tag: [{ type: 'Mention', href: me, name: myHandle }, ...( AP.timelineEmojis(m.emoji_json) ||[])],405 attachment: AP. timelineAttachments(m.media_json),424 tag: [{ type: 'Mention', href: me, name: myHandle }, ...(emojiAllowed ? (AP.timelineEmojis(m.emoji_json) || []) : [])], 425 attachment: AP.gateAttachments(AP.timelineAttachments(m.media_json), { images: imagesAllowed, audio: musicAllowed }), 406 426 // FEP-633c: what kind of message this is. The wave is a gentle nudge from 407 427 // a guardian; the help request is the buoy. Both render differently. 408 428 'shaer:wave': m.wave ? true : undefined, 409 429 'shaer:helpRequest': m.help_request ? true : undefined, 410 'shaer:quote': AP.timelineQuote(m.quote_json),411 'shaer:author': (m.actor_name || m.actor_handle || m.actor_icon) ? {430 'shaer:quote': quotesAllowed ? AP.timelineQuote(m.quote_json) : undefined, 431 'shaer:author': gateAuthor((m.actor_name || m.actor_handle || m.actor_icon) ? { 412 432 name: m.actor_name || undefined, handle: m.actor_handle || undefined, 413 433 icon: m.actor_icon || undefined, url: m.actor_url || undefined, 414 434 emojis: (() => { try { return m.actor_emoji_json ? JSON.parse(m.actor_emoji_json) : undefined; } catch { return undefined; } })(), 415 } : undefined ,435 } : undefined), 416 436 'shaer:embed': embedsAllowed ? AP.timelineEmbed(m.embed_json, { playback: playbackAllowed }) : undefined, 417 437 }, … … 475 495 // and not just the picture over it. 476 496 'shaer:externalLinks': playbackAllowed, 497 // De rest van de familie (8-8): de app hoort VOORAF te weten wat hij mag 498 // aanbieden in plaats van het bij de eerste weigering te ontdekken. De 499 // (+) kaart leest shaer:compose al (Barts gate); de rest is er voor de 500 // schermen die nog komen. Serveren wat waar is kost hier niets. 501 'shaer:compose': composeAllowed, 502 'shaer:messages': messagesAllowed, 503 'shaer:images': imagesAllowed, 504 'shaer:music': musicAllowed, 505 'shaer:quoteCards': quotesAllowed, 506 'shaer:customEmoji': emojiAllowed, 507 'shaer:externalThreads': threadsAllowed, 477 508 }, 478 509 // Het merk van wat hierin zit. Geef hem terug als `since` om op het … … 721 752 if (!/^https:\/\//i.test(objectUri)) return res.status(400).json({ error: 'object must be an https URI' }); 722 753 const isWard = (() => { try { return Guardianship.listGuardians(auth.site.slug).length > 0; } catch { return false; } })(); 723 const uit = await AP.getThread(auth.site.slug, objectUri , { isWard });754 const uit = await AP.getThread(auth.site.slug, objectUri); 724 755 if (!uit.found) return res.status(404).json({ error: 'note not reachable' }); 756 // De poortstand komt uit de kolom (shaer-9y2): expliciete 0/1 van de 757 // guardians wint, de automatiek is dicht-voor-een-ward. Dicht is de KRING, 758 // niet niets: antwoorden van al goedgekeurd volk blijven staan, en wat er 759 // buiten valt wordt geteld. Beeld, muziek en emoji gaan door dezelfde 760 // poorten als de tijdlijn -- per verzoek, buiten de threadcache om. 761 const threadsOpen = Guardianship.wardGateAllowed(auth.site.external_threads, isWard); 762 const gate2 = (col) => Guardianship.wardGateAllowed(auth.site[col], isWard); 763 const kring = threadsOpen ? { notes: uit.notes, hidden: 0 } : AP.filterThreadToCircle(auth.site.slug, uit.notes); 764 const imagesOk = gate2('gate_images'), musicOk = gate2('gate_music'), emojiOk = gate2('gate_custom_emoji'); 765 uit.notes = kring.notes.map((n) => ({ 766 ...n, 767 attachment: AP.gateAttachments(n.attachment, { images: imagesOk, audio: musicOk }), 768 tag: emojiOk ? n.tag : AP.stripEmojiTags(n.tag), 769 'shaer:author': (n['shaer:author'] && !emojiOk) ? { ...n['shaer:author'], emojis: undefined } : n['shaer:author'], 770 })); 771 uit.hidden = kring.hidden; 725 772 // Liked/boosted per antwoord, BUITEN de cache om: de genormaliseerde notes 726 773 // mogen twee minuten oud zijn, maar of JIJ iets geliked hebt hoort van nu te
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)