// One-time backfill: publish any APPROVED submissions that never got a blog // Post (they predate auto-publish-on-approval). Idempotent — already-imported // submissions are skipped, so it is safe to re-run. // // Usage (from backend/): // npm run backfill-submissions import { prisma } from '../src/db/prisma'; import { importPostFromNostr, resolveSubmissionImport } from '../src/services/postImport'; async function main() { const approved = await prisma.submission.findMany({ where: { status: 'APPROVED' }, orderBy: { createdAt: 'asc' }, }); console.log(`Found ${approved.length} APPROVED submission(s).`); let imported = 0; let skipped = 0; let failed = 0; for (const submission of approved) { const label = `"${submission.title}" (${submission.id})`; try { const importInput = await resolveSubmissionImport(submission); if (!importInput) { console.warn(` FAILED ${label}: could not resolve Nostr event from relays.`); failed++; continue; } const existing = await prisma.post.findUnique({ where: { nostrEventId: importInput.nostrEventId }, }); if (existing) { console.log(` SKIP ${label}: already published (slug: ${existing.slug}).`); skipped++; continue; } const post = await importPostFromNostr(importInput); console.log(` IMPORT ${label}: published (slug: ${post?.slug}).`); imported++; } catch (err) { console.error(` FAILED ${label}:`, err); failed++; } } console.log(`\nDone. Imported: ${imported}, Skipped: ${skipped}, Failed: ${failed}.`); } main() .then(async () => { await prisma.$disconnect(); // The Nostr relay pool keeps websockets open, which would otherwise keep the // process alive after the work is done. process.exit(0); }) .catch(async (err) => { console.error('Backfill error:', err); await prisma.$disconnect(); process.exit(1); });