EventBuzz_Backend/scripts/backfill-tenant-organizatio...

90 lines
3.2 KiB
JavaScript

/**
* Backfill tenant fields for multi-tenant consistency (run BEFORE deploying required schema).
* - Form.tenantOrganization from linked Event.organization
* - FormSubmission.tenantOrganization from parent Form
* - Logs Speaker rows missing organization (fix manually or delete)
*
* Run: cd backend && npm run backfill:tenant-organization
*/
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const mongoose = require('mongoose');
const Form = require(path.join(__dirname, '..', 'src', 'models', 'Form'));
const FormSubmission = require(path.join(__dirname, '..', 'src', 'models', 'FormSubmission'));
const Event = require(path.join(__dirname, '..', 'src', 'models', 'Event'));
const Speaker = require(path.join(__dirname, '..', 'src', 'models', 'Speaker'));
async function run() {
const uri = process.env.MONGODB_URI;
if (!uri) {
console.error('MONGODB_URI is not set');
process.exit(1);
}
await mongoose.connect(uri);
const formsNeedingTenant = await Form.find({
$or: [{ tenantOrganization: { $exists: false } }, { tenantOrganization: null }],
})
.select('_id event')
.lean();
let formsUpdated = 0;
for (const f of formsNeedingTenant) {
if (!f.event) {
console.warn(`Form ${f._id} has no event and no tenantOrganization — skipped`);
continue;
}
const ev = await Event.findById(f.event).select('organization').lean();
if (!ev?.organization) {
console.warn(`Form ${f._id} event ${f.event} has no organization — skipped`);
continue;
}
await Form.updateOne({ _id: f._id }, { $set: { tenantOrganization: ev.organization } });
formsUpdated += 1;
}
console.log(`Backfilled tenantOrganization on ${formsUpdated} form(s).`);
const subsNeedingTenant = await FormSubmission.find({
$or: [{ tenantOrganization: { $exists: false } }, { tenantOrganization: null }],
})
.select('_id form')
.lean();
let subsUpdated = 0;
for (const s of subsNeedingTenant) {
const form = await Form.findById(s.form).select('tenantOrganization').lean();
if (!form?.tenantOrganization) {
console.warn(`Submission ${s._id} form ${s.form} has no tenantOrganization — skipped`);
continue;
}
await FormSubmission.updateOne({ _id: s._id }, { $set: { tenantOrganization: form.tenantOrganization } });
subsUpdated += 1;
}
console.log(`Backfilled tenantOrganization on ${subsUpdated} form submission(s).`);
const orphanSpeakers = await Speaker.countDocuments({
$or: [{ organization: { $exists: false } }, { organization: null }],
});
if (orphanSpeakers > 0) {
console.warn(
`${orphanSpeakers} speaker(s) have no organization — assign org or delete before schema requires it.`,
);
const sample = await Speaker.find({ $or: [{ organization: { $exists: false } }, { organization: null }] })
.select('_id email firstName lastName')
.limit(10)
.lean();
console.warn('Sample:', JSON.stringify(sample, null, 2));
} else {
console.log('All speakers have an organization.');
}
await mongoose.disconnect();
console.log('Done.');
}
run().catch((e) => {
console.error(e);
process.exit(1);
});