source: Klonkt/src/views/pages/admin-migrate.ejs@ f894be5

main
Last change on this file since f894be5 was f894be5, checked in by Robin <roboburr@…>, 4 weeks ago

De helft van de outbox, hotlinks in de tekst, en een lege images-tab

Robin na de echte fetch: 18 van de 35 berichten binnen, alle plaatjes
hotlinken naar de oude site, en de images-tab is leeg. Drie oorzaken, en de
eerste was de pijnlijkste omdat hij zonder één waarschuwing "klaar" meldde.

DE KALE OUTBOX IS EEN VALSTRIK. Klonkt zet er first EN een kopie van pagina 1
in (Pleroma eiste ooit een first, sindsdien staan ze er allebei). De ingest
zag items op de kale collectie, sloeg first over, vond daarna geen next (dat
veld bestaat alleen op echte pagina's) en dacht klaar te zijn. Precies 18 van
de 35, en "ingest klaar" in het log. Nu wordt de keten ALTIJD via first
gevolgd, en telt de ingest na: meldt de bron meer items dan er verwerkt zijn,
dan staat dat in het verslag.

PLAATJES IN DE TEKST BLEVEN HOTLINKS. De gebakken content draagt absolute
verwijzingen naar de bron, in img en in de href eromheen. Die worden nu
gedownload naar HETZELFDE pad onder onze mediamap en relatief herschreven.
Hetzelfde pad is drie reparaties in een: de verwijzingen in de tekst kloppen,
de zip en de pull convergeren op dezelfde bestanden, en de images-tab (die de
MAP post-images scant, niet de databasetabel) is niet langer leeg.

BESTAANDE POSTS WORDEN GEREPAREERD. Robins 18 staan er al, met hotlinks en
zonder cover. Een tweede ronde herschrijft hun tekst, haalt de bestanden
binnen en vult de cover aan. Overslaan is voortaan alleen voor posts waar
niets aan mankeert.

En onderweg twee eigen missers gevonden en gedicht:

  • de regex voor het herschrijven stond als string in een template literal; \s verloor zijn backslash en werd de LETTER s, dus elke URL met een s erin (post-images!) knapte af. De waarschuwing ".../media/po" gaf hem weg.
  • haalBijlage plakte /media/ voor een pad dat al met /media/ begon.

Gemeten op twee instanties met 28 posts, elk met cover en inline plaatje:
28/28 binnen, 0 hotlinks, 28 covers met bestand, post-images-map 28 stuks, en
de reparatieronde maakt een met opzet kapotgemaakte post weer heel.

Changed files:
src/services/MigrationService.js

  • first wordt altijd gevolgd; natellen tegen totalItems
  • bronMediaPad(): bron-media naar hetzelfde pad hier, met ../-bewaking
  • inhoudMediaBinnen(): alle bron-media in de tekst binnenhalen en relatief maken; idempotent
  • bestaande posts: tekst gerepareerd en cover aangevuld op een tweede ronde
  • de dubbele /media/ en de opgegeten backslash

src/views/pages/admin-migrate.ejs

  • "berichten gerepareerd" in het ophaalverslag

src/services/i18n.js

  • mig.r_posts_updated in nl/en/de

test/fep1580-migration.test.js

  • regressietests: de kale-collectie-valstrik, de verzwegen pagina, en het herschrijven van een URL met een s erin, letter voor letter

remarks: de reden dat mijn eigen proef dit nooit zag: mijn nepbron gaf
orderedItems zonder first, precies de vorm die de bug ontweek. En een post met
een ongeldige published_at sloopt de HELE outbox van de bron (unhandled
rejection in buildOutbox); hier gevonden met kapotte testdata, nog niet
gerepareerd. Suite 997 groen; tegenproef op de paginatie en de backslash, en de
eerste tegenproef op die backslash was VALS (sabotage kwam niet aan), daarna
opnieuw met bewijs.

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

  • Property mode set to 100644
File size: 12.0 KB
Line 
1<div class="container mig-wrap">
2 <h1><%= t('mig.title') %></h1>
3 <p class="mig-lead"><%= t('mig.lead') %></p>
4
5 <% if (typeof success !== 'undefined' && success) { %><div class="alert alert-success"><%= success %></div><% } %>
6 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error %></div><% } %>
7
8 <%# ── Exporteren ─────────────────────────────────────────────── %>
9 <section class="mig-card">
10 <h2><%= t('mig.export_title') %></h2>
11 <p class="form-hint"><%= t('mig.export_hint') %></p>
12
13 <% if (telling) { %>
14 <ul class="mig-counts">
15 <li><strong><%= telling.posts %></strong> <%= t('mig.c_posts') %></li>
16 <li><strong><%= telling.replies %></strong> <%= t('mig.c_replies') %></li>
17 <li><strong><%= telling.media %></strong> <%= t('mig.c_media') %></li>
18 <%# Muziek APART tellen, niet onder "media". Dit ontbrak, en juist daardoor
19 kon een export van 140 nummers er als 4,5 MB uitzien zonder dat iemand
20 het merkte: de teller zei "39 mediabestanden" en zweeg over de rest. %>
21 <% if (telling.tracks) { %>
22 <%# Wat er ECHT meegaat, niet hoeveel rijen er in de database staan.
23 "8 nummers" met daaronder "van 3 ontbreekt het bestand" telt niet
24 op; 5 plus die waarschuwing wel. %>
25 <li><strong><%= telling.tracks - (telling.audioMissing || 0) %></strong> <%= t('mig.c_tracks') %></li>
26 <% } %>
27 <% if (telling.playlists) { %>
28 <li><strong><%= telling.playlists %></strong> <%= t('mig.c_playlists') %></li>
29 <% } %>
30 <% if (typeof telling.following === 'number') { %>
31 <li><strong><%= telling.following %></strong> <%= t('mig.c_following') %></li>
32 <% } %>
33 <li><strong><%= mb(telling.bytes) %></strong> <%= t('mig.c_size') %></li>
34 </ul>
35
36 <% if (telling.ontbrekend) { %>
37 <%# Niets stils: media die op schijf ontbreekt wordt geteld en gemeld, want
38 een archief dat stilzwijgend minder bevat is erger dan een waarschuwing. %>
39 <p class="alert alert-error"><%= t('mig.missing', { n: telling.ontbrekend }) %></p>
40 <% } %>
41
42 <% if (telling.audioMissing) { %>
43 <%# Een eigen zin voor muziek. "N mediaverwijzingen" zei niets over de
44 vraag die er toe doet: gaat mijn bibliotheek mee. %>
45 <p class="alert alert-error"><%= t('mig.audio_missing', { n: telling.audioMissing }) %></p>
46 <% } %>
47
48
49 <% if (telling.groot) { %>
50 <p class="alert alert-error"><%= t('mig.too_big') %></p>
51 <% } else { %>
52 <p><a class="btn btn-primary" href="/admin/migrate/export"><%= t('mig.export_btn') %></a></p>
53 <% } %>
54 <% } else { %>
55 <p class="form-hint"><%= t('mig.export_none') %></p>
56 <% } %>
57 </section>
58
59 <%# ── Rechtstreeks ophalen (FEP-1580) ────────────────────────── %>
60 <section class="mig-card">
61 <h2><%= t('mig.pull_title') %></h2>
62 <p class="form-hint"><%= t('mig.pull_hint') %></p>
63
64 <% if (haalVerslag) { %>
65 <div class="mig-report<%= haalVerslag.error ? '' : ' is-done' %>">
66 <% if (haalVerslag.error) { %>
67 <h3><%= t('mig.pull_failed') %></h3>
68 <%# Elke weigering krijgt een eigen zin. "Er ging iets mis" laat je
69 raden welke van de twee kanten van de afspraak ontbreekt, en dat
70 is precies wat je moet weten om het op te lossen. %>
71 <p><%= t('mig.e_' + haalVerslag.error) !== 'mig.e_' + haalVerslag.error
72 ? t('mig.e_' + haalVerslag.error) : (haalVerslag.melding || haalVerslag.error) %></p>
73 <% if (haalVerslag.error === 'not_moved_here' && haalVerslag.movedTo) { %>
74 <p class="form-hint"><%= t('mig.e_points_at') %> <code><%= haalVerslag.movedTo %></code></p>
75 <% } %>
76 <% } else { %>
77 <h3><%= t('mig.pull_done') %></h3>
78 <ul class="mig-counts">
79 <li><strong><%= haalVerslag.posts %></strong> <%= t('mig.r_imported') %></li>
80 <% if (haalVerslag.overgeslagen) { %><li><strong><%= haalVerslag.overgeslagen %></strong> <%= t('mig.r_skipped') %></li><% } %>
81 <% if (haalVerslag.media) { %><li><strong><%= haalVerslag.media %></strong> <%= t('mig.r_media') %></li><% } %>
82 <% if (haalVerslag.blocks) { %><li><strong><%= haalVerslag.blocks %></strong> <%= t('mig.r_blocks') %></li><% } %>
83 <% if (haalVerslag.tracksBinnen) { %><li><strong><%= haalVerslag.tracksBinnen %></strong> <%= t('mig.c_tracks') %></li><% } %>
84 <%# Aangevuld telt apart van nieuw. Een tweede ronde die "0 erbij"
85 meldt terwijl hij drie nummers compleet maakte, leest als niets
86 gedaan. %>
87 <% if (haalVerslag.tracksBijgewerkt) { %><li><strong><%= haalVerslag.tracksBijgewerkt %></strong> <%= t('mig.r_tracks_updated') %></li><% } %>
88 <% if (haalVerslag.postsBijgewerkt) { %><li><strong><%= haalVerslag.postsBijgewerkt %></strong> <%= t('mig.r_posts_updated') %></li><% } %>
89 <% if (haalVerslag.playlistsBinnen) { %><li><strong><%= haalVerslag.playlistsBinnen %></strong> <%= t('mig.c_playlists') %></li><% } %>
90 </ul>
91 <% if (haalVerslag.tracksMislukt) { %>
92 <p class="alert alert-error"><%= t('mig.r_tracks_missing', { n: haalVerslag.tracksMislukt }) %></p>
93 <% } %>
94 <% } %>
95 <% if (haalVerslag.waarschuwingen && haalVerslag.waarschuwingen.length) { %>
96 <ul class="mig-warnlist">
97 <% haalVerslag.waarschuwingen.slice(0, 6).forEach(function (w) { %><li><%= w %></li><% }); %>
98 </ul>
99 <% } %>
100 </div>
101 <% } %>
102
103 <form method="post" action="/admin/migrate/pull">
104 <label for="mig-bron"><%= t('mig.pull_source') %></label>
105 <input type="url" id="mig-bron" name="bron" value="<%= bron || '' %>"
106 placeholder="https://oude-klonkt.nl/ap/users/jij" class="mig-input">
107 <p class="form-hint"><%= t('mig.pull_source_hint') %></p>
108 <button type="submit" class="btn"><%= t('mig.pull_btn') %></button>
109 </form>
110
111 <% if (mig && (mig.total || mig.moves)) { %>
112 <p class="form-hint mig-state">
113 <%= t('mig.state', { n: mig.total }) %>
114 <%= mig.complete ? t('mig.state_done') : t('mig.state_busy') %>
115 </p>
116 <% } %>
117 </section>
118
119 <%# ── Importeren ─────────────────────────────────────────────── %>
120 <section class="mig-card">
121 <h2><%= t('mig.import_title') %></h2>
122 <p class="form-hint"><%= t('mig.import_hint') %></p>
123
124 <% if (verslag) { %>
125 <div class="mig-report<%= verslag.echt ? ' is-done' : '' %>">
126 <h3><%= verslag.echt ? t('mig.r_done') : t('mig.r_dry') %></h3>
127 <p class="form-hint"><%= verslag.bestand %> &middot; <%= mb(verslag.bytes) %></p>
128 <ul class="mig-counts">
129 <li><strong><%= verslag.posts %></strong> <%= verslag.echt ? t('mig.r_imported') : t('mig.r_would') %></li>
130 <li><strong><%= verslag.overgeslagen %></strong> <%= t('mig.r_skipped') %></li>
131 <% if (verslag.overschreven) { %><li><strong><%= verslag.overschreven %></strong> <%= t('mig.r_overwritten') %></li><% } %>
132 <% if (verslag.mediaMissing) { %><li><strong><%= verslag.mediaMissing %></strong> <%= t('mig.r_media_missing') %></li><% } %>
133 <% if (verslag.media) { %><li><strong><%= verslag.media %></strong> <%= t('mig.r_media') %></li><% } %>
134 <%# Ook hier: muziek apart. Zonder deze twee regels zie je aan de
135 ontvangende kant net zo min of je bibliotheek is aangekomen. %>
136 <% if (verslag.tracks) { %><li><strong><%= verslag.tracks %></strong> <%= t('mig.c_tracks') %></li><% } %>
137 <% if (verslag.playlists) { %><li><strong><%= verslag.playlists %></strong> <%= t('mig.c_playlists') %></li><% } %>
138 </ul>
139 <% if (verslag.tracksMissing) { %>
140 <p class="alert alert-error"><%= t('mig.r_tracks_missing', { n: verslag.tracksMissing }) %></p>
141 <% } %>
142 <% if (verslag.waarschuwingen && verslag.waarschuwingen.length) { %>
143 <ul class="mig-warnlist">
144 <% verslag.waarschuwingen.slice(0, 6).forEach(function (w) { %><li><%= w %></li><% }); %>
145 </ul>
146 <% } %>
147 <% if (verslag.idsBehouden === false) { %>
148 <%# Dit is de belangrijkste regel van het hele verslag: komt het archief
149 van een ANDER adres, dan krijgen de posts nieuwe id's en zijn het
150 nieuwe objecten voor de fediverse. %>
151 <p class="alert alert-error"><%= t('mig.r_new_ids') %></p>
152 <% } %>
153
154 <% if (!verslag.echt && verslag.posts > 0) { %>
155 <form method="post" action="/admin/migrate/import" enctype="multipart/form-data" class="mig-confirm">
156 <p class="form-hint"><%= t('mig.r_confirm_hint') %></p>
157 <label for="mig-file2"><%= t('mig.file_label') %></label>
158 <input type="file" id="mig-file2" name="archief" accept=".zip,application/zip" required>
159 <input type="hidden" name="echt" value="1">
160 <% if (verslag.overschrijf) { %><input type="hidden" name="overschrijf" value="1"><% } %>
161 <button type="submit" class="btn btn-primary"><%= t('mig.r_confirm_btn') %></button>
162 </form>
163 <% } %>
164 </div>
165 <% } %>
166
167 <form method="post" action="/admin/migrate/import" enctype="multipart/form-data">
168 <label for="mig-file"><%= t('mig.file_label') %></label>
169 <input type="file" id="mig-file" name="archief" accept=".zip,application/zip" required>
170
171 <label class="mig-check">
172 <input type="checkbox" name="overschrijf" value="1">
173 <%= t('mig.overwrite_label') %>
174 </label>
175 <p class="form-hint mig-warn"><%= t('mig.overwrite_hint') %></p>
176
177 <button type="submit" class="btn"><%= t('mig.check_btn') %></button>
178 <p class="form-hint"><%= t('mig.check_hint') %></p>
179 </form>
180 </section>
181
182 <%# ── Wie je volgt ────────────────────────────────────────────── %>
183 <section class="mig-card">
184 <h2><%= t('mig.follows_title') %></h2>
185 <p class="form-hint"><%= t('mig.follows_hint') %></p>
186 <p><a class="btn" href="/connect"><%= t('mig.follows_btn') %></a></p>
187 </section>
188</div>
189
190<style>
191 .mig-wrap { max-width: 46rem; }
192 .mig-lead { color: var(--sub); margin-bottom: 1.5rem; }
193 .mig-card { border: 1px solid var(--rule); border-radius: 12px; padding: 1.25rem 1.4rem; margin-bottom: 1.25rem; }
194 .mig-card h2 { margin: 0 0 .35rem; font-size: 1.1rem; }
195 .mig-counts { list-style: none; padding: 0; margin: .9rem 0; display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
196 .mig-counts li { color: var(--sub); font-size: .94rem; }
197 .mig-counts strong { color: var(--ink); font-size: 1.05rem; }
198 .mig-card label { display: block; margin: .9rem 0 .35rem; font-weight: 600; font-size: .92rem; }
199 .mig-card input[type="file"] { display: block; margin-bottom: .6rem; }
200 .mig-check { display: flex; align-items: center; gap: .5rem; font-weight: 400 !important; }
201 .mig-input { width: 100%; max-width: 34rem; padding: .5rem .6rem; border: 1px solid var(--rule);
202 border-radius: 8px; background: transparent; color: var(--ink); font-size: .95rem; }
203 .mig-state { margin-top: .9rem; }
204 .mig-report code { word-break: break-all; font-size: .88rem; }
205 .mig-warn { color: var(--accent); }
206 .mig-report { border-left: 3px solid var(--accent); padding: .8rem 1rem; margin-bottom: 1.2rem;
207 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); border-radius: 0 8px 8px 0; }
208 .mig-report.is-done { border-left-color: #3fa843; }
209 .mig-report h3 { margin: 0 0 .3rem; font-size: 1rem; }
210 .mig-warnlist { margin: .5rem 0; padding-left: 1.2rem; color: var(--accent); font-size: .9rem; }
211 .mig-confirm { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--rule); }
212</style>
Note: See TracBrowser for help on using the repository browser.