EventBuzz_Backend/scripts/setup-goa-7-8-microsite.js

298 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Align Goa 7–8 Aug microsite with Goa 8–9 Aug format and publish.
*
* Usage:
* node scripts/setup-goa-7-8-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 SOURCE_SUBDOMAIN = 'novel2026-goa-8-9-aug';
const TARGET_EVENT_ID = '6a43e05fdc940a0d6e057f7b';
const TARGET_SUBDOMAIN = 'novel2026-goa-7-8-aug';
const SOURCE_EVENT_ID = '6a4cb75a7475c040cc6f2dd7';
const DEFAULT_CSV = path.join(__dirname, '..', '..', 'novel2026-goa-7-8-aug.csv');
const PUBLIC_WEB_BASE = (process.env.PUBLIC_WEB_BASE || 'https://web.eventbuzz.live').replace(/\/$/, '');
const TARGET = {
name: 'NOVEL Lung Health Summit - Goa - 7th & 8th August 2026',
shortPlace: 'Goa',
dateLabel: '7th & 8th August 2026',
dateShort: 'Aug 7–8, 2026',
countdownDate: '2026-08-07',
scheduleDay1: 'August 7, 2026',
scheduleDay2: 'August 8, 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));
}
function replaceAllStrings(obj, replacements) {
if (obj == null) return obj;
if (typeof obj === 'string') {
let out = obj;
for (const [from, to] of replacements) {
if (from) out = out.split(from).join(to);
}
return out;
}
if (Array.isArray(obj)) return obj.map((item) => replaceAllStrings(item, replacements));
if (typeof obj === 'object') {
const out = {};
for (const [k, v] of Object.entries(obj)) out[k] = replaceAllStrings(v, replacements);
return out;
}
return 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: [TARGET.scheduleDay1, TARGET.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 applyTargetOverrides(config, targetEventId, forms, heroBannerUrl) {
const next = deepClone(config);
next.meta = next.meta || {};
next.meta.title = TARGET.name;
next.meta.eventId = String(targetEventId);
const regUrl = forms.registration
? `${PUBLIC_WEB_BASE}/event/${targetEventId}/form/${forms.registration._id}`
: `${PUBLIC_WEB_BASE}/event/${targetEventId}/register`;
const feedbackUrl = forms.feedback
? `${PUBLIC_WEB_BASE}/event/${targetEventId}/form/${forms.feedback._id}`
: null;
const sections = next.sections || {};
if (sections.hero) {
sections.hero.event_name = `${TARGET.shortPlace} - ${TARGET.dateLabel}`;
sections.hero.date_venue = TARGET.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 = TARGET.countdownDate;
}
}
if (sections.informationBar?.items) {
for (const item of sections.informationBar.items) {
if (item.label === 'Location') item.value = TARGET.location;
if (item.label === 'Date & Time') {
item.value = TARGET.dateShort;
if (item.calendar) {
item.calendar.title = TARGET.name;
item.calendar.start = TARGET.countdownDate;
item.calendar.end = '2026-08-08';
item.calendar.location = TARGET.location;
}
}
}
}
if (sections.event_schedule?.days) {
if (sections.event_schedule.days[0]) sections.event_schedule.days[0].date = TARGET.scheduleDay1;
if (sections.event_schedule.days[1]) sections.event_schedule.days[1].date = TARGET.scheduleDay2;
}
if (sections.map) {
sections.map.embedUrl = `https://maps.google.com/maps?q=${TARGET.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 targetEvent = await Event.findById(TARGET_EVENT_ID).lean();
if (!targetEvent) throw new Error(`Target event not found: ${TARGET_EVENT_ID}`);
const sourceSite = await EventStaticMicrosite.findOne({ subdomain: SOURCE_SUBDOMAIN }).populate('template').lean();
if (!sourceSite) throw new Error(`Source microsite not found: ${SOURCE_SUBDOMAIN}`);
const scheduleDays = loadScheduleFromCsv(csvPath);
const agendaResult = await importNovelScheduleToAgenda(TARGET_EVENT_ID, scheduleDays);
console.log(
`Agenda: deleted ${agendaResult.deleted}, created ${agendaResult.created} session(s) on track ${agendaResult.trackId}`,
);
const existingTarget = await EventStaticMicrosite.findOne({ event: TARGET_EVENT_ID });
const previousTarget = existingTarget ? deepClone(existingTarget.config) : null;
const heroBannerUrl = previousTarget?.sections?.hero?.image?.url || null;
const subdomain = normalizeSubdomain(TARGET_SUBDOMAIN);
const avail = await subdomainAvailability(subdomain, TARGET_EVENT_ID, existingTarget?._id?.toString());
if (!avail.available) throw new Error(avail.message || 'Subdomain not available');
const [registration, feedback, contact] = await Promise.all([
findForm(TARGET_EVENT_ID, 'registration'),
findForm(TARGET_EVENT_ID, 'feedback'),
findContactForm(TARGET_EVENT_ID),
]);
const sourceForms = await Promise.all([
findForm(SOURCE_EVENT_ID, 'registration'),
findForm(SOURCE_EVENT_ID, 'feedback'),
findContactForm(SOURCE_EVENT_ID),
]);
const replacements = [
[SOURCE_EVENT_ID, TARGET_EVENT_ID],
[sourceForms[0]?._id ? String(sourceForms[0]._id) : '', registration?._id ? String(registration._id) : ''],
[sourceForms[1]?._id ? String(sourceForms[1]._id) : '', feedback?._id ? String(feedback._id) : ''],
['NOVEL Lung Health Summit - Goa - 8th & 9th August 2026', TARGET.name],
['Goa - 8th & 9th August 2026', `${TARGET.shortPlace} - ${TARGET.dateLabel}`],
['Aug 8–9, 2026', TARGET.dateShort],
].filter(([from]) => from);
let config = replaceAllStrings(sourceSite.config, replacements);
config = applyScheduleToConfig(config, scheduleDays);
config = applyTargetOverrides(config, TARGET_EVENT_ID, { registration, feedback, contact }, heroBannerUrl);
const user = shouldPublish ? await findPublishUser() : null;
const templateId = sourceSite.template?._id || sourceSite.template;
const payload = {
event: targetEvent._id,
organization: targetEvent.organization,
subdomain,
template: templateId,
config,
updatedBy: user?._id,
};
let siteDoc;
if (existingTarget) {
Object.assign(existingTarget, payload);
existingTarget.markModified('config');
await existingTarget.save();
siteDoc = existingTarget;
console.log(`Updated microsite ${existingTarget._id}`);
} else {
siteDoc = await EventStaticMicrosite.create({ ...payload, status: 'draft' });
console.log(`Created microsite ${siteDoc._id}`);
}
console.log(`Event: ${targetEvent.name}`);
console.log(`Subdomain: ${subdomain}`);
console.log(`Template: ${sourceSite.template?.slug || templateId}`);
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(siteDoc._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);
});