This commit is contained in:
silverpro89
2026-01-26 20:23:08 +07:00
parent 53d97ba5db
commit 2c7b4675a7
49 changed files with 12668 additions and 1 deletions

View File

@@ -0,0 +1,237 @@
const fs = require('fs');
const path = require('path');
const { Subject, Chapter, Lesson, sequelize } = require('../models');
/**
* Import MoveUp curriculum data from data/moveup folder
* Structure: data/moveup/g1/unit4.json -> Subject: moveup_grade1 -> Chapter: Unit 4 -> Lessons
*/
async function importMoveUpData() {
const transaction = await sequelize.transaction();
try {
console.log('🚀 Starting MoveUp data import...\n');
const dataPath = path.join(__dirname, '../data/moveup');
const grades = ['g1', 'g2', 'g3', 'g4', 'g5'];
const stats = {
subjects: 0,
chapters: 0,
lessons: 0,
errors: []
};
for (const grade of grades) {
const gradePath = path.join(dataPath, grade);
// Check if grade folder exists
if (!fs.existsSync(gradePath)) {
console.log(`⏭️ Skipping ${grade} - folder not found`);
continue;
}
console.log(`📚 Processing ${grade.toUpperCase()}...`);
// Create Subject for this grade
const gradeNumber = grade.replace('g', '');
const subjectCode = `MOVEUP-G${gradeNumber}`;
const subjectName = `MoveUp Grade ${gradeNumber}`;
let subject = await Subject.findOne({
where: { subject_code: subjectCode },
transaction
});
if (!subject) {
subject = await Subject.create({
subject_code: subjectCode,
subject_name: subjectName,
subject_name_en: `MoveUp Grade ${gradeNumber}`,
description: `English curriculum for Grade ${gradeNumber} - MoveUp series`,
is_active: true,
is_public: true,
is_premium: false
}, { transaction });
stats.subjects++;
console.log(` ✅ Created Subject: ${subjectName} (${subject.id})`);
} else {
console.log(` ⏭️ Subject already exists: ${subjectName} (${subject.id})`);
}
// Read all JSON files in grade folder
const files = fs.readdirSync(gradePath).filter(f => f.endsWith('.json'));
for (const file of files) {
const filePath = path.join(gradePath, file);
const unitNumber = file.replace('unit', '').replace('.json', '');
console.log(` 📖 Processing ${file}...`);
// Create Chapter for this unit
const chapterTitle = `Unit ${unitNumber}`;
let chapter = await Chapter.findOne({
where: {
subject_id: subject.id,
chapter_number: parseInt(unitNumber)
},
transaction
});
if (!chapter) {
chapter = await Chapter.create({
subject_id: subject.id,
chapter_number: parseInt(unitNumber),
chapter_title: chapterTitle,
chapter_description: `Unit ${unitNumber} lessons`,
is_published: true,
display_order: parseInt(unitNumber)
}, { transaction });
stats.chapters++;
console.log(` ✅ Created Chapter: ${chapterTitle} (${chapter.id})`);
} else {
console.log(` ⏭️ Chapter already exists: ${chapterTitle} (${chapter.id})`);
}
// Read lessons from JSON file
let lessonsData;
try {
const fileContent = fs.readFileSync(filePath, 'utf8');
lessonsData = JSON.parse(fileContent);
} catch (error) {
stats.errors.push(`Failed to read ${file}: ${error.message}`);
console.log(` ❌ Error reading ${file}: ${error.message}`);
continue;
}
// Create lessons
for (const lessonData of lessonsData) {
try {
// Check if lesson already exists
const existingLesson = await Lesson.findOne({
where: {
chapter_id: chapter.id,
lesson_number: lessonData.lesson_number
},
transaction
});
if (existingLesson) {
console.log(` ⏭️ Lesson ${lessonData.lesson_number} already exists: ${lessonData.lesson_title}`);
continue;
}
// Normalize content_json based on lesson_content_type
let normalizedContentJson = lessonData.content_json;
if (lessonData.lesson_content_type === 'vocabulary' && lessonData.content_json) {
// Convert vocabulary array to words array for consistency
if (lessonData.content_json.vocabulary && Array.isArray(lessonData.content_json.vocabulary)) {
normalizedContentJson = {
...lessonData.content_json,
type: 'vocabulary',
words: lessonData.content_json.vocabulary
};
}
} else if (lessonData.lesson_content_type === 'grammar' && lessonData.content_json) {
// Normalize grammar content
if (lessonData.content_json.grammar) {
normalizedContentJson = {
...lessonData.content_json,
type: 'grammar',
sentences: Array.isArray(lessonData.content_json.grammar)
? lessonData.content_json.grammar
: [lessonData.content_json.grammar]
};
}
} else if (lessonData.lesson_content_type === 'phonics' && lessonData.content_json) {
// Normalize phonics content
normalizedContentJson = {
...lessonData.content_json,
type: 'phonics',
phonics_rules: lessonData.content_json.letters && lessonData.content_json.sounds ? [
{
letters: lessonData.content_json.letters,
sounds: lessonData.content_json.sounds,
words: lessonData.content_json.vocabulary || []
}
] : []
};
}
// Create lesson
const lesson = await Lesson.create({
chapter_id: chapter.id,
lesson_number: lessonData.lesson_number,
lesson_title: lessonData.lesson_title,
lesson_type: lessonData.lesson_type,
lesson_description: lessonData.lesson_description,
lesson_content_type: lessonData.lesson_content_type,
content_json: normalizedContentJson,
content_url: lessonData.content_url || null,
content_type: lessonData.content_type || null,
is_published: true,
is_free: false,
display_order: lessonData.lesson_number
}, { transaction });
stats.lessons++;
console.log(` ✅ Created Lesson ${lessonData.lesson_number}: ${lessonData.lesson_title}`);
} catch (error) {
stats.errors.push(`Failed to create lesson ${lessonData.lesson_number} in ${file}: ${error.message}`);
console.log(` ❌ Error creating lesson ${lessonData.lesson_number}: ${error.message}`);
}
}
}
console.log(''); // Empty line between grades
}
await transaction.commit();
// Print summary
console.log('\n' + '='.repeat(60));
console.log('📊 IMPORT SUMMARY');
console.log('='.repeat(60));
console.log(`✅ Subjects created: ${stats.subjects}`);
console.log(`✅ Chapters created: ${stats.chapters}`);
console.log(`✅ Lessons created: ${stats.lessons}`);
if (stats.errors.length > 0) {
console.log(`\n❌ Errors encountered: ${stats.errors.length}`);
stats.errors.forEach((err, i) => {
console.log(` ${i + 1}. ${err}`);
});
} else {
console.log('\n🎉 No errors!');
}
console.log('='.repeat(60));
console.log('\n✨ Import completed successfully!\n');
} catch (error) {
await transaction.rollback();
console.error('\n❌ FATAL ERROR during import:', error);
throw error;
}
}
// Run import if called directly
if (require.main === module) {
importMoveUpData()
.then(() => {
console.log('✅ Script completed');
process.exit(0);
})
.catch(error => {
console.error('❌ Script failed:', error);
process.exit(1);
});
}
module.exports = { importMoveUpData };