forked from UKSOURCE/cms.hailearning.edu.vn
179 lines
5.5 KiB
JavaScript
179 lines
5.5 KiB
JavaScript
const mongoose = require('mongoose');
|
|
const Booking = require('../models/booking');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
require('dotenv').config();
|
|
|
|
|
|
|
|
const filePath = path.join(__dirname, '..', 'data', 'booking.json');
|
|
let raw = '{}';
|
|
try {
|
|
raw = fs.readFileSync(filePath, 'utf8');
|
|
} catch (e) {
|
|
console.error('Could not read booking.json at', filePath);
|
|
process.exit(2);
|
|
}
|
|
|
|
let data;
|
|
try {
|
|
data = JSON.parse(raw || '{}');
|
|
} catch (e) {
|
|
console.error('Invalid JSON in booking.json:', e.message);
|
|
process.exit(3);
|
|
}
|
|
|
|
// Remove _id fields recursively to avoid conflicts
|
|
function stripIds(obj) {
|
|
if (Array.isArray(obj)) return obj.map(i => stripIds(i));
|
|
if (obj && typeof obj === 'object') {
|
|
const out = {};
|
|
for (const k in obj) {
|
|
if (k !== '_id') out[k] = stripIds(obj[k]);
|
|
}
|
|
return out;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
data = stripIds(data);
|
|
|
|
// Normalize vouchers to an array of objects so Mongoose casting won't fail
|
|
function normalizeVouchers(doc) {
|
|
if (!doc) return;
|
|
// support root-level `vouchers` and `configuration.vouchers`
|
|
let v = doc.vouchers || (doc.configuration && doc.configuration.vouchers);
|
|
if (!v) return;
|
|
|
|
// Try to parse stringified arrays (may use single quotes or JS literal)
|
|
if (typeof v === 'string') {
|
|
try {
|
|
v = JSON.parse(v);
|
|
} catch (e1) {
|
|
try {
|
|
// try parsing JS object-literal style strings
|
|
// eslint-disable-next-line no-new-func
|
|
v = (new Function('return ' + v))();
|
|
} catch (e2) {
|
|
// fallback: attempt to extract codes by splitting on commas
|
|
v = v.split && v.split(',').map(s => s.trim()).filter(Boolean).map(s => ({ validCodes: s, type: 'unknown', value: null }));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Normalize array items into objects
|
|
if (Array.isArray(v)) {
|
|
v = v.map(item => {
|
|
if (typeof item === 'string') return { validCodes: item, type: 'unknown', value: null };
|
|
if (item && typeof item === 'object') {
|
|
return {
|
|
validCodes: item.validCodes || item.code || '',
|
|
type: item.type || '',
|
|
value: typeof item.value === 'number' ? item.value : (item.amount && Number(item.amount)) || null,
|
|
};
|
|
}
|
|
return item;
|
|
});
|
|
}
|
|
|
|
// If Booking schema expects array of strings, convert objects -> string codes
|
|
try {
|
|
const Booking = require('../models/booking');
|
|
const pathType = Booking.schema.path('vouchers') || Booking.schema.path('configuration.vouchers');
|
|
if (pathType && pathType.instance === 'Array' && pathType.caster && pathType.caster.instance === 'String') {
|
|
const mapped = (v || []).map(it => (typeof it === 'string' ? it : (it && typeof it === 'object' ? it.validCodes || JSON.stringify(it) : String(it))));
|
|
if (doc.vouchers) doc.vouchers = mapped;
|
|
else if (doc.configuration) doc.configuration.vouchers = mapped;
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
// ignore and keep object form
|
|
}
|
|
|
|
if (doc.vouchers) doc.vouchers = v;
|
|
else if (doc.configuration) doc.configuration.vouchers = v;
|
|
}
|
|
|
|
normalizeVouchers(data);
|
|
|
|
// Also normalize discounts (some inputs have them stringified or as objects)
|
|
function normalizeDiscounts(doc) {
|
|
if (!doc) return;
|
|
let d = doc.discounts || (doc.configuration && doc.configuration.discounts);
|
|
if (!d) return;
|
|
|
|
if (typeof d === 'string') {
|
|
try {
|
|
d = JSON.parse(d);
|
|
} catch (e1) {
|
|
try {
|
|
// eslint-disable-next-line no-new-func
|
|
d = (new Function('return ' + d))();
|
|
} catch (e2) {
|
|
d = d.split && d.split('\n').map(s => s.trim()).filter(Boolean).map(s => ({ id: '', name: s }));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Array.isArray(d)) {
|
|
d = d.map(item => {
|
|
if (typeof item === 'string') return { id: '', name: item };
|
|
if (item && typeof item === 'object') return item;
|
|
return item;
|
|
});
|
|
}
|
|
|
|
try {
|
|
const Booking = require('../models/booking');
|
|
const pathType = Booking.schema.path('discounts') || Booking.schema.path('configuration.discounts');
|
|
if (pathType && pathType.instance === 'Array' && pathType.caster && pathType.caster.instance === 'String') {
|
|
const mapped = (d || []).map(it => (typeof it === 'string' ? it : (it.id || it.name || JSON.stringify(it))));
|
|
if (doc.discounts) doc.discounts = mapped;
|
|
else if (doc.configuration) doc.configuration.discounts = mapped;
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
|
|
if (doc.discounts) doc.discounts = d;
|
|
else if (doc.configuration) doc.configuration.discounts = d;
|
|
}
|
|
|
|
normalizeDiscounts(data);
|
|
|
|
const dryRun = process.argv.includes('--dry-run') || process.argv.includes('-n');
|
|
|
|
async function run() {
|
|
try {
|
|
const dbUri = process.env.MONGODB_URI || process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/cms';
|
|
console.log('Using DB URI:', dbUri);
|
|
|
|
if (dryRun) {
|
|
console.log('\nDRY RUN - preview of document to upsert:\n');
|
|
console.log(JSON.stringify(data, null, 2));
|
|
process.exit(0);
|
|
}
|
|
|
|
await mongoose.connect(dbUri, { useNewUrlParser: true, useUnifiedTopology: true });
|
|
console.log('Connected to MongoDB');
|
|
|
|
const result = await Booking.findOneAndUpdate({}, data, {
|
|
upsert: true,
|
|
new: true,
|
|
setDefaultsOnInsert: true,
|
|
});
|
|
|
|
console.log('Upsert complete. Document id:', result._id.toString());
|
|
console.log('Summary: programs=', (data.programs || []).length, 'camps=', (data.camps || []).length);
|
|
|
|
await mongoose.disconnect();
|
|
process.exit(0);
|
|
} catch (err) {
|
|
console.error('Migration failed:', err && err.message ? err.message : err);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
run();
|