Changeset 971d00b in Klonkt


Ignore:
Timestamp:
08/06/2026 06:48:32 AM (5 weeks ago)
Author:
Claude (agent) <aiclaude@…>
Branches:
main
Children:
99a7b40
Parents:
39111c0
git-author:
Robin <roboburr@…> (08/06/2026 06:48:31 AM)
git-committer:
Claude (agent) <aiclaude@…> (08/06/2026 06:48:32 AM)
Message:

Eigen berichten renderen als post: media meegeven aan note-body

Berichten deelt note-body al met de Krant en de Guardian-PWA, dus opmaak, quotes
en embeds werkten -- maar alleen voor wat je ONTVANGT. Een sent-item kreeg geen
enkel renderveld mee, dus een foto of geluidsfragment dat jij meestuurde kwam
als kale tekst binnen terwijl hetzelfde bericht bij de ander wel een plaatje is.

De oorzaak is een vormverschil dat nooit vertaald werd: note-body leest
media_json met een type, ap_outbox bewaart attachments met een mediaType.
outboxMediaJson vertaalt dat, en geeft null bij niets of rommel -- kapotte JSON
in die kolom mag hooguit de media kosten, nooit het bericht zelf.

Emoji, quote en embed blijven leeg voor eigen berichten: ap_outbox bewaart die
kolommen niet. De HTML-inhoud zelf gaat wel door note-body heen, dus opmaak in
je eigen antwoord werkt al.

Suite 412/412, met een test op de vertaling en een op kapotte invoer.

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

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r39111c0 r971d00b  
    627627// outboxId), sorted as one stream. Consecutive likes/boosts on the same post collapse into
    628628// one grouped item (actors list + count) so activity doesn't drown out conversations.
     629/** ap_outbox.attachments ([{url, mediaType, name}]) naar de vorm die note-body
     630 *  leest (media_json: [{url, type, name}]). Geeft null bij niets of rommel,
     631 *  zodat een kapotte kolom hooguit media kost en niet de hele regel. */
     632function outboxMediaJson(attachments) {
     633  if (!attachments) return null;
     634  try {
     635    const list = JSON.parse(attachments);
     636    if (!Array.isArray(list) || !list.length) return null;
     637    const media = list
     638      .filter((a) => a && a.url)
     639      .map((a) => ({ url: a.url, type: a.mediaType || a.type || '', name: a.name || undefined }));
     640    return media.length ? JSON.stringify(media) : null;
     641  } catch { return null; }
     642}
     643
    629644export function getMessages(slug, limit, offset) {
    630645  const off = Math.max(0, offset || 0);
     
    641656        in_reply_to: m.in_reply_to, post_slug: m.post_slug, content: m.content,
    642657        editable: m.editable, language: m.language, created_at: m.created_at,
     658        // Je eigen bericht hoort er hetzelfde uit te zien als dat van een ander:
     659        // note-body rendert Berichten, de Krant en de Guardian-PWA, maar leest
     660        // media uit media_json met een `type`, terwijl ap_outbox ze als
     661        // `attachments` met een `mediaType` bewaart. Zonder deze vertaling kwam
     662        // een foto die JIJ meestuurde als kale tekst binnen.
     663        media_json: outboxMediaJson(m.attachments),
    643664      });
    644665    }
     
    30203041  // gaat staan (zie threadKey). Zonder die kolom viel een uitwisseling uit
    30213042  // elkaar in "Verzonden" en "Gesprekken".
    3022   return db.prepare('SELECT id, content, to_handle, to_actor, to_actors, post_slug, in_reply_to, language, created_at FROM ap_outbox WHERE site_slug = ? ORDER BY created_at DESC')
     3043  return db.prepare('SELECT id, content, to_handle, to_actor, to_actors, post_slug, in_reply_to, attachments, language, created_at FROM ap_outbox WHERE site_slug = ? ORDER BY created_at DESC')
    30233044    .all(siteSlug).map((r) => { const c = stripLeadingMentions(r.content); return { ...r, content: c, editable: outboxEditableText(c) }; });
    30243045}
  • test/messages-conversations.test.js

    r39111c0 r971d00b  
    132132  assert.equal(a, b, 'dezelfde tegenpartij hoort dezelfde sleutel te geven');
    133133});
     134
     135test('een eigen bericht met media rendert als een post, niet als kale tekst', async () => {
     136  // note-body (gedeeld met de Krant) leest media_json met een `type`; ap_outbox
     137  // bewaart attachments met een `mediaType`. Zonder vertaling viel een foto die
     138  // JIJ meestuurde weg.
     139  const db = (await import('../src/config/database.js')).default;
     140  db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
     141    .run('mu', 'mu', 'mu@test', 'x', 'god');
     142  db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('ms', 'media', 'Media', 'mu');
     143  db.prepare(`INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, to_handle, content, attachments, created_at)
     144    VALUES ('om1','media','pm1','een-post','@anna@a.test','<p>kijk</p>',?,'2026-08-06 09:00:00')`)
     145    .run(JSON.stringify([{ url: '/media/foto.png', mediaType: 'image/png', name: 'foto' }]));
     146
     147  const t = AP.getMessages('media', 50, 0).find((i) => i.type === 'thread');
     148  const sent = t.messages.find((m) => m.type === 'sent');
     149  assert.deepEqual(JSON.parse(sent.media_json), [{ url: '/media/foto.png', type: 'image/png', name: 'foto' }]);
     150});
     151
     152test('een eigen bericht zonder of met kapotte media houdt gewoon zijn tekst', async () => {
     153  const db = (await import('../src/config/database.js')).default;
     154  db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('ms2', 'media2', 'M2', 'mu');
     155  db.prepare(`INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, to_handle, content, attachments, created_at)
     156    VALUES ('om2','media2','pm2','p','@anna@a.test','<p>a</p>','geen json','2026-08-06 09:00:00'),
     157           ('om3','media2','pm3','p','@bo@b.test','<p>b</p>',NULL,'2026-08-06 09:01:00')`).run();
     158  const threads = AP.getMessages('media2', 50, 0).filter((i) => i.type === 'thread');
     159  const alle = threads.flatMap((t) => t.messages);
     160  assert.equal(alle.length, 2, 'geen bericht mag verdwijnen door kapotte media');
     161  for (const m of alle) assert.equal(m.media_json, null);
     162});
Note: See TracChangeset for help on using the changeset viewer.