208 lines
8.2 KiB
JavaScript
208 lines
8.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Spielt die überarbeiteten Bisaya-Kursinhalte ein und setzt den Lernfortschritt zurück.
|
|
*
|
|
* Verwendung:
|
|
* node backend/scripts/apply-bisaya-course-refresh.js
|
|
*/
|
|
|
|
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 VocabCourseProgress from '../models/community/vocab_course_progress.js';
|
|
import VocabGrammarExerciseProgress from '../models/community/vocab_grammar_exercise_progress.js';
|
|
import { Op } from 'sequelize';
|
|
|
|
const LESSON_DIDACTICS = {
|
|
'Begrüßungen & Höflichkeit': {
|
|
learningGoals: [
|
|
'Einfache Begrüßungen verstehen und selbst verwenden.',
|
|
'Tageszeitbezogene Grüße und einfache Verabschiedungen unterscheiden.',
|
|
'Höfliche Reaktionen wie Danke und Bitte passend einsetzen.',
|
|
'Ein kurzes Begrüßungs-Mini-Gespräch laut üben.'
|
|
],
|
|
corePatterns: ['Kumusta ka?', 'Maayong buntag.', 'Maayong adlaw.', 'Amping.', 'Babay.', 'Maayo ko.', 'Salamat.', 'Palihug.'],
|
|
grammarFocus: [
|
|
{ title: 'Kurzantworten mit ko', text: 'Mit "ko" sprichst du über dich selbst: "Maayo ko."', example: 'Maayo ko. = Mir geht es gut.' },
|
|
{ title: 'Maayong + Tageszeit', text: 'Mit "Maayong" kannst du Grüße für verschiedene Tageszeiten bilden.', example: 'Maayong buntag. / Maayong gabii.' }
|
|
],
|
|
speakingPrompts: [
|
|
{ title: 'Mini-Gespräch', prompt: 'Begrüße eine Person, frage nach dem Befinden und reagiere höflich.', cue: 'Kumusta ka? Maayo ko. Salamat.' },
|
|
{ title: 'Verabschiedung', prompt: 'Verabschiede dich kurz und wünsche, dass die andere Person auf sich aufpasst.', cue: 'Babay. Amping.' }
|
|
],
|
|
practicalTasks: [{ title: 'Alltag', text: 'Sprich die Begrüßung dreimal laut und variiere die Antwort.' }]
|
|
},
|
|
'Familienwörter': {
|
|
learningGoals: [
|
|
'Die wichtigsten Familienbezeichnungen sicher erkennen.',
|
|
'Familienmitglieder mit respektvollen Wörtern ansprechen.',
|
|
'Kurze Sätze über die eigene Familie bilden.'
|
|
],
|
|
corePatterns: ['Si Nanay', 'Si Tatay', 'Kuya nako', 'Ate nako'],
|
|
grammarFocus: [
|
|
{ title: 'Respekt in Familienanreden', text: 'Kuya und Ate werden nicht nur in der Familie, sondern auch respektvoll für ältere Personen benutzt.', example: 'Kuya, palihug.' }
|
|
],
|
|
speakingPrompts: [
|
|
{ title: 'Meine Familie', prompt: 'Stelle zwei Familienmitglieder mit einem kurzen Satz vor.', cue: 'Si Nanay. Si Kuya.' }
|
|
],
|
|
practicalTasks: [{ title: 'Familienpraxis', text: 'Nenne laut fünf Familienwörter und bilde danach zwei Mini-Sätze.' }]
|
|
},
|
|
'Essen & Fürsorge': {
|
|
learningGoals: [
|
|
'Fürsorgliche Fragen rund ums Essen verstehen.',
|
|
'Einladungen zum Essen passend beantworten.',
|
|
'Kurze Essens-Dialoge laut üben.'
|
|
],
|
|
corePatterns: ['Nikaon na ka?', 'Kaon ta.', 'Gusto ka mokaon?', 'Lami kaayo.'],
|
|
grammarFocus: [
|
|
{ title: 'na als Zustandsmarker', text: '"na" markiert oft etwas, das bereits eingetreten ist oder jetzt gilt.', example: 'Nikaon na ka?' }
|
|
],
|
|
speakingPrompts: [
|
|
{ title: 'Fürsorge-Dialog', prompt: 'Frage, ob jemand schon gegessen hat, und biete Essen oder Wasser an.', cue: 'Nikaon na ka? Gusto ka mokaon?' }
|
|
],
|
|
practicalTasks: [{ title: 'Rollenspiel', text: 'Spiele ein kurzes Gespräch zwischen Gastgeber und Gast beim Essen.' }]
|
|
},
|
|
'Zeitformen - Grundlagen': {
|
|
learningGoals: [
|
|
'Ni- und Mo- als einfache Zeitmarker unterscheiden.',
|
|
'Kurze Sätze in Vergangenheit und Zukunft bilden.',
|
|
'Das Muster laut mit mehreren Verben wiederholen.'
|
|
],
|
|
corePatterns: ['Ni-kaon ko.', 'Mo-kaon ko.', 'Ni-adto ko.', 'Mo-adto ko.'],
|
|
grammarFocus: [
|
|
{ title: 'Zeitpräfixe', text: 'Ni- verweist auf Vergangenes, Mo- auf Zukünftiges oder Bevorstehendes.', example: 'Ni-kaon ko. / Mo-kaon ko.' }
|
|
],
|
|
speakingPrompts: [
|
|
{ title: 'Vorher und nachher', prompt: 'Sage einen Satz über etwas, das du getan hast, und einen Satz über etwas, das du tun wirst.', cue: 'Ni-kaon ko. Mo-adto ko.' }
|
|
],
|
|
practicalTasks: [{ title: 'Mustertraining', text: 'Nimm ein Verb und sprich es einmal mit Ni- und einmal mit Mo-.' }]
|
|
},
|
|
'Woche 1 - Wiederholung': {
|
|
learningGoals: [
|
|
'Die Kernmuster der ersten Woche ohne Hilfe wiederholen.',
|
|
'Zwischen Begrüßung, Familie und Fürsorge schneller wechseln.',
|
|
'Eine kurze Alltagssequenz frei sprechen.'
|
|
],
|
|
corePatterns: ['Kumusta ka?', 'Palangga taka.', 'Nikaon na ka?', 'Wala ko kasabot.'],
|
|
speakingPrompts: [
|
|
{ title: 'Freie Wiederholung', prompt: 'Begrüße jemanden, drücke Zuneigung aus und frage fürsorglich nach dem Essen.', cue: 'Kumusta ka? Palangga taka. Nikaon na ka?' }
|
|
]
|
|
},
|
|
'Woche 1 - Vokabeltest': {
|
|
learningGoals: [
|
|
'Die wichtigsten Wörter der ersten Woche schnell abrufen.',
|
|
'Bedeutung und Gebrauch zentraler Wörter unterscheiden.',
|
|
'Von einzelnen Wörtern zu kurzen Sätzen übergehen.'
|
|
],
|
|
corePatterns: ['Kumusta', 'Salamat', 'Lami', 'Mingaw ko nimo']
|
|
}
|
|
};
|
|
|
|
async function resetBisayaProgress(courseIds) {
|
|
if (courseIds.length === 0) return { lessonProgress: 0, exerciseProgress: 0 };
|
|
|
|
const lessonIds = await VocabCourseLesson.findAll({
|
|
where: {
|
|
courseId: {
|
|
[Op.in]: courseIds
|
|
}
|
|
},
|
|
attributes: ['id']
|
|
});
|
|
|
|
const numericLessonIds = lessonIds.map((row) => row.id);
|
|
const exerciseIds = numericLessonIds.length > 0
|
|
? await VocabGrammarExercise.findAll({
|
|
where: {
|
|
lessonId: {
|
|
[Op.in]: numericLessonIds
|
|
}
|
|
},
|
|
attributes: ['id']
|
|
})
|
|
: [];
|
|
|
|
const deletedLessonProgress = await VocabCourseProgress.destroy({
|
|
where: { courseId: { [Op.in]: courseIds } }
|
|
});
|
|
|
|
let deletedExerciseProgress = 0;
|
|
if (exerciseIds.length > 0) {
|
|
deletedExerciseProgress = await VocabGrammarExerciseProgress.destroy({
|
|
where: { exerciseId: { [Op.in]: exerciseIds.map((row) => row.id) } }
|
|
});
|
|
}
|
|
|
|
return {
|
|
lessonProgress: deletedLessonProgress,
|
|
exerciseProgress: deletedExerciseProgress
|
|
};
|
|
}
|
|
|
|
async function applyBisayaCourseRefresh() {
|
|
await sequelize.authenticate();
|
|
|
|
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 FROM community.vocab_course WHERE language_id = :languageId ORDER BY id ASC`,
|
|
{
|
|
replacements: { languageId: bisayaLanguage.id },
|
|
type: sequelize.QueryTypes.SELECT
|
|
}
|
|
);
|
|
|
|
const courseIds = courses.map((course) => course.id);
|
|
const resetStats = await resetBisayaProgress(courseIds);
|
|
|
|
let updatedLessons = 0;
|
|
for (const course of courses) {
|
|
const lessons = await VocabCourseLesson.findAll({
|
|
where: { courseId: course.id }
|
|
});
|
|
|
|
for (const lesson of lessons) {
|
|
const didactics = LESSON_DIDACTICS[lesson.title];
|
|
if (!didactics) continue;
|
|
|
|
await lesson.update({
|
|
learningGoals: didactics.learningGoals || [],
|
|
corePatterns: didactics.corePatterns || [],
|
|
grammarFocus: didactics.grammarFocus || [],
|
|
speakingPrompts: didactics.speakingPrompts || [],
|
|
practicalTasks: didactics.practicalTasks || []
|
|
});
|
|
updatedLessons++;
|
|
}
|
|
}
|
|
|
|
console.log('✅ Bisaya-Kursupdate vorbereitet.');
|
|
console.log(` Kurse: ${courses.length}`);
|
|
console.log(` Didaktisch aktualisierte Lektionen: ${updatedLessons}`);
|
|
console.log(` Gelöschte Lektionsfortschritte: ${resetStats.lessonProgress}`);
|
|
console.log(` Gelöschte Übungsfortschritte: ${resetStats.exerciseProgress}`);
|
|
console.log('');
|
|
console.log('Nächste Schritte:');
|
|
console.log('1. create-bisaya-course-content.js ausführen, um die neuen Übungen einzuspielen');
|
|
console.log('2. optional update-week1-bisaya-exercises.js ausführen, falls Woche 1 separat gepflegt wird');
|
|
}
|
|
|
|
applyBisayaCourseRefresh()
|
|
.then(() => {
|
|
sequelize.close();
|
|
process.exit(0);
|
|
})
|
|
.catch((error) => {
|
|
console.error('❌ Fehler:', error);
|
|
sequelize.close();
|
|
process.exit(1);
|
|
});
|