#!/usr/bin/env node /** * Script zum Aktualisieren der "Familienwörter"-Übungen in Bisaya-Kursen * * Verwendung: * node backend/scripts/update-family-words-exercises.js * * Ersetzt bestehende Dummy-Übungen durch spezifische Familienwörter-Übungen. */ import { sequelize } from '../utils/sequelize.js'; import VocabCourseLesson from '../models/community/vocab_course_lesson.js'; import VocabGrammarExercise from '../models/community/vocab_grammar_exercise.js'; import VocabCourse from '../models/community/vocab_course.js'; import User from '../models/community/user.js'; // Familienwörter-Übersetzungen in verschiedene Muttersprachen const FAMILY_WORDS = { Mutter: { de: 'Mutter', en: 'Mother', es: 'Madre', fr: 'Mère', it: 'Madre', pt: 'Mãe' }, Vater: { de: 'Vater', en: 'Father', es: 'Padre', fr: 'Père', it: 'Padre', pt: 'Pai' }, 'älterer Bruder': { de: 'älterer Bruder', en: 'older brother', es: 'hermano mayor', fr: 'frère aîné', it: 'fratello maggiore', pt: 'irmão mais velho' }, 'ältere Schwester': { de: 'ältere Schwester', en: 'older sister', es: 'hermana mayor', fr: 'sœur aînée', it: 'sorella maggiore', pt: 'irmã mais velha' }, Großmutter: { de: 'Großmutter', en: 'Grandmother', es: 'Abuela', fr: 'Grand-mère', it: 'Nonna', pt: 'Avó' }, Großvater: { de: 'Großvater', en: 'Grandfather', es: 'Abuelo', fr: 'Grand-père', it: 'Nonno', pt: 'Avô' } }; // Bisaya-Übersetzungen const BISAYA_TRANSLATIONS = { 'Mutter': 'Nanay', 'Vater': 'Tatay', 'älterer Bruder': 'Kuya', 'ältere Schwester': 'Ate', 'Großmutter': 'Lola', 'Großvater': 'Lolo' }; // Sprach-Codes für Mapping const LANGUAGE_CODES = { 'Deutsch': 'de', 'English': 'en', 'Español': 'es', 'Français': 'fr', 'Italiano': 'it', 'Português': 'pt', 'Spanish': 'es', 'French': 'fr', 'Italian': 'it', 'Portuguese': 'pt' }; // Erstelle Übungen basierend auf Muttersprache function createFamilyWordsExercises(nativeLanguageName) { const langCode = LANGUAGE_CODES[nativeLanguageName] || 'de'; // Fallback zu Deutsch const exercises = []; // Multiple Choice Übungen für jedes Familienwort const familyWords = Object.keys(FAMILY_WORDS); const bisayaWords = ['Nanay', 'Tatay', 'Kuya', 'Ate', 'Lola', 'Lolo']; familyWords.forEach((key, index) => { const nativeWord = FAMILY_WORDS[key][langCode]; const bisayaWord = BISAYA_TRANSLATIONS[key]; // Erstelle Multiple Choice mit falschen Antworten const wrongAnswers = bisayaWords.filter(w => w !== bisayaWord); const shuffledWrong = wrongAnswers.sort(() => Math.random() - 0.5).slice(0, 3); const options = [bisayaWord, ...shuffledWrong].sort(() => Math.random() - 0.5); const correctIndex = options.indexOf(bisayaWord); exercises.push({ exerciseTypeId: 2, // multiple_choice title: `Wie sagt man "${nativeWord}" auf Bisaya?`, instruction: 'Wähle die richtige Übersetzung.', questionData: { type: 'multiple_choice', question: `Wie sagt man "${nativeWord}" auf Bisaya?`, options: options }, answerData: { type: 'multiple_choice', correctAnswer: correctIndex }, explanation: `"${bisayaWord}" bedeutet "${nativeWord}" auf Bisaya.` }); }); // Gap Fill Übung const nativeWords = familyWords.map(key => FAMILY_WORDS[key][langCode]); exercises.push({ exerciseTypeId: 1, // gap_fill title: 'Familienwörter vervollständigen', instruction: `Fülle die Lücken mit den richtigen Bisaya-Familienwörtern.`, questionData: { type: 'gap_fill', text: familyWords.map((key, i) => `{gap} (${nativeWords[i]})`).join(' | '), gaps: familyWords.length }, answerData: { type: 'gap_fill', answers: bisayaWords }, explanation: bisayaWords.map((bw, i) => `${bw} = ${nativeWords[i]}`).join(', ') + '.' }); // Transformation Übung exercises.push({ exerciseTypeId: 4, // transformation title: 'Familienwörter übersetzen', instruction: `Übersetze das Familienwort ins Bisaya.`, questionData: { type: 'transformation', text: nativeWords[0], // Erste Muttersprache als Beispiel sourceLanguage: nativeLanguageName || 'Deutsch', targetLanguage: 'Bisaya' }, answerData: { type: 'transformation', correct: bisayaWords[0], alternatives: [bisayaWords[0]] // Nur die korrekte Antwort }, explanation: `"${bisayaWords[0]}" bedeutet "${nativeWords[0]}" auf Bisaya.` }); return exercises; } async function findOrCreateSystemUser() { let systemUser = await User.findOne({ where: { username: 'system' } }); if (!systemUser) { systemUser = await User.findOne({ where: { username: 'admin' } }); } if (!systemUser) { console.error('❌ System-Benutzer nicht gefunden.'); throw new Error('System user not found'); } return systemUser; } async function updateFamilyWordsExercises() { await sequelize.authenticate(); console.log('Datenbankverbindung erfolgreich hergestellt.\n'); const systemUser = await findOrCreateSystemUser(); console.log(`Verwende System-Benutzer: ${systemUser.username} (ID: ${systemUser.id})\n`); // Finde alle Bisaya-Kurse const [bisayaLanguage] = await sequelize.query( `SELECT id FROM community.vocab_language WHERE name = 'Bisaya' LIMIT 1`, { type: sequelize.QueryTypes.SELECT } ); if (!bisayaLanguage) { console.error('❌ Bisaya-Sprache nicht gefunden.'); return; } const courses = await sequelize.query( `SELECT c.id, c.title, c.owner_user_id, c.native_language_id, nl.name as native_language_name FROM community.vocab_course c LEFT JOIN community.vocab_language nl ON c.native_language_id = nl.id WHERE c.language_id = :languageId`, { replacements: { languageId: bisayaLanguage.id }, type: sequelize.QueryTypes.SELECT } ); console.log(`Gefunden: ${courses.length} Bisaya-Kurse\n`); let totalExercisesUpdated = 0; let totalLessonsUpdated = 0; for (const course of courses) { const nativeLangName = course.native_language_name || 'Deutsch'; // Fallback zu Deutsch console.log(`📚 Kurs: ${course.title} (ID: ${course.id}, Muttersprache: ${nativeLangName})`); // Erstelle Übungen für diese Muttersprache const exercises = createFamilyWordsExercises(nativeLangName); // Finde "Familienwörter"-Lektionen const lessons = await VocabCourseLesson.findAll({ where: { courseId: course.id, title: 'Familienwörter' }, order: [['lessonNumber', 'ASC']] }); console.log(` ${lessons.length} "Familienwörter"-Lektionen gefunden\n`); for (const lesson of lessons) { // Lösche bestehende Übungen (inkl. Dummy-Übungen) const deletedCount = await VocabGrammarExercise.destroy({ where: { lessonId: lesson.id } }); console.log(` 🗑️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${deletedCount} alte Übung(en) gelöscht`); // Erstelle neue Übungen let exerciseNumber = 1; for (const exerciseData of exercises) { await VocabGrammarExercise.create({ lessonId: lesson.id, exerciseTypeId: exerciseData.exerciseTypeId, exerciseNumber: exerciseNumber++, title: exerciseData.title, instruction: exerciseData.instruction, questionData: JSON.stringify(exerciseData.questionData), answerData: JSON.stringify(exerciseData.answerData), explanation: exerciseData.explanation, createdByUserId: course.owner_user_id || systemUser.id }); totalExercisesUpdated++; } console.log(` ✅ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${exercises.length} neue Übung(en) erstellt (${nativeLangName} → Bisaya)`); totalLessonsUpdated++; } console.log(''); } console.log(`\n🎉 Zusammenfassung:`); console.log(` ${totalLessonsUpdated} Lektionen aktualisiert`); console.log(` ${totalExercisesUpdated} neue Grammatik-Übungen erstellt`); } updateFamilyWordsExercises() .then(() => { sequelize.close(); process.exit(0); }) .catch((error) => { console.error('❌ Fehler:', error); sequelize.close(); process.exit(1); });