Changeset 19430fa in Klonkt for src/services/MigrationService.js


Ignore:
Timestamp:
08/14/2026 12:40:43 AM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
5a49eba
Parents:
919b82d
Message:

GUID's blijven altijd behouden bij een verhuizing

Robin vroeg of we bestaande GUID's hergebruiken. Het antwoord was zes vakjes:

zip ophaalknop

posts nieuw bij andere origin altijd nieuw
tracks OUD BEHOUDEN altijd nieuw
playlists OUD BEHOUDEN altijd nieuw

Vier keer nieuw, twee keer niet, en die twee uitzonderingen waren niet
besloten maar ontstaan: de zip schreef INSERT OR REPLACE met het id uit het
archief zonder dat daar ooit over nagedacht is. Die scheve tabel was precies de
oorzaak van de shortcode die Robin op TikTik zag: post uit de zip met
[[track:oud]], nummer uit de pull met een nieuw id.

Zijn besluit: altijd behouden. Nu is het één regel.

WAAROM DAT MAG. Het interne id is niet de AP-URI. https://nieuw/ap/notes/<id>
is een ander adres dan https://oud/ap/notes/<id>, dus je claimt niets van een
ander door het GUID te hergebruiken. Het oude argument in de code ("een id op
andermans domein publiceren is een vervalsingsoppervlak") haalde die twee door
elkaar. Wat je wint: elke interne verwijzing blijft kloppen, [[track:]],
[[playlist:]] en [[album:]] wijzen na de verhuizing nog naar het goede ding.

Wat NIET verandert is de AP-URI. Die is domeingebonden en hoort nieuw te zijn,
en daar is de migration-collectie voor. idsBehouden gaat voortaan alleen daar
nog over.

Gemeten door dezelfde inhoud via BEIDE routes over elkaar heen te halen:

posts oud 6 | nieuw 6 | zelfde id 6 | afwijkend 0
audio_tracks oud 3 | nieuw 3 | zelfde id 3 | afwijkend 0
playlists oud 1 | nieuw 1 | zelfde id 1 | afwijkend 0

Geen dubbele. Zip en ophaalknop zijn daarmee inwisselbaar geworden, en dat was
eerder de combinatie die stukging.

Changed files:
src/services/ArchiveImportService.js

  • posts houden hun id, ongeacht de origin
  • de waarschuwing zegt nu wat er echt verandert: het AP-adres, niet het id

src/services/MigrationService.js

  • posts, tracks en playlists nemen het id van de bron over
  • "staat hij hier al" is daarmee een blik in de tabel in plaats van een omweg via ap_migration; verwijderen en opnieuw ophalen werkt vanzelf
  • de eerderPl/eerder-omwegen konden weg

test/archive-import.test.js

  • de origin-test omgedraaid: het AP-adres verandert, het id blijft

test/fep1580-migration.test.js

  • de shortcode-test toetst nu de UITKOMST (wijst naar een bestaand nummer) in plaats van de route ernaartoe
  • nieuwe test voor het botsingsgeval, waar het bijtrekken wel nodig is

remarks: het bijtrekken van [[track:]] blijft bestaan als vangnet voor een
botsend id. In het normale geval doet het niets meer, en dat is de bedoeling.
Suite 991 groen.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/MigrationService.js

    r919b82d r19430fa  
    417417        if (auteur && auteur !== bronActor.id) continue;              // alleen wat van HEM was
    418418        gezien++;
    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         }
     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
    432429
    433430        // Media eerst, want een post die naar een plaatje wijst dat we niet
     
    451448        }
    452449
    453         const id = crypto.randomUUID();
    454450        const cover = binnen.find((b) => AFBEELDING.test(b.type || ''));
    455451        const rest = binnen.filter((b) => b !== cover);
     
    526522        // Alleen LEGE velden worden gevuld. Wat jij zelf hebt aangepast blijft
    527523        // staan; een migratie hoort je correcties niet terug te draaien.
    528         const eerder = migrationTarget(site.slug, a.id);
    529         if (eerder) {
    530           const lokaalId = String(eerder).split('/').pop();
     524        const trackId = ruwId(a.id) || crypto.randomUUID();
     525        {
    531526          const rij = db.prepare('SELECT id, cover_url, duration, artist FROM audio_tracks WHERE id = ? AND site_id = ?')
    532             .get(lokaalId, site.id);
     527            .get(trackId, site.id);
    533528          if (rij) {
    534529            trackKaart.set(String(a.id), rij.id);   // MOET, anders vinden de playlists hem niet
     
    557552            continue;
    558553          }
    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.
    561554        }
    562555        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));
     
    583576          else rapport.waarschuwingen.push(`hoes niet opgehaald: ${a.name || hoesUrl}`);
    584577        }
    585         const trackId = crypto.randomUUID();
    586578        const mediaId = crypto.randomUUID();
    587579        try {
     
    651643          continue;
    652644        }
    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);
    656645        // De hoes van de plaat, net als bij een nummer.
    657646        let plHoes = null;
     
    665654          else rapport.waarschuwingen.push(`hoes van playlist niet opgehaald: ${plc.name || uri}`);
    666655        }
    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         })();
     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();
    673659        try {
    674660          db.prepare(`INSERT INTO playlists (id, site_id, title, artist, year, kind, cover_url) VALUES (?,?,?,?,?,?,?)
Note: See TracChangeset for help on using the changeset viewer.