Changeset f926d13 in Klonkt for src/routes/posts.js


Ignore:
Timestamp:
08/13/2026 07:37:56 PM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
47db4b5
Parents:
822d16d
Message:

De volglijst als bestand uploaden, niet alleen plakken

Robins vraag bij de echte verhuizing: hij downloadt een CSV en moet hem dan met de
hand openen en de inhoud overplakken. Dat is een omweg die niemand hoort te lopen.

Nu een bestandskiezer naast het plakveld. Multer met memoryStorage, want dit is een
lijstje adressen van een paar kilobyte dat na het lezen niets te zoeken heeft op de
server; op schijf schrijven zou alleen rommel achterlaten. Een gekozen bestand wint
van het plakveld: wie een bestand aanwijst bedoelt dat.

De BOM gaat eraf. Excel zet die voor een CSV, en zonder dat eraf te halen plakt hij
aan het eerste adres vast en is de eerste regel stil onbruikbaar.

En twee redirects in deze route wezen nog naar /following. Dat is de oude pagina
waar niets meer naartoe linkt (zie 822d16d), dus je kwam na een import op een
scherm waar je zelf niet meer weg kon. Beide naar /connect.

Changed files:
src/routes/posts.js

  • multer memoryStorage, single('csvfile'), 512kb, 1 bestand
  • bestand wint van plakveld, BOM eraf
  • drie redirects van /following naar /connect

src/views/pages/connect.ejs

  • bestandskiezer met accept=".csv,text/csv,text/plain", formulier op multipart

src/services/i18n.js

  • tl.move_import_file in nl, en en de; het plakveld-label ingekort tot "Of plak de lijst hier"

test/following-csv.test.js

  • test 14: een echt multipart-verzoek met een BOM ervoor, plus de controle dat het plakveld ernaast blijft werken

remarks: 927 groen in UTC en Europe/Amsterdam. De uploadweg is met een echte
multipart-POST tegen een draaiende express+multer getest, niet alleen beredeneerd.
De pagina apart gerenderd: bestandskiezer en multipart-enctype aanwezig, geen
onvertaalde sleutels.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r822d16d rf926d13  
    12941294  const { followingCsv } = await import('../services/ArchiveExportService.js');
    12951295  const csv = site ? followingCsv(site.slug) : null;
    1296   if (!csv) return res.redirect('/following?error=' + encodeURIComponent('Je volgt nog niemand'));
     1296  if (!csv) return res.redirect('/connect?error=' + encodeURIComponent('Je volgt nog niemand'));
    12971297  res.set('Content-Type', 'text/csv; charset=utf-8');
    12981298  res.set('Content-Disposition', `attachment; filename="following-${site.slug}.csv"`);
     
    13021302});
    13031303
    1304 router.post('/news/following/import', requireSiteManager, express.urlencoded({ extended: false, limit: '256kb' }), async (req, res) => {
    1305   const site = res.locals.site;
    1306   const csv = (req.body && req.body.csv) || '';
    1307   if (!site || !String(csv).trim()) return res.redirect('/following?error=' + encodeURIComponent('Geen lijst ontvangen'));
     1304// Een bestand OF geplakte tekst. Multer leest een multipart-formulier, en dat
     1305// bevat allebei: het bestandsveld en het tekstveld. In het geheugen, niet op
     1306// schijf: dit is een lijstje adressen van een paar kilobyte dat na het lezen
     1307// niets meer te zoeken heeft op de server.
     1308const followingCsvUpload = multer({
     1309  storage: multer.memoryStorage(),
     1310  limits: { fileSize: 512 * 1024, files: 1 },
     1311}).single('csvfile');
     1312
     1313router.post('/news/following/import', requireSiteManager, followingCsvUpload, async (req, res) => {
     1314  const site = res.locals.site;
     1315  // Een geupload bestand wint van het plakveld: wie een bestand kiest bedoelt dat.
     1316  const csv = (req.file && req.file.buffer)
     1317    ? req.file.buffer.toString('utf8').replace(/^/, '')   // BOM eraf; Excel zet die erin
     1318    : ((req.body && req.body.csv) || '');
     1319  if (!site || !String(csv).trim()) return res.redirect('/connect?error=' + encodeURIComponent('Geen lijst ontvangen'));
    13081320
    13091321  const { importFollowing } = await import('../services/ArchiveImportService.js');
     
    13261338    delen.push(`${r.mislukt.length} mislukt (${namen}${r.mislukt.length > 3 ? '…' : ''})`);
    13271339  }
    1328   res.redirect('/following?' + (r.mislukt.length ? 'error=' : 'success=') + encodeURIComponent(delen.join(', ')));
     1340  // Terug naar /connect: daar staat het blok, /following is de oude pagina.
     1341  res.redirect('/connect?' + (r.mislukt.length ? 'error=' : 'success=') + encodeURIComponent(delen.join(', ')));
    13291342});
    13301343
Note: See TracChangeset for help on using the changeset viewer.