Changes in / [5a49eba:2365630] in Klonkt
- Files:
-
- 4 edited
-
src/services/ArchiveImportService.js (modified) (2 diffs)
-
src/services/MigrationService.js (modified) (7 diffs)
-
test/archive-import.test.js (modified) (2 diffs)
-
test/fep1580-migration.test.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ArchiveImportService.js
r5a49eba r2365630 285 285 rapport.origin = manifest.origin || null; 286 286 287 // IDENTITEIT. Het INTERNE id blijft altijd (Robins besluit, 14-8). 288 // 289 // Dat is iets anders dan de AP-URI. Die is domeingebonden en wordt hoe dan 290 // ook nieuw: https://nieuw/ap/notes/<id> is een ander adres dan 291 // https://oud/ap/notes/<id>. Je claimt dus niets van een ander door het GUID 292 // te hergebruiken, en je wint dat elke INTERNE verwijzing blijft kloppen: 293 // [[track:]], [[playlist:]] en [[album:]] wijzen na een verhuizing nog naar 294 // het goede ding. 295 // 296 // Voorheen hing dit aan de origin, en alleen voor posts; tracks en playlists 297 // hielden hun id al wel. Die scheve tabel was precies waarom een post uit de 298 // zip met [[track:oud]] naast een nummer uit de pull met een nieuw id kwam te 299 // staan, en je de shorthand als kale tekst in je bericht zag. 300 // 301 // `idsBehouden` gaat hieronder alleen nog over de AP-URI: gelijke origin 302 // betekent dat ook die identiek blijft, en dan valt er niets te vertalen. 287 // IDENTITEIT. Gelijke origin -> de AP-ids blijven, en daarmee vinden de boosts 288 // en antwoorden die er al naar wijzen hun post terug. Anders nieuwe ids, want 289 // een id op andermans domein publiceren is een vervalsingsoppervlak en andere 290 // servers halen het daar toch op. 303 291 const idsBehouden = !!(manifest.origin && eigenOrigin && manifest.origin === eigenOrigin); 304 292 rapport.idsBehouden = idsBehouden; 305 293 if (!idsBehouden) { 306 294 rapport.waarschuwingen.push( 307 `origin verschilt (archief ${manifest.origin || '?'} vs deze site ${eigenOrigin || '?'}): de berichten krijgen een nieuw AP-adres. Hun interne id blijft, dus verwijzingen binnen je site blijven kloppen.`,295 `origin verschilt (archief ${manifest.origin || '?'} vs deze site ${eigenOrigin || '?'}): nieuwe AP-ids, de oude blijven als verwijzing staan`, 308 296 ); 309 297 } … … 319 307 const o = JSON.parse(files.get(pad).toString('utf8')); 320 308 const oudId = decodeURIComponent(String(o.id || '').split('/ap/notes/')[1] || path.basename(pad, '.json')); 321 // Altijd het id uit het archief. Staat er hier al iets met dat id, dan is 322 // dat hetzelfde object, en dat handelt de botsingscontrole hieronder af. 323 const nieuwId = oudId; 309 const nieuwId = idsBehouden ? oudId : randomUUID(); 324 310 idKaart.set(oudId, nieuwId); 325 311 -
src/services/MigrationService.js
r5a49eba r2365630 417 417 if (auteur && auteur !== bronActor.id) continue; // alleen wat van HEM was 418 418 gezien++; 419 // Het interne id BLIJFT (Robins besluit, 14-8). Daarmee is "staat hij 420 // hier al" gewoon een blik in de tabel, en niet iets dat je uit een 421 // aparte mapping moet afleiden. Verwijder je een bericht en haal je 422 // opnieuw op, dan komt het gewoon terug: er staat immers niets meer. 423 const id = ruwId(o.id) || crypto.randomUUID(); 424 if (db.prepare('SELECT 1 FROM posts WHERE id = ? AND site_id = ?').get(id, site.id)) { 425 rapport.overgeslagen++; 426 continue; 427 } 428 if (migrationTarget(site.slug, o.id)) rapport.opnieuw++; // was er, is weg, komt terug 419 // Al binnen? Alleen overslaan als het bericht er OOK nog staat. Heb je 420 // het verwijderd, dan is opnieuw ophalen precies wat je bedoelt, en 421 // een mapping die dat blokkeert is een val: opruimen hielp dan niet, 422 // want de blokkade zat in ap_migration en niet in de posts. 423 const eerderPost = migrationTarget(site.slug, o.id); 424 if (eerderPost) { 425 const postId = String(eerderPost).split('/').pop(); 426 if (db.prepare('SELECT 1 FROM posts WHERE id = ? AND site_id = ?').get(decodeURIComponent(postId), site.id)) { 427 rapport.overgeslagen++; 428 continue; 429 } 430 rapport.opnieuw++; // weg hier, dus opnieuw binnenhalen 431 } 429 432 430 433 // Media eerst, want een post die naar een plaatje wijst dat we niet … … 448 451 } 449 452 453 const id = crypto.randomUUID(); 450 454 const cover = binnen.find((b) => AFBEELDING.test(b.type || '')); 451 455 const rest = binnen.filter((b) => b !== cover); … … 522 526 // Alleen LEGE velden worden gevuld. Wat jij zelf hebt aangepast blijft 523 527 // staan; een migratie hoort je correcties niet terug te draaien. 524 const trackId = ruwId(a.id) || crypto.randomUUID(); 525 { 528 const eerder = migrationTarget(site.slug, a.id); 529 if (eerder) { 530 const lokaalId = String(eerder).split('/').pop(); 526 531 const rij = db.prepare('SELECT id, cover_url, duration, artist FROM audio_tracks WHERE id = ? AND site_id = ?') 527 .get( trackId, site.id);532 .get(lokaalId, site.id); 528 533 if (rij) { 529 534 trackKaart.set(String(a.id), rij.id); // MOET, anders vinden de playlists hem niet … … 552 557 continue; 553 558 } 559 // De rij is weg maar de mapping staat er nog. Dan is opnieuw ophalen 560 // precies wat je wilt, dus we vallen door naar de gewone tak. 554 561 } 555 562 const bron = a.url && (typeof a.url === 'string' ? a.url : (Array.isArray(a.url) ? (a.url[0] && (a.url[0].href || a.url[0])) : a.url.href)); … … 576 583 else rapport.waarschuwingen.push(`hoes niet opgehaald: ${a.name || hoesUrl}`); 577 584 } 585 const trackId = crypto.randomUUID(); 578 586 const mediaId = crypto.randomUUID(); 579 587 try { … … 643 651 continue; 644 652 } 653 // Bestond hij al? Dan dezelfde rij bijwerken. Zonder deze stap levert 654 // elke tweede ronde een dubbele plaat op. 655 const eerderPl = migrationTarget(site.slug, uri); 645 656 // De hoes van de plaat, net als bij een nummer. 646 657 let plHoes = null; … … 654 665 else rapport.waarschuwingen.push(`hoes van playlist niet opgehaald: ${plc.name || uri}`); 655 666 } 656 // Ook hier het id van de bron. Dan blijft [[playlist:<id>]] in een 657 // bericht wijzen, en is een tweede ronde vanzelf dezelfde rij. 658 const plId = ruwId(uri) || crypto.randomUUID(); 667 const plId = (() => { 668 if (!eerderPl) return crypto.randomUUID(); 669 const bestaand = String(eerderPl).split('/').pop(); 670 return db.prepare('SELECT 1 FROM playlists WHERE id = ? AND site_id = ?').get(bestaand, site.id) 671 ? bestaand : crypto.randomUUID(); 672 })(); 659 673 try { 660 674 db.prepare(`INSERT INTO playlists (id, site_id, title, artist, year, kind, cover_url) VALUES (?,?,?,?,?,?,?) -
test/archive-import.test.js
r5a49eba r2365630 126 126 }); 127 127 128 test('een andere origin geeft een nieuw AP-adres, maar het interne id BLIJFT', () => { 129 // Omgedraaid op 14-8 (Robin: "altijd behouden"). Het interne id is niet 130 // hetzelfde als de AP-URI: https://nieuw/ap/notes/<id> is een ander adres dan 131 // https://oud/ap/notes/<id>, dus je claimt niets van een ander door het GUID 132 // te hergebruiken. Wat je wint is dat elke INTERNE verwijzing blijft kloppen. 133 // 134 // Het oude gedrag brak precies dat: een post uit de zip hield 135 // [[track:<oud id>]] in zijn tekst terwijl het nummer een nieuw id kreeg, en 136 // dan zie je de shorthand als kale tekst in je bericht staan. 128 test('een andere origin levert NIEUWE ids op, met een waarschuwing', () => { 129 // Oude ids houden op een ander domein zou objecten publiceren onder een id dat 130 // je niet beheert -- andere servers halen dat daar op, en het is bovendien een 131 // vervalsingsoppervlak. 137 132 leeg(); 138 133 const files = new Map(ARCHIEF.files); … … 141 136 files.set('manifest.json', Buffer.from(JSON.stringify(m))); 142 137 const r = AI.importArchive(files, { slug: 'me' }); 143 assert.equal(r.idsBehouden, false , 'de AP-URI verandert wel, en dat blijft gemeld');138 assert.equal(r.idsBehouden, false); 144 139 assert.match(r.waarschuwingen.join(' '), /origin verschilt/); 145 assert.equal(db.prepare("SELECT COUNT(*) AS n FROM posts WHERE id = 'zwaar'").get().n, 1, 146 'het interne id komt ongewijzigd terug'); 147 assert.equal(db.prepare('SELECT COUNT(*) AS n FROM posts').get().n, 1); 140 assert.equal(db.prepare("SELECT COUNT(*) AS n FROM posts WHERE id = 'zwaar'").get().n, 0); 141 assert.equal(db.prepare('SELECT COUNT(*) AS n FROM posts').get().n, 1, 'wel geimporteerd, met een nieuw id'); 148 142 }); 149 143 -
test/fep1580-migration.test.js
r5a49eba r2365630 481 481 }); 482 482 483 test('de [[track:]]-verwijzing in een bericht blijft naar een bestaand nummer wijzen', async () => {483 test('de [[track:]]-verwijzing in een bericht wordt bijgetrokken', async () => { 484 484 // Wat Robin op TikTik zag: het bericht toonde de shorthand zelf in plaats van 485 485 // een speler. Zijn posts kwamen uit de ZIP (die bewaart posts.content … … 515 515 })); 516 516 517 // DE EIS, ongeacht hoe: na een verhuizing wijst de shorthand naar een nummer518 // dat hier bestaat. Sinds "altijd behouden" (14-8) klopt dat meestal vanzelf,519 // want het id verandert niet meer. Botst het id wel, dan trekt de ingest de520 // tekst bij. Deze test toetst de UITKOMST en niet de route ernaartoe.521 517 const inhoud = db.prepare("SELECT content FROM posts WHERE id = 'pz'").get().content; 522 518 const m = /\[\[track:([^\]]+)\]\]/.exec(inhoud); 523 assert.ok(m, 'de shorthand blijft staan'); 519 assert.ok(m, 'de shorthand blijft staan, alleen het id verandert'); 520 assert.notEqual(m[1], 't-oud', 'het oude id wijst hier nergens heen'); 524 521 const bestaat = db.prepare('SELECT 1 FROM audio_tracks WHERE id = ? AND site_id = ?').get(m[1], 's1'); 525 assert.ok(bestaat, `[[track:${m[1]}]] hoort bij een nummer dat er echt is`); 526 assert.equal(m[1], 't-oud', 'en omdat het id behouden blijft, hoefde er niets herschreven'); 527 }); 528 529 test('botst het track-id wel, dan wordt de tekst bijgetrokken', async () => { 530 // Het vangnet. "Altijd behouden" kan niet als er hier al iets anders met dat 531 // id staat; dan krijgt het nummer een ander id en moet de shorthand mee. 532 const s2 = site({ aliases: [BRON] }); 533 db.prepare(`INSERT INTO posts (id, site_id, author_id, slug, title, content, status, published_at) 534 VALUES ('pb','s1','u1','botsing','Botsing','<p>[[track:t-bots]]</p>','published','2026-08-13T10:00:00Z')`).run(); 535 // Een nummer dat hier AL bestaat onder datzelfde id, van iets anders. 536 db.prepare("INSERT INTO media (id, site_id, filename, mime_type, size, storage_path) VALUES ('mx','s1','x.mp3','audio/mpeg',1,'/x')").run(); 537 db.prepare("INSERT INTO audio_tracks (id, site_id, title, media_id) VALUES ('t-bots','s1','Al van mij','mx')").run(); 538 539 const kaart2 = new Map([ 540 [BRON, { id: BRON, type: 'Person', movedTo: IK, outbox: `${BRON}/outbox`, streams: [`${BRON}/tracks`] }], 541 [`${BRON}/outbox`, { type: 'OrderedCollection', orderedItems: [] }], 542 [`${BRON}/tracks`, { 543 type: 'OrderedCollection', 544 orderedItems: [{ 545 id: `${BRON}/tracks/t-bots`, type: 'Audio', name: 'Van de bron', 546 url: [{ type: 'Link', href: `${BRON}/audio/y.mp3`, mediaType: 'audio/mpeg' }], 547 }], 548 }], 549 ]); 550 await stil(() => Mig.ingestFromSource(s2, { 551 deps: { 552 getJson: async (_slug, url) => kaart2.get(url) || null, 553 noteId: (b, id) => `${b}/ap/notes/${id}`, 554 noteVisibility: AP.noteVisibility, 555 audioRoot: '/nep/audio', mediaRoot: '/nep/media', 556 signHeaders: () => ({ Signature: 'nep' }), 557 safeFetch: async () => ({ ok: true, arrayBuffer: async () => Buffer.from('y'), headers: { get: () => 'audio/mpeg' } }), 558 fs: { mkdirSync() {}, writeFileSync() {} }, 559 path, 560 }, 561 })); 562 // Het bestaande nummer blijft van jou; de tekst wijst naar iets dat bestaat. 563 const inhoud = db.prepare("SELECT content FROM posts WHERE id = 'pb'").get().content; 564 const m = /\[\[track:([^\]]+)\]\]/.exec(inhoud); 565 assert.ok(m); 566 assert.ok(db.prepare('SELECT 1 FROM audio_tracks WHERE id = ? AND site_id = ?').get(m[1], 's1'), 567 'wat er ook gebeurde met het id, de verwijzing wijst naar een bestaand nummer'); 522 assert.ok(bestaat, 'en het nieuwe id hoort bij een nummer dat er echt is'); 568 523 }); 569 524
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)