Refactor exercise handling and improve user feedback in VocabLessonView
- Enhanced the exercise display logic to provide clearer feedback on available grammar exercises, improving user engagement. - Updated conditional rendering to ensure accurate handling of lesson and exercise data, reducing potential errors. - Improved logging for exercise counts and active tab states, aiding in debugging and performance monitoring.
This commit is contained in:
270
backend/scripts/update-survival-sentences-exercises.js
Executable file
270
backend/scripts/update-survival-sentences-exercises.js
Executable file
@@ -0,0 +1,270 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Script zum Aktualisieren der "Überlebenssätze"-Übungen in Bisaya-Kursen
|
||||
*
|
||||
* Verwendung:
|
||||
* node backend/scripts/update-survival-sentences-exercises.js
|
||||
*
|
||||
* Ersetzt bestehende generische Übungen durch spezifische Überlebenssätze-Ü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 User from '../models/community/user.js';
|
||||
|
||||
// Spezifische Übungen für Überlebenssätze
|
||||
const SURVIVAL_EXERCISES = {
|
||||
'Überlebenssätze - Teil 1': [
|
||||
{
|
||||
exerciseTypeId: 2, // multiple_choice
|
||||
title: 'Wie sagt man "Ich verstehe nicht"?',
|
||||
instruction: 'Wähle die richtige Übersetzung.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Wie sagt man "Ich verstehe nicht" auf Bisaya?',
|
||||
options: ['Wala ko kasabot', 'Palihug', 'Salamat', 'Maayo']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Wala ko kasabot" bedeutet "Ich verstehe nicht" - sehr wichtig für Anfänger!'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 2, // multiple_choice
|
||||
title: 'Wie sagt man "Kannst du das wiederholen?"?',
|
||||
instruction: 'Wähle die richtige Bitte aus.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Wie sagt man "Kannst du das wiederholen?" auf Bisaya?',
|
||||
options: ['Palihug ka mubalik?', 'Salamat', 'Maayo', 'Kumusta ka?']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Palihug ka mubalik?" bedeutet "Bitte kannst du wiederholen?" - essentiell für das Lernen!'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 2, // multiple_choice
|
||||
title: 'Wie sagt man "Wo ist...?"?',
|
||||
instruction: 'Wähle die richtige Frage aus.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Wie sagt man "Wo ist die Toilette?" auf Bisaya?',
|
||||
options: ['Asa ang CR?', 'Kumusta ka?', 'Salamat', 'Maayo']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Asa ang CR?" bedeutet "Wo ist die Toilette?" - "Asa" = "Wo", "CR" = "Comfort Room" (Toilette).'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1, // gap_fill
|
||||
title: 'Überlebenssätze vervollständigen',
|
||||
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: '{gap} ko kasabot. {gap} ka mubalik?',
|
||||
gaps: 2
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Wala', 'Palihug']
|
||||
},
|
||||
explanation: '"Wala ko kasabot" = "Ich verstehe nicht", "Palihug ka mubalik?" = "Bitte wiederholen".'
|
||||
}
|
||||
],
|
||||
|
||||
'Überlebenssätze - Teil 2': [
|
||||
{
|
||||
exerciseTypeId: 2, // multiple_choice
|
||||
title: 'Wie sagt man "Wie viel kostet das?"?',
|
||||
instruction: 'Wähle die richtige Frage aus.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Wie sagt man "Wie viel kostet das?" auf Bisaya?',
|
||||
options: ['Tagpila ni?', 'Asa ni?', 'Unsa ni?', 'Kinsa ni?']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Tagpila ni?" bedeutet "Wie viel kostet das?" - sehr nützlich beim Einkaufen!'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 2, // multiple_choice
|
||||
title: 'Wie sagt man "Entschuldigung"?',
|
||||
instruction: 'Wähle die richtige Entschuldigung aus.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Wie sagt man "Entschuldigung" auf Bisaya?',
|
||||
options: ['Pasensya', 'Salamat', 'Palihug', 'Maayo']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Pasensya" bedeutet "Entschuldigung" oder "Entschuldige bitte" - wichtig für höfliche Kommunikation.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1, // gap_fill
|
||||
title: 'Wichtige Fragen bilden',
|
||||
instruction: 'Fülle die Lücken mit den richtigen Fragewörtern.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: '{gap} ni? (Wie viel kostet das?) | {gap} ni? (Was ist das?) | {gap} lang (Bitte langsam)',
|
||||
gaps: 3
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Tagpila', 'Unsa', 'Hinay-hinay']
|
||||
},
|
||||
explanation: '"Tagpila" = "Wie viel", "Unsa" = "Was", "Hinay-hinay lang" = "Bitte langsam".'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 4, // transformation
|
||||
title: 'Überlebenssätze übersetzen',
|
||||
instruction: 'Übersetze den Satz ins Bisaya.',
|
||||
questionData: {
|
||||
type: 'transformation',
|
||||
text: 'Ich spreche kein Bisaya',
|
||||
sourceLanguage: 'Deutsch',
|
||||
targetLanguage: 'Bisaya'
|
||||
},
|
||||
answerData: {
|
||||
type: 'transformation',
|
||||
correct: 'Dili ko mag-Bisaya',
|
||||
alternatives: ['Wala ko mag-Bisaya', 'Dili ko makasabot Bisaya']
|
||||
},
|
||||
explanation: '"Dili ko mag-Bisaya" bedeutet "Ich spreche kein Bisaya" - nützlich, um zu erklären, dass du noch lernst.'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
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 updateSurvivalExercises() {
|
||||
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 id, title, owner_user_id FROM community.vocab_course WHERE 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) {
|
||||
console.log(`📚 Kurs: ${course.title} (ID: ${course.id})`);
|
||||
|
||||
// Finde "Überlebenssätze"-Lektionen
|
||||
const lessons = await VocabCourseLesson.findAll({
|
||||
where: {
|
||||
courseId: course.id,
|
||||
title: ['Überlebenssätze - Teil 1', 'Überlebenssätze - Teil 2']
|
||||
},
|
||||
order: [['lessonNumber', 'ASC']]
|
||||
});
|
||||
|
||||
console.log(` ${lessons.length} "Überlebenssätze"-Lektionen gefunden\n`);
|
||||
|
||||
for (const lesson of lessons) {
|
||||
const exercises = SURVIVAL_EXERCISES[lesson.title];
|
||||
|
||||
if (!exercises || exercises.length === 0) {
|
||||
console.log(` ⚠️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - keine Übungen definiert`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Lösche bestehende Ü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`);
|
||||
totalLessonsUpdated++;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
console.log(`\n🎉 Zusammenfassung:`);
|
||||
console.log(` ${totalLessonsUpdated} Lektionen aktualisiert`);
|
||||
console.log(` ${totalExercisesUpdated} neue Grammatik-Übungen erstellt`);
|
||||
}
|
||||
|
||||
updateSurvivalExercises()
|
||||
.then(() => {
|
||||
sequelize.close();
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ Fehler:', error);
|
||||
sequelize.close();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user