#!/usr/bin/env node /** * Seed the EventUp microsite-v2 template: upload files to S3 and create MicrositeV2Template row. * * Usage: node scripts/seed-microsite-v2-template.js [--user-id=] * * Requires: MONGODB_URI, AWS_* env vars (or will create DB row only with --db-only) */ require('dotenv').config(); const fs = require('fs'); const path = require('path'); const mongoose = require('mongoose'); const AdmZip = require('adm-zip'); const { connectDB } = require('../src/config/database'); const MicrositeV2Template = require('../src/models/MicrositeV2Template'); const User = require('../src/models/User'); const { uploadTemplateFile, uploadTemplateAsset, templateAssetsBaseUrl, } = require('../src/utils/s3MicrositeV2'); const { parseTemplateSchema } = require('../src/utils/templateSchema'); const SLUG = 'event-up'; const TEMPLATE_DIR = path.join(__dirname, '..', 'microsite-v2-templates', SLUG); const TEMPLATE_ASSETS = path.join(TEMPLATE_DIR, 'assets'); const EVENT_UP_ASSETS = path.join(__dirname, '..', '..', 'microsites', 'event-up', 'assets'); async function findSeedUser(userIdArg) { if (userIdArg) { const u = await User.findById(userIdArg); if (u) return u; } const superAdmin = await User.findOne({ role: 'super_admin' }).sort({ createdAt: 1 }); if (superAdmin) return superAdmin; throw new Error('No super_admin user found. Pass --user-id='); } function walkDir(dir, base = dir) { const files = []; if (!fs.existsSync(dir)) return files; for (const name of fs.readdirSync(dir)) { const full = path.join(dir, name); const stat = fs.statSync(full); if (stat.isDirectory()) { files.push(...walkDir(full, base)); } else { files.push({ full, rel: path.relative(base, full).replace(/\\/g, '/') }); } } return files; } function mimeFor(filePath) { if (filePath.endsWith('.css')) return 'text/css'; if (filePath.endsWith('.js')) return 'application/javascript'; if (filePath.endsWith('.woff') || filePath.endsWith('.woff2')) return 'font/woff2'; if (filePath.endsWith('.png')) return 'image/png'; if (filePath.endsWith('.jpg') || filePath.endsWith('.jpeg')) return 'image/jpeg'; if (filePath.endsWith('.svg')) return 'image/svg+xml'; return 'application/octet-stream'; } async function main() { const dbOnly = process.argv.includes('--db-only'); const userIdArg = (process.argv.find((a) => a.startsWith('--user-id=')) || '').split('=')[1]; await connectDB(); const user = await findSeedUser(userIdArg); console.log(`Using user: ${user.email || user._id}`); const htmlPath = path.join(TEMPLATE_DIR, 'template.html'); const jsonPath = path.join(TEMPLATE_DIR, 'template.json'); if (!fs.existsSync(htmlPath) || !fs.existsSync(jsonPath)) { throw new Error(`Missing template files in ${TEMPLATE_DIR}`); } const htmlBuf = fs.readFileSync(htmlPath); const jsonBuf = fs.readFileSync(jsonPath); const schema = parseTemplateSchema(jsonBuf); let htmlS3Key; let schemaS3Key; let thumbnailUrl; let assetsBaseUrl = templateAssetsBaseUrl(SLUG); if (!dbOnly && process.env.AWS_BUCKET) { console.log('Uploading template.html...'); const htmlUp = await uploadTemplateFile(SLUG, 'template.html', htmlBuf, 'text/html; charset=utf-8'); htmlS3Key = htmlUp.s3Key; console.log('Uploading template.json...'); const jsonUp = await uploadTemplateFile(SLUG, 'template.json', jsonBuf, 'application/json'); schemaS3Key = jsonUp.s3Key; const thumbCandidates = [ path.join(TEMPLATE_DIR, 'thumbnail.jpg'), path.join(TEMPLATE_DIR, 'thumbnail.png'), path.join(EVENT_UP_ASSETS, 'img', 'hero.jpg'), ]; for (const tp of thumbCandidates) { if (fs.existsSync(tp)) { const ext = path.extname(tp).slice(1) || 'jpg'; const thumbUp = await uploadTemplateFile( SLUG, `thumbnail.${ext}`, fs.readFileSync(tp), `image/${ext === 'jpg' ? 'jpeg' : ext}`, ); thumbnailUrl = thumbUp.url; break; } } if (!thumbnailUrl) { const placeholder = Buffer.from( 'EventUp', ); const thumbUp = await uploadTemplateFile(SLUG, 'thumbnail.svg', placeholder, 'image/svg+xml'); thumbnailUrl = thumbUp.url; } if (fs.existsSync(EVENT_UP_ASSETS)) { console.log('Uploading assets from event-up...'); const assetFiles = walkDir(EVENT_UP_ASSETS); for (const { full, rel } of assetFiles) { await uploadTemplateAsset(SLUG, rel, fs.readFileSync(full), mimeFor(rel)); } } if (fs.existsSync(TEMPLATE_ASSETS)) { console.log('Uploading template-specific assets (SSR bridge)...'); const overlayFiles = walkDir(TEMPLATE_ASSETS); for (const { full, rel } of overlayFiles) { await uploadTemplateAsset(SLUG, rel, fs.readFileSync(full), mimeFor(rel)); } } assetsBaseUrl = templateAssetsBaseUrl(SLUG); console.log('S3 upload complete.'); } else { console.log('Skipping S3 upload (--db-only or AWS_BUCKET not set).'); } const existing = await MicrositeV2Template.findOne({ slug: SLUG }); const doc = { slug: SLUG, name: 'EventUp Conference', description: 'Full EventUp conference microsite ported from microsites/event-up — hero, schedule, speakers, sponsors, contact, and more.', thumbnailUrl: thumbnailUrl || '', htmlS3Key: htmlS3Key || '', schemaS3Key: schemaS3Key || '', schema, assetsBaseUrl, assetsS3Prefix: `templates/${SLUG}/assets`, isActive: Boolean(htmlS3Key && schemaS3Key), version: 1, createdBy: user._id, }; if (existing) { Object.assign(existing, doc); await existing.save(); console.log(`Updated MicrositeV2Template: ${existing._id}`); } else { const created = await MicrositeV2Template.create(doc); console.log(`Created MicrositeV2Template: ${created._id}`); } await mongoose.disconnect(); console.log('Done.'); } main().catch((err) => { console.error(err); process.exit(1); });