From 089743ac235ff780945adf66f171075fa1323216 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 19 Jan 2026 23:37:16 +0100 Subject: [PATCH] Refactor VocabLessonView for improved lesson navigation and user feedback - Enhanced the loadLesson and checkLessonCompletion methods to streamline lesson transitions and prevent redundant executions, improving user experience. - Updated navigation logic to utilize more efficient history management, ensuring smoother course and lesson changes. - Added detailed console logging for better insights during lesson loading and completion checks, aiding in debugging and user interaction. --- .../update-family-conversations-exercises.js | 521 ++++++++++++++++++ 1 file changed, 521 insertions(+) create mode 100755 backend/scripts/update-family-conversations-exercises.js diff --git a/backend/scripts/update-family-conversations-exercises.js b/backend/scripts/update-family-conversations-exercises.js new file mode 100755 index 0000000..747b591 --- /dev/null +++ b/backend/scripts/update-family-conversations-exercises.js @@ -0,0 +1,521 @@ +#!/usr/bin/env node +/** + * Script zum Erstellen von Übungen für die "Familien-Gespräche" Lektion + * + * Verwendung: + * node backend/scripts/update-family-conversations-exercises.js + * + * Erstellt Gesprächsübungen für die "Familien-Gespräche" Lektion in allen Bisaya-Kursen. + */ + +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 VocabLanguage from '../models/community/vocab_language.js'; +import VocabGrammarExerciseType from '../models/community/vocab_grammar_exercise_type.js'; +import User from '../models/community/user.js'; +import crypto from 'crypto'; +import bcrypt from 'bcryptjs'; +import { Op } from 'sequelize'; + +// Familiengespräche auf Bisaya mit verschiedenen Muttersprachen +const FAMILY_CONVERSATIONS = { + // Deutsch -> Bisaya + 'Deutsch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: 'Wie geht es dir, Mama?', + explanation: '"Kumusta ka" ist "Wie geht es dir?" und "Nanay" ist "Mama"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'Mir geht es gut, danke. Und dir?', + explanation: '"Maayo ko" bedeutet "Mir geht es gut", "Ikaw" ist "du" (formal)' + }, + { + bisaya: 'Asa si Tatay?', + native: 'Wo ist Papa?', + explanation: '"Asa" bedeutet "wo", "si" ist ein Marker für Personen, "Tatay" ist "Papa"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'Er ist zu Hause.', + explanation: '"Naa" bedeutet "ist/sein", "siya" ist "er/sie", "sa balay" ist "zu Hause"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: 'Wie geht es dem älteren Bruder?', + explanation: '"Kumusta na" ist "Wie geht es", "ang" ist ein Artikel, "Kuya" ist "älterer Bruder"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'Es geht ihm gut.', + explanation: '"Maayo ra" bedeutet "gut/gut geht es", "siya" ist "ihm"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'Ich bin hungrig, Mama.', + explanation: '"Gutom" bedeutet "hungrig", "na" zeigt einen Zustand, "ko" ist "ich"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Warte nur, das Essen ist fast fertig.', + explanation: '"Hulata" ist "warte", "lang" ist "nur", "hapit na" ist "fast", "pagkaon" ist "Essen"' + } + ] + }, + // Englisch -> Bisaya + 'Englisch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: 'How are you, Mom?', + explanation: '"Kumusta ka" means "How are you?" and "Nanay" means "Mom"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'I\'m fine, thank you. And you?', + explanation: '"Maayo ko" means "I\'m fine", "Ikaw" is "you" (formal)' + }, + { + bisaya: 'Asa si Tatay?', + native: 'Where is Dad?', + explanation: '"Asa" means "where", "si" is a person marker, "Tatay" means "Dad"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'He is at home.', + explanation: '"Naa" means "is/be", "siya" is "he/she", "sa balay" means "at home"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: 'How is the older brother?', + explanation: '"Kumusta na" means "How is", "ang" is an article, "Kuya" means "older brother"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'He is fine.', + explanation: '"Maayo ra" means "fine/well", "siya" means "he"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'I\'m hungry, Mom.', + explanation: '"Gutom" means "hungry", "na" shows a state, "ko" is "I"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Just wait, the food is almost ready.', + explanation: '"Hulata" means "wait", "lang" means "just", "hapit na" means "almost", "pagkaon" means "food"' + } + ] + }, + // Spanisch -> Bisaya + 'Spanisch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: '¿Cómo estás, Mamá?', + explanation: '"Kumusta ka" significa "¿Cómo estás?" y "Nanay" significa "Mamá"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'Estoy bien, gracias. ¿Y tú?', + explanation: '"Maayo ko" significa "Estoy bien", "Ikaw" es "tú" (formal)' + }, + { + bisaya: 'Asa si Tatay?', + native: '¿Dónde está Papá?', + explanation: '"Asa" significa "dónde", "si" es un marcador de persona, "Tatay" significa "Papá"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'Él está en casa.', + explanation: '"Naa" significa "está/ser", "siya" es "él/ella", "sa balay" significa "en casa"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: '¿Cómo está el hermano mayor?', + explanation: '"Kumusta na" significa "¿Cómo está?", "ang" es un artículo, "Kuya" significa "hermano mayor"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'Él está bien.', + explanation: '"Maayo ra" significa "bien", "siya" significa "él"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'Tengo hambre, Mamá.', + explanation: '"Gutom" significa "hambriento", "na" muestra un estado, "ko" es "yo"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Solo espera, la comida está casi lista.', + explanation: '"Hulata" significa "espera", "lang" significa "solo", "hapit na" significa "casi", "pagkaon" significa "comida"' + } + ] + }, + // Französisch -> Bisaya + 'Französisch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: 'Comment vas-tu, Maman?', + explanation: '"Kumusta ka" signifie "Comment vas-tu?" et "Nanay" signifie "Maman"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'Je vais bien, merci. Et toi?', + explanation: '"Maayo ko" signifie "Je vais bien", "Ikaw" est "tu" (formel)' + }, + { + bisaya: 'Asa si Tatay?', + native: 'Où est Papa?', + explanation: '"Asa" signifie "où", "si" est un marqueur de personne, "Tatay" signifie "Papa"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'Il est à la maison.', + explanation: '"Naa" signifie "est/être", "siya" est "il/elle", "sa balay" signifie "à la maison"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: 'Comment va le grand frère?', + explanation: '"Kumusta na" signifie "Comment va", "ang" est un article, "Kuya" signifie "grand frère"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'Il va bien.', + explanation: '"Maayo ra" signifie "bien", "siya" signifie "il"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'J\'ai faim, Maman.', + explanation: '"Gutom" signifie "faim", "na" montre un état, "ko" est "je"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Attends juste, la nourriture est presque prête.', + explanation: '"Hulata" signifie "attends", "lang" signifie "juste", "hapit na" signifie "presque", "pagkaon" signifie "nourriture"' + } + ] + }, + // Italienisch -> Bisaya + 'Italienisch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: 'Come stai, Mamma?', + explanation: '"Kumusta ka" significa "Come stai?" e "Nanay" significa "Mamma"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'Sto bene, grazie. E tu?', + explanation: '"Maayo ko" significa "Sto bene", "Ikaw" è "tu" (formale)' + }, + { + bisaya: 'Asa si Tatay?', + native: 'Dove è Papà?', + explanation: '"Asa" significa "dove", "si" è un marcatore di persona, "Tatay" significa "Papà"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'È a casa.', + explanation: '"Naa" significa "è/essere", "siya" è "lui/lei", "sa balay" significa "a casa"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: 'Come sta il fratello maggiore?', + explanation: '"Kumusta na" significa "Come sta", "ang" è un articolo, "Kuya" significa "fratello maggiore"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'Sta bene.', + explanation: '"Maayo ra" significa "bene", "siya" significa "lui"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'Ho fame, Mamma.', + explanation: '"Gutom" significa "fame", "na" mostra uno stato, "ko" è "io"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Aspetta solo, il cibo è quasi pronto.', + explanation: '"Hulata" significa "aspetta", "lang" significa "solo", "hapit na" significa "quasi", "pagkaon" significa "cibo"' + } + ] + }, + // Portugiesisch -> Bisaya + 'Portugiesisch': { + conversations: [ + { + bisaya: 'Kumusta ka, Nanay?', + native: 'Como você está, Mãe?', + explanation: '"Kumusta ka" significa "Como você está?" e "Nanay" significa "Mãe"' + }, + { + bisaya: 'Maayo ko, Salamat. Ikaw?', + native: 'Estou bem, obrigado. E você?', + explanation: '"Maayo ko" significa "Estou bem", "Ikaw" é "você" (formal)' + }, + { + bisaya: 'Asa si Tatay?', + native: 'Onde está o Papai?', + explanation: '"Asa" significa "onde", "si" é um marcador de pessoa, "Tatay" significa "Papai"' + }, + { + bisaya: 'Naa siya sa balay.', + native: 'Ele está em casa.', + explanation: '"Naa" significa "está/ser", "siya" é "ele/ela", "sa balay" significa "em casa"' + }, + { + bisaya: 'Kumusta na ang Kuya?', + native: 'Como está o irmão mais velho?', + explanation: '"Kumusta na" significa "Como está", "ang" é um artigo, "Kuya" significa "irmão mais velho"' + }, + { + bisaya: 'Maayo ra siya.', + native: 'Ele está bem.', + explanation: '"Maayo ra" significa "bem", "siya" significa "ele"' + }, + { + bisaya: 'Gutom na ko, Nanay.', + native: 'Estou com fome, Mãe.', + explanation: '"Gutom" significa "fome", "na" mostra um estado, "ko" é "eu"' + }, + { + bisaya: 'Hulata lang, hapit na ang pagkaon.', + native: 'Apenas espere, a comida está quase pronta.', + explanation: '"Hulata" significa "espere", "lang" significa "apenas", "hapit na" significa "quase", "pagkaon" significa "comida"' + } + ] + } +}; + +async function findOrCreateSystemUser() { + // Versuche zuerst einen System-Benutzer zu finden (z.B. mit username "system" oder "admin") + let systemUser = await User.findOne({ + where: { + username: { [sequelize.Sequelize.Op.in]: ['system', 'admin', 'System', 'Admin'] } + } + }); + + if (!systemUser) { + // Erstelle einen System-Benutzer + const password = crypto.randomBytes(32).toString('hex'); + const hashedPassword = await bcrypt.hash(password, 10); + const hashedId = crypto.createHash('sha256').update(`system-${Date.now()}`).digest('hex'); + + systemUser = await User.create({ + username: 'system', + password: hashedPassword, + hashedId: hashedId, + email: 'system@your-part.de' + }); + console.log('✅ System-Benutzer erstellt:', systemUser.hashedId); + } else { + console.log('✅ System-Benutzer gefunden:', systemUser.hashedId); + } + + return systemUser; +} + +function createFamilyConversationExercises(nativeLanguageName) { + const exercises = []; + const conversations = FAMILY_CONVERSATIONS[nativeLanguageName]?.conversations || []; + + if (conversations.length === 0) { + console.warn(`⚠️ Keine Gespräche für Muttersprache "${nativeLanguageName}" gefunden. Verwende Deutsch als Fallback.`); + return createFamilyConversationExercises('Deutsch'); + } + + let exerciseNum = 1; + + // Multiple Choice: Übersetze Bisaya-Satz in Muttersprache + conversations.forEach((conv, idx) => { + if (idx < 4) { // Erste 4 als Multiple Choice + exercises.push({ + exerciseTypeId: 2, // multiple_choice + exerciseNumber: exerciseNum++, + title: `Familien-Gespräch ${idx + 1} - Übersetzung`, + instruction: 'Übersetze den Bisaya-Satz ins ' + nativeLanguageName, + questionData: JSON.stringify({ + type: 'multiple_choice', + question: `Wie sagt man "${conv.bisaya}" auf ${nativeLanguageName}?`, + options: [ + conv.native, + conversations[(idx + 1) % conversations.length].native, + conversations[(idx + 2) % conversations.length].native, + conversations[(idx + 3) % conversations.length].native + ] + }), + answerData: JSON.stringify({ + type: 'multiple_choice', + correctAnswer: 0 + }), + explanation: conv.explanation + }); + } + }); + + // Gap Fill: Vervollständige Familiengespräche + exercises.push({ + exerciseTypeId: 1, // gap_fill + exerciseNumber: exerciseNum++, + title: 'Familien-Gespräch vervollständigen', + instruction: 'Vervollständige das Gespräch mit den richtigen Bisaya-Wörtern.', + questionData: JSON.stringify({ + type: 'gap_fill', + text: 'Person A: Kumusta ka, {gap}? (Mama)\nPerson B: {gap} ko, Salamat. Ikaw? (Mir geht es gut)', + gaps: 2 + }), + answerData: JSON.stringify({ + type: 'gap_fill', + answers: ['Nanay', 'Maayo'] + }), + explanation: '"Nanay" ist "Mama" und "Maayo ko" bedeutet "Mir geht es gut"' + }); + + // Transformation: Übersetze Muttersprache-Satz nach Bisaya + exercises.push({ + exerciseTypeId: 3, // transformation + exerciseNumber: exerciseNum++, + title: 'Familien-Gespräch - Übersetzung nach Bisaya', + instruction: 'Übersetze den Satz ins Bisaya.', + questionData: JSON.stringify({ + type: 'transformation', + text: conversations[0].native + }), + answerData: JSON.stringify({ + type: 'transformation', + correctAnswer: conversations[0].bisaya + }), + explanation: `"${conversations[0].bisaya}" bedeutet "${conversations[0].native}" auf Bisaya. ${conversations[0].explanation}` + }); + + // Weitere Multiple Choice: Rückwärts-Übersetzung + exercises.push({ + exerciseTypeId: 2, // multiple_choice + exerciseNumber: exerciseNum++, + title: 'Familien-Gespräch - Was bedeutet dieser Satz?', + instruction: 'Was bedeutet dieser Bisaya-Satz?', + questionData: JSON.stringify({ + type: 'multiple_choice', + question: `Was bedeutet "${conversations[2].bisaya}"?`, + options: [ + conversations[2].native, + conversations[3].native, + conversations[4].native, + conversations[5].native + ] + }), + answerData: JSON.stringify({ + type: 'multiple_choice', + correctAnswer: 0 + }), + explanation: conversations[2].explanation + }); + + return exercises; +} + +async function updateFamilyConversationExercises() { + await sequelize.authenticate(); + console.log('✅ Datenbankverbindung erfolgreich hergestellt.\n'); + + const systemUser = await findOrCreateSystemUser(); + const bisayaLanguage = await VocabLanguage.findOne({ where: { name: 'Bisaya' } }); + + if (!bisayaLanguage) { + console.error('❌ Bisaya-Sprache nicht gefunden.'); + return; + } + + // Hole alle Bisaya-Kurse + const courses = await VocabCourse.findAll({ + where: { languageId: bisayaLanguage.id }, + attributes: ['id', 'title', 'nativeLanguageId'] + }); + + // Hole native language info für jeden Kurs + const coursesWithNativeLang = await Promise.all( + courses.map(async (course) => { + let nativeLanguage = null; + if (course.nativeLanguageId) { + nativeLanguage = await VocabLanguage.findByPk(course.nativeLanguageId); + } + return { + ...course.get({ plain: true }), + nativeLanguage: nativeLanguage ? nativeLanguage.get({ plain: true }) : null + }; + }) + ); + + console.log(`📚 Gefunden: ${courses.length} Bisaya-Kurse\n`); + + let totalExercisesCreated = 0; + let totalLessonsProcessed = 0; + + for (const course of coursesWithNativeLang) { + console.log(`📖 Kurs: ${course.title} (ID: ${course.id})`); + + // Finde native language name + const nativeLanguageName = course.nativeLanguage?.name || 'Deutsch'; + console.log(` Muttersprache: ${nativeLanguageName}`); + + // Finde "Familien-Gespräche" Lektion + const lessons = await VocabCourseLesson.findAll({ + where: { + courseId: course.id, + title: 'Familien-Gespräche' + }, + attributes: ['id', 'title', 'lessonNumber'] + }); + + console.log(` ${lessons.length} "Familien-Gespräche"-Lektion(en) gefunden`); + + for (const lesson of lessons) { + // Lösche vorhandene Ü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 + const exercises = createFamilyConversationExercises(nativeLanguageName); + + if (exercises.length > 0) { + const exercisesToCreate = exercises.map(ex => ({ + ...ex, + lessonId: lesson.id, + createdByUserId: systemUser.id + })); + + await VocabGrammarExercise.bulkCreate(exercisesToCreate); + totalExercisesCreated += exercisesToCreate.length; + console.log(` ✅ ${exercisesToCreate.length} neue Übung(en) erstellt`); + } else { + console.log(` ⚠️ Keine Übungen erstellt`); + } + + totalLessonsProcessed++; + } + console.log(''); + } + + console.log(`\n🎉 Zusammenfassung:`); + console.log(` ${totalLessonsProcessed} "Familien-Gespräche"-Lektion(en) verarbeitet`); + console.log(` ${totalExercisesCreated} Grammatik-Übungen erstellt`); +} + +updateFamilyConversationExercises() + .then(() => { + sequelize.close(); + process.exit(0); + }) + .catch((error) => { + console.error('❌ Fehler:', error); + sequelize.close(); + process.exit(1); + });