/** * Load novel2026-goa-8-9-aug.csv into microsite + agenda for the 8–9 Aug Goa event. * * Usage: * node scripts/setup-goa-8-9-microsite.js [--publish] [--csv=path] */ const path = require('path'); const fs = require('fs'); require('dotenv').config({ path: path.join(__dirname, '..', '.env') }); const mongoose = require('mongoose'); const { connectDB } = require('../src/config/database'); const Event = require('../src/models/Event'); const Form = require('../src/models/Form'); const EventStaticMicrosite = require('../src/models/EventStaticMicrosite'); const User = require('../src/models/User'); const { normalizeSubdomain, subdomainAvailability } = require('../src/utils/subdomainAvailability'); const { publishStaticMicrosite } = require('../src/utils/publishStaticMicrosite'); const { parseNovelScheduleCsv } = require('../src/utils/parseNovelScheduleCsv'); const { importNovelScheduleToAgenda } = require('../src/utils/importNovelScheduleAgenda'); const EVENT_ID = '6a4cb75a7475c040cc6f2dd7'; const SUBDOMAIN = 'novel2026-goa-8-9-aug'; const DEFAULT_CSV = path.join(__dirname, '..', '..', 'novel2026-goa-8-9-aug.csv'); const PUBLIC_WEB_BASE = (process.env.PUBLIC_WEB_BASE || 'https://web.eventbuzz.live').replace(/\/$/, ''); const EVENT = { name: 'NOVEL Lung Health Summit - Goa - 8th & 9th August 2026', shortPlace: 'Goa', dateLabel: '8th & 9th August 2026', dateShort: 'Aug 8–9, 2026', countdownDate: '2026-08-08', scheduleDay1: 'August 8, 2026', scheduleDay2: 'August 9, 2026', location: 'DoubleTree by Hilton Panjim, Goa', mapQuery: 'DoubleTree+by+Hilton+Goa+Panaji,+Chimbel,+Goa', }; function argValue(name, fallback) { const hit = process.argv.find((a) => a.startsWith(`--${name}=`)); return hit ? hit.split('=').slice(1).join('=').trim() : fallback; } function deepClone(obj) { return JSON.parse(JSON.stringify(obj)); } async function findForm(eventId, type) { return Form.findOne({ event: eventId, type, 'settings.isActive': { $ne: false } }) .sort({ createdAt: 1 }) .select('_id name') .lean(); } async function findContactForm(eventId) { return Form.findOne({ event: eventId, type: 'other', name: /contact/i, 'settings.isActive': { $ne: false } }) .sort({ createdAt: 1 }) .select('_id name') .lean(); } async function findPublishUser() { const platform = await User.findOne({ platform_admin: 'yes', isActive: { $ne: false } }).sort({ createdAt: 1 }); if (platform) return platform; const superAdmin = await User.findOne({ role: 'super_admin' }).sort({ createdAt: 1 }); if (superAdmin) return superAdmin; throw new Error('No user found for publish'); } function loadScheduleFromCsv(csvPath) { if (!fs.existsSync(csvPath)) { throw new Error(`Schedule CSV not found: ${csvPath}`); } const text = fs.readFileSync(csvPath, 'utf8'); const { days } = parseNovelScheduleCsv(text, { dayDates: [EVENT.scheduleDay1, EVENT.scheduleDay2], }); return days; } function applyScheduleToConfig(config, days) { const next = deepClone(config); const sections = next.sections || {}; sections.event_schedule = sections.event_schedule || {}; sections.event_schedule.show = sections.event_schedule.show !== false; sections.event_schedule.heading = sections.event_schedule.heading || 'Event Schedule'; sections.event_schedule.subtitle = sections.event_schedule.subtitle || 'Scientific programme at DoubleTree by Hilton Panjim, Goa.'; sections.event_schedule.days = days; next.sections = sections; return next; } function applyEventOverrides(config, eventId, forms, heroBannerUrl) { const next = deepClone(config); next.meta = next.meta || {}; next.meta.title = EVENT.name; next.meta.eventId = String(eventId); const regUrl = forms.registration ? `${PUBLIC_WEB_BASE}/event/${eventId}/form/${forms.registration._id}` : `${PUBLIC_WEB_BASE}/event/${eventId}/register`; const feedbackUrl = forms.feedback ? `${PUBLIC_WEB_BASE}/event/${eventId}/form/${forms.feedback._id}` : null; const sections = next.sections || {}; if (sections.hero) { sections.hero.event_name = `${EVENT.shortPlace} - ${EVENT.dateLabel}`; sections.hero.date_venue = EVENT.location; if (heroBannerUrl && sections.hero.image) { sections.hero.image.url = heroBannerUrl; } if (sections.hero.cta) { sections.hero.cta.url = regUrl; sections.hero.cta.target = '_blank'; } if (sections.hero.countdown) { sections.hero.countdown.date = EVENT.countdownDate; } } if (sections.informationBar?.items) { for (const item of sections.informationBar.items) { if (item.label === 'Location') item.value = EVENT.location; if (item.label === 'Date & Time') { item.value = EVENT.dateShort; if (item.calendar) { item.calendar.title = EVENT.name; item.calendar.start = EVENT.countdownDate; item.calendar.end = '2026-08-09'; item.calendar.location = EVENT.location; } } } } if (sections.map) { sections.map.embedUrl = `https://maps.google.com/maps?q=${EVENT.mapQuery}&hl=en&z=15&output=embed`; } if (sections.contact && forms.contact) { sections.contact.show = true; sections.contact.formId = String(forms.contact._id); sections.contact.apiBaseUrl = sections.contact.apiBaseUrl || 'https://api.eventbuzz.live/api'; } if (sections.feedback && feedbackUrl) { sections.feedback.url = feedbackUrl; } if (sections.footer?.links) { for (const link of sections.footer.links) { if (link.text && /register/i.test(link.text)) { link.url = regUrl; link.target = '_blank'; } if (link.text && /feedback/i.test(link.text) && feedbackUrl) { link.url = feedbackUrl; link.target = '_blank'; } } } next.sections = sections; return next; } async function main() { const shouldPublish = process.argv.includes('--publish'); const csvPath = argValue('csv', DEFAULT_CSV); await connectDB(); const event = await Event.findById(EVENT_ID).lean(); if (!event) throw new Error(`Event not found: ${EVENT_ID}`); const scheduleDays = loadScheduleFromCsv(csvPath); const agendaResult = await importNovelScheduleToAgenda(EVENT_ID, scheduleDays); console.log( `Agenda: deleted ${agendaResult.deleted}, created ${agendaResult.created} session(s) on track ${agendaResult.trackId}`, ); const existingSite = await EventStaticMicrosite.findOne({ event: EVENT_ID }).populate('template'); if (!existingSite) { throw new Error(`Microsite not found for event ${EVENT_ID}. Run setup-crest-novel-microsite.js first.`); } const heroBannerUrl = existingSite.config?.sections?.hero?.image?.url || null; const subdomain = normalizeSubdomain(SUBDOMAIN); const avail = await subdomainAvailability(subdomain, EVENT_ID, existingSite._id?.toString()); if (!avail.available) throw new Error(avail.message || 'Subdomain not available'); const [registration, feedback, contact] = await Promise.all([ findForm(EVENT_ID, 'registration'), findForm(EVENT_ID, 'feedback'), findContactForm(EVENT_ID), ]); let config = applyScheduleToConfig(existingSite.config, scheduleDays); config = applyEventOverrides(config, EVENT_ID, { registration, feedback, contact }, heroBannerUrl); const user = shouldPublish ? await findPublishUser() : null; Object.assign(existingSite, { subdomain, config, updatedBy: user?._id, }); existingSite.markModified('config'); await existingSite.save(); console.log(`Updated microsite ${existingSite._id}`); console.log(`Event: ${event.name}`); console.log(`Subdomain: ${subdomain}`); console.log(`Template: ${existingSite.template?.slug || existingSite.template}`); console.log(`CSV: ${csvPath}`); console.log(`Reg form: ${registration?._id || '(none)'}`); console.log(`Feedback: ${feedback?._id || '(none)'}`); console.log(`Contact: ${contact?._id || '(none)'}`); if (shouldPublish) { const populated = await EventStaticMicrosite.findById(existingSite._id).populate('template'); const result = await publishStaticMicrosite({ staticMicrosite: populated, template: populated.template, userId: user._id, }); Object.assign(populated, result); await populated.save(); console.log(`Published: ${result.publicUrl}`); } else { console.log('Saved as draft. Re-run with --publish to publish.'); } await mongoose.disconnect(); } main().catch((err) => { console.error(err); process.exit(1); });