186 lines
6.5 KiB
JavaScript
186 lines
6.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Seed the CREST NOVEL microsite-v2 template.
|
|
*
|
|
* Usage: node scripts/seed-crest-novel-template.js [--user-id=<mongoId>] [--db-only]
|
|
*/
|
|
require('dotenv').config();
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const mongoose = require('mongoose');
|
|
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 = 'crest-novel';
|
|
const TEMPLATE_DIR = path.join(__dirname, '..', 'microsite-v2-templates', SLUG);
|
|
const TEMPLATE_ASSETS = path.join(TEMPLATE_DIR, 'assets');
|
|
const SOURCE_ASSETS = path.join(__dirname, '..', '..', 'microsites', 'crest-novel', '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=<mongoId>');
|
|
}
|
|
|
|
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')) return 'font/woff';
|
|
if (filePath.endsWith('.woff2')) return 'font/woff2';
|
|
if (filePath.endsWith('.ttf')) return 'font/ttf';
|
|
if (filePath.endsWith('.eot')) return 'application/vnd.ms-fontobject';
|
|
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';
|
|
}
|
|
|
|
/** IcoMoon exports use filenames like LineIcons.woff?y2l643 — normalize for S3 keys. */
|
|
function normalizeAssetRelPath(rel) {
|
|
const base = String(rel).replace(/\\/g, '/');
|
|
const fontsMatch = base.match(/^fonts\/LineIcons\.(woff2?|ttf|eot|svg)\?/i);
|
|
if (fontsMatch) {
|
|
return `fonts/LineIcons.${fontsMatch[1].toLowerCase()}`;
|
|
}
|
|
return base;
|
|
}
|
|
|
|
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(SOURCE_ASSETS, 'img', 'hero.jpg'),
|
|
path.join(SOURCE_ASSETS, 'img', 'novel-logo.png'),
|
|
];
|
|
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(
|
|
'<svg xmlns="http://www.w3.org/2000/svg" width="400" height="240"><rect fill="#015AAA" width="400" height="240"/><text x="50%" y="50%" fill="#fff" text-anchor="middle" dy=".3em" font-family="sans-serif" font-size="22">CREST NOVEL</text></svg>',
|
|
);
|
|
const thumbUp = await uploadTemplateFile(SLUG, 'thumbnail.svg', placeholder, 'image/svg+xml');
|
|
thumbnailUrl = thumbUp.url;
|
|
}
|
|
|
|
const assetRoots = [TEMPLATE_ASSETS, SOURCE_ASSETS];
|
|
for (const root of assetRoots) {
|
|
if (!fs.existsSync(root)) continue;
|
|
console.log(`Uploading assets from ${root}...`);
|
|
for (const { full, rel } of walkDir(root)) {
|
|
const normalizedRel = normalizeAssetRelPath(rel);
|
|
if (normalizedRel !== rel && fs.existsSync(path.join(root, normalizedRel))) {
|
|
continue;
|
|
}
|
|
await uploadTemplateAsset(SLUG, normalizedRel, fs.readFileSync(full), mimeFor(normalizedRel));
|
|
}
|
|
}
|
|
|
|
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: 'CREST NOVEL',
|
|
description:
|
|
'CREST / NOVEL lung health summit microsite — marketing popup, dual about sections, expert videos, tabbed speakers, schedule, sponsors, contact form, and feedback FAB.',
|
|
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);
|
|
});
|