Changeset 67f7150 in Klonkt for test/c2s-compose.test.js


Ignore:
Timestamp:
07/30/2026 11:26:35 AM (6 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
6dd26e5
Parents:
a9da2c0
Message:

C2S Delete voor eigen notes en shaer:author op de eigen outbox

Twee dingen uit de app (Robins verzoek, 30-7). Een: long-press delete op
een eigen post. De C2S outbox accepteert nu Delete voor notes van dit
account: eigen posts (Tombstone naar volgers, dan cascade zoals de
web-route) en eigen outbound replies (via deliverOutboxDelete). Andermans
posts en onbekende notes krijgen een helder 403/404.

Twee: eigen posts hadden in de app geen header. De timeline-entries
dragen shaer:author, maar de eigen outbox-leg niet, dus elke kaart had
een byline behalve je eigen. De outbox zet nu op de friend-leg de eigen
display-info (titel, handle, avatar) als shaer:author op elke note.

Changed files:
src/services/ActivityPubService.js

  • case 'Delete' in ingestOutboxActivity: eigen post -> deliverDelete + cascade (comments, FTS, post); eigen outbox-reply -> tombstone; vreemd -> 403/404
  • selfAuthor(base, site): eigen byline in shaer:author-vorm

src/routes/activitypub.js

  • outbox friend-leg verrijkt elke note met shaer:author

test/c2s-compose.test.js

  • delete-test (eigen wel, andermans niet, onbekend 404) en selfAuthor-test

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/c2s-compose.test.js

    ra9da2c0 r67f7150  
    144144});
    145145
     146test('C2S Delete takes an own post back, and only an own post', async () => {
     147  // Long-press delete in the app (Robins verzoek, 30-7): the child changes
     148  // their mind, the post goes, followers get the Tombstone.
     149  const r = await AP.ingestOutboxActivity(site, user, {
     150    type: 'Create',
     151    object: {
     152      type: 'Note', content: '<p>weg hiermee</p>',
     153      to: ['https://test.example/ap/users/kid/followers'],
     154      cc: ['https://www.w3.org/ns/activitystreams#Public'],
     155    },
     156  });
     157  assert.equal(r.status, 201);
     158  const del = await AP.ingestOutboxActivity(site, user, { type: 'Delete', object: r.url });
     159  assert.equal(del.status, 202, 'an own note deletes');
     160  assert.equal(db.prepare('SELECT COUNT(*) c FROM posts WHERE id = ?').get(r.id).c, 0, 'and the row is gone');
     161
     162  const unknown = await AP.ingestOutboxActivity(site, user, { type: 'Delete', object: 'https://test.example/ap/notes/bestaat-niet' });
     163  assert.equal(unknown.status, 404, 'an unknown note is a clear no');
     164
     165  // Another account's post on this server: refused, row untouched.
     166  db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)').run('u2', 'ander', 'u2@t', 'x', 'user');
     167  db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,0)').run('s2', 'ander', 'ander', 'u2');
     168  db.prepare(`INSERT INTO posts (id, site_id, author_id, slug, title, content, status, published_at, created_at, updated_at)
     169              VALUES ('p-ander', 's2', 'u2', 'n-ander', '', '<p>van een ander</p>', 'published', datetime('now'), datetime('now'), datetime('now'))`).run();
     170  const foreign = await AP.ingestOutboxActivity(site, user, { type: 'Delete', object: 'https://test.example/ap/notes/p-ander' });
     171  assert.equal(foreign.status, 403, "someone else's post is not yours to take back");
     172  assert.equal(db.prepare('SELECT COUNT(*) c FROM posts WHERE id = ?').get('p-ander').c, 1, 'and it stays');
     173});
     174
     175test('selfAuthor: the byline for your own outbox notes', () => {
     176  // The owner's app reads its own posts from the outbox, which carried no
     177  // author info: every card but your own had a header (Robins melding, 30-7).
     178  const me = AP.selfAuthor('https://test.example', site);
     179  assert.equal(me.name, 'kid');
     180  assert.equal(me.handle, '@kid@test.example');
     181});
     182
    146183test('a media-only post is a post, not an empty-note error', async () => {
    147184  const r = await AP.ingestOutboxActivity(site, user, {
Note: See TracChangeset for help on using the changeset viewer.