update
This commit is contained in:
267
scripts/dump-and-sync-teachers.js
Normal file
267
scripts/dump-and-sync-teachers.js
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* 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();
|
||||
Reference in New Issue
Block a user