Files
sena_db_api_layer/scripts/dump-and-sync-teachers.js
2026-01-19 09:33:35 +07:00

268 lines
8.0 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Script: Dump và Sync All Teachers
* Mục đích: Kiểm tra và tạo user_profile cho TẤT CẢ teachers trong hệ thống
*
* Usage:
* node src/scripts/dump-and-sync-teachers.js
* node src/scripts/dump-and-sync-teachers.js --auto-fix
*/
require('dotenv').config();
const { sequelize, TeacherDetail, UserProfile, UsersAuth } = require('../models');
const teacherProfileService = require('../services/teacherProfileService');
async function dumpAllTeachers() {
console.log('📊 Dumping All Teachers Information...\n');
console.log('='.repeat(80));
try {
// Get all teachers (without join to avoid association issues)
const teachers = await TeacherDetail.findAll({
order: [['created_at', 'ASC']],
});
console.log(`\n📈 Total Teachers: ${teachers.length}\n`);
const withProfile = [];
const withoutProfile = [];
const invalidUserId = [];
for (const teacher of teachers) {
const teacherInfo = {
id: teacher.id,
user_id: teacher.user_id,
teacher_code: teacher.teacher_code,
teacher_type: teacher.teacher_type,
status: teacher.status,
created_at: teacher.created_at,
};
// Check if user_id exists in users_auth
const userAuth = await UsersAuth.findByPk(teacher.user_id, {
attributes: ['id', 'username', 'email', 'is_active'],
});
if (!userAuth) {
invalidUserId.push({
...teacherInfo,
issue: 'user_id not found in users_auth',
});
continue;
}
teacherInfo.username = userAuth.username;
teacherInfo.email = userAuth.email;
teacherInfo.is_active = userAuth.is_active;
// Check if profile exists
const userProfile = await UserProfile.findOne({
where: { user_id: teacher.user_id },
});
if (userProfile) {
teacherInfo.profile = {
id: userProfile.id,
full_name: userProfile.full_name,
phone: userProfile.phone,
needs_update: userProfile.etc?.needs_profile_update,
};
withProfile.push(teacherInfo);
} else {
withoutProfile.push(teacherInfo);
}
}
// Display results
console.log('✅ Teachers WITH Profile:', withProfile.length);
if (withProfile.length > 0) {
console.log('\nSample (first 5):');
withProfile.slice(0, 5).forEach((t, i) => {
console.log(` ${i + 1}. ${t.teacher_code} (${t.teacher_type}) - ${t.username}`);
console.log(` Profile: ${t.profile.full_name} | Phone: ${t.profile.phone || 'N/A'}`);
});
if (withProfile.length > 5) {
console.log(` ... and ${withProfile.length - 5} more\n`);
}
}
console.log('\n❌ Teachers WITHOUT Profile:', withoutProfile.length);
if (withoutProfile.length > 0) {
console.log('\nList:');
withoutProfile.forEach((t, i) => {
console.log(` ${i + 1}. ${t.teacher_code} (${t.teacher_type}) - ${t.username} - user_id: ${t.user_id}`);
});
}
console.log('\n⚠ Teachers with Invalid user_id:', invalidUserId.length);
if (invalidUserId.length > 0) {
console.log('\nList:');
invalidUserId.forEach((t, i) => {
console.log(` ${i + 1}. ${t.teacher_code} - ${t.issue} - user_id: ${t.user_id}`);
});
}
console.log('\n' + '='.repeat(80));
return {
total: teachers.length,
withProfile: withProfile.length,
withoutProfile: withoutProfile.length,
invalidUserId: invalidUserId.length,
teachers: {
withProfile,
withoutProfile,
invalidUserId,
}
};
} catch (error) {
console.error('❌ Dump failed:', error.message);
throw error;
}
}
async function autoFixProfiles(teachersData) {
console.log('\n🔧 Starting Auto-Fix for Teachers without Profile...\n');
const { withoutProfile } = teachersData.teachers;
if (withoutProfile.length === 0) {
console.log('✅ No teachers need fixing. All have profiles!\n');
return { success: 0, failed: 0 };
}
console.log(`📋 Processing ${withoutProfile.length} teachers...\n`);
const results = {
success: [],
failed: [],
};
for (const teacher of withoutProfile) {
try {
console.log(`Processing: ${teacher.teacher_code} (${teacher.username})...`);
// Create profile using service
const userProfile = await UserProfile.create({
user_id: teacher.user_id,
full_name: teacherProfileService._generateFullNameFromCode(teacher.teacher_code),
first_name: '',
last_name: '',
phone: '',
date_of_birth: null,
gender: null,
address: '',
school_id: null,
city: '',
district: '',
avatar_url: null,
etc: {
teacher_code: teacher.teacher_code,
teacher_type: teacher.teacher_type,
username: teacher.username,
synced_from: 'dump-and-sync-script',
needs_profile_update: true,
synced_at: new Date().toISOString(),
}
});
results.success.push({
teacher_code: teacher.teacher_code,
username: teacher.username,
user_id: teacher.user_id,
profile_id: userProfile.id,
full_name: userProfile.full_name,
});
console.log(` ✅ Created profile: ${userProfile.full_name}\n`);
} catch (error) {
results.failed.push({
teacher_code: teacher.teacher_code,
username: teacher.username,
error: error.message,
});
console.log(` ❌ Failed: ${error.message}\n`);
}
}
// Summary
console.log('\n' + '='.repeat(80));
console.log('📊 AUTO-FIX SUMMARY');
console.log('='.repeat(80));
console.log(`✅ Success: ${results.success.length}`);
console.log(`❌ Failed: ${results.failed.length}`);
if (results.success.length > 0) {
console.log('\n✅ Successfully Created Profiles:');
results.success.forEach((item, i) => {
console.log(` ${i + 1}. ${item.teacher_code}${item.full_name}`);
console.log(` user_id: ${item.user_id} | profile_id: ${item.profile_id}`);
});
}
if (results.failed.length > 0) {
console.log('\n❌ Failed:');
results.failed.forEach((item, i) => {
console.log(` ${i + 1}. ${item.teacher_code} - ${item.error}`);
});
}
console.log('\n' + '='.repeat(80));
return {
success: results.success.length,
failed: results.failed.length,
details: results,
};
}
async function main() {
console.log('\n🚀 Teacher Profile Dump & Sync Tool\n');
try {
// Parse arguments
const args = process.argv.slice(2);
const autoFix = args.includes('--auto-fix');
// Connect to database
await sequelize.authenticate();
console.log('✅ Database connected\n');
// Step 1: Dump all teachers
const dumpResults = await dumpAllTeachers();
// Step 2: Ask for auto-fix if not specified
if (!autoFix && dumpResults.withoutProfile > 0) {
console.log('\n⚠ Found teachers without profile!');
console.log('💡 Run with --auto-fix to create profiles automatically:');
console.log(' node src/scripts/dump-and-sync-teachers.js --auto-fix\n');
process.exit(0);
}
// Step 3: Auto-fix if requested
if (autoFix && dumpResults.withoutProfile > 0) {
const fixResults = await autoFixProfiles(dumpResults);
console.log('\n🎉 COMPLETED!');
console.log(` Total: ${dumpResults.total} teachers`);
console.log(` Fixed: ${fixResults.success} profiles`);
console.log(` Already had: ${dumpResults.withProfile} profiles`);
console.log(` Failed: ${fixResults.failed} profiles\n`);
} else if (autoFix) {
console.log('\n✅ All teachers already have profiles! Nothing to fix.\n');
}
process.exit(0);
} catch (error) {
console.error('\n❌ Error:', error.message);
console.error(error.stack);
process.exit(1);
}
}
// Run
main();