Ignore:
Timestamp:
08/06/2026 07:02:57 AM (5 weeks ago)
Author:
Claude (agent) <aiclaude@…>
Branches:
main
Children:
84ce988
Parents:
99a7b40
git-author:
Robin <roboburr@…> (08/06/2026 07:02:56 AM)
git-committer:
Claude (agent) <aiclaude@…> (08/06/2026 07:02:57 AM)
Message:

Antwoorden vanuit een gesprek, rijk, met de zwaai als eigen knop

Berichten kon je gesprekken tonen maar er niet in antwoorden. Het invoerveld dat
er stond was msg-quickreply: platte tekst, 200 tekens, en het verstuurde geen
antwoord maar een zwaai (deliverDirectNote met wave:true, een FEP-633c-seintje).
Dat is iets anders dat toevallig op een reply leek.

Onder elke draad staat nu de gedeelde reply-editor, ingeklapt achter een
"Reageer" -- open onder elk gesprek maakt de lijst weer onleesbaar, precies wat
deze weergave moest oplossen. De zwaai blijft ernaast als eigen knop, want een
seintje en een antwoord horen niet op een hoop.

/messages/reply kiest het pad op wat de draad zelf meedraagt (replyTo):

  • draad aan een post -> deliverReply op het nieuwste ontvangen bericht erin, met een controle dat die parent ook echt bij die post hoort; anders kon een aangepast formulier een antwoord onder andermans draad hangen.
  • draad aan een persoon -> een direct bericht terug.

Voor dat tweede pad kon deliverDirectNote nog geen rijke inhoud: het escapete
platte tekst. Het accepteert nu html, door dezelfde sanitizer als deliverReply,
zodat een antwoord uit Berichten via één poort gaat. De mention-anker blijft een
eigen alinea vooraan, want de ontvanger moet genoemd staan ook als de inhoud met
een kop of lijst begint. Levert de sanitizer niets bruikbaars op, dan valt het
terug op de escaped tekst -- een leeggepoetste editor mag geen leeg bericht
versturen.

Meldingen in nl/en/de erbij, en getNotifications geeft nu het interactie-id en
de actor-uri mee, want zonder die twee weet een antwoord niet waar het heen moet.

Geverifieerd op dev: beide draden daar adresseren hun eigen tegenpartij, het
formulier draagt de juiste verborgen velden en de zwaai staat er los naast.
Suite 412/412.

Co-Authored-By: Claude Opus 5 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r99a7b40 r189e335  
    653653    for (const m of listOutbox(slug).slice(0, need)) {
    654654      items.push({
    655         type: 'sent', outboxId: m.id, to_handle: m.to_handle, to_actors: m.to_actors,
     655        type: 'sent', outboxId: m.id, to_handle: m.to_handle, to_actor: m.to_actor, to_actors: m.to_actors,
    656656        in_reply_to: m.in_reply_to, post_slug: m.post_slug, content: m.content,
    657657        editable: m.editable, language: m.language, created_at: m.created_at,
     
    785785    // onbeantwoord bericht leest.
    786786    t.mine = t.messages.some((m) => m.type === 'sent');
     787    // Waar gaat een antwoord uit deze draad heen? Twee paden, en ze sluiten
     788    // elkaar uit: hangt de draad aan een post, dan antwoord je op het NIEUWSTE
     789    // ontvangen bericht erin (dat is de parent van de thread) -- anders is het
     790    // een direct bericht aan de tegenpartij.
     791    const inkomend = t.messages.filter((m) => m.type !== 'sent');
     792    const laatste = inkomend[inkomend.length - 1];
     793    t.replyTo = {
     794      interactionId: (laatste && laatste.interactionId) || null,
     795      postSlug: (t.post && t.post.slug) || null,
     796      actorUri: (laatste && (laatste.actorUri || laatste.url))
     797        || (t.messages.find((m) => m.to_actor) || {}).to_actor
     798        || (() => { try { return JSON.parse((t.messages.find((m) => m.to_actors) || {}).to_actors || '[]')[0] || null; } catch { return null; } })(),
     799    };
    787800  }
    788801  return out;
     
    44294442  try {
    44304443    const rows = db.prepare(`
    4431       SELECT i.kind, i.actor_name, i.actor_handle, i.actor_url, i.actor_icon, i.content, i.created_at, i.published, i.visibility,
     4444      SELECT i.id AS interaction_id, i.kind, i.actor_uri, i.actor_name, i.actor_handle, i.actor_url, i.actor_icon, i.content, i.created_at, i.published, i.visibility,
    44324445             i.emoji_json, i.actor_emoji_json, i.media_json, i.quote_json, i.embed_json,
    44334446             p.slug AS post_slug, p.title AS post_title
     
    44384451    for (const r of rows) out.push({
    44394452      type: r.kind, name: r.actor_name, handle: r.actor_handle, url: r.actor_url, icon: r.actor_icon,
     4453      // Waar een antwoord uit de draad heen moet: het id is de parent voor
     4454      // deliverReply, de uri het adres voor een direct bericht.
     4455      interactionId: r.interaction_id, actorUri: r.actor_uri,
    44404456      content: stripLeadingMentions(r.content), post_slug: r.post_slug, post_title: r.post_title, created_at: r.created_at,
    44414457      // When the post was written, for display. created_at (when it reached us)
     
    46714687  getOutboxRow: (id) => iStmts().getO.get(id),
    46724688  buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliver, enqueueDelivery,
     4689  // Rijke directe berichten: dezelfde sanitizer als deliverReply gebruikt, zodat
     4690  // een antwoord uit Berichten door precies één poort gaat.
     4691  sanitizeHtml: (h) => HtmlSanitizerService.sanitize(h),
     4692  htmlToPlainText: (h) => HtmlSanitizerService.toPlainText(h),
    46734693});
    46744694/**
Note: See TracChangeset for help on using the changeset viewer.