Add grammar exercise creation in course generation
- Integrated functionality to create example grammar exercises for grammar lessons during course creation. - Added a new helper function to generate gap fill and multiple choice exercises based on lesson data. - Enhanced logging to confirm the number of grammar exercises created, improving feedback during course setup.
This commit is contained in:
141
backend/scripts/add-grammar-exercises-to-existing-courses.js
Normal file
141
backend/scripts/add-grammar-exercises-to-existing-courses.js
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Script zum Hinzufügen von Grammatik-Übungen zu bestehenden Kursen
|
||||||
|
*
|
||||||
|
* Verwendung:
|
||||||
|
* node backend/scripts/add-grammar-exercises-to-existing-courses.js
|
||||||
|
*
|
||||||
|
* Fügt Beispiel-Grammatik-Übungen zu allen Grammar-Lektionen hinzu, die noch keine Übungen haben.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
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. Bitte erstelle einen System-Benutzer.');
|
||||||
|
throw new Error('System user not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return systemUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erstelle Beispiel-Grammatik-Übungen für eine Grammar-Lektion
|
||||||
|
function createExampleGrammarExercises(lessonId, lessonTitle, ownerUserId) {
|
||||||
|
const exercises = [];
|
||||||
|
|
||||||
|
// Beispiel-Übung 1: Gap Fill (Lückentext)
|
||||||
|
exercises.push({
|
||||||
|
lessonId: lessonId,
|
||||||
|
exerciseTypeId: 1, // gap_fill
|
||||||
|
exerciseNumber: 1,
|
||||||
|
title: `${lessonTitle} - Übung 1`,
|
||||||
|
instruction: 'Fülle die Lücken mit den richtigen Wörtern.',
|
||||||
|
questionData: JSON.stringify({
|
||||||
|
type: 'gap_fill',
|
||||||
|
text: 'Hallo! Wie geht es {gap}? Mir geht es {gap}, danke!',
|
||||||
|
gaps: 2
|
||||||
|
}),
|
||||||
|
answerData: JSON.stringify({
|
||||||
|
type: 'gap_fill',
|
||||||
|
answers: ['dir', 'gut']
|
||||||
|
}),
|
||||||
|
explanation: 'Die richtigen Antworten sind "dir" und "gut".',
|
||||||
|
createdByUserId: ownerUserId
|
||||||
|
});
|
||||||
|
|
||||||
|
// Beispiel-Übung 2: Multiple Choice
|
||||||
|
exercises.push({
|
||||||
|
lessonId: lessonId,
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
exerciseNumber: 2,
|
||||||
|
title: `${lessonTitle} - Übung 2`,
|
||||||
|
instruction: 'Wähle die richtige Antwort aus.',
|
||||||
|
questionData: JSON.stringify({
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Wie sagt man "Guten Tag"?',
|
||||||
|
options: ['Guten Tag', 'Gute Nacht', 'Auf Wiedersehen', 'Tschüss']
|
||||||
|
}),
|
||||||
|
answerData: JSON.stringify({
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
}),
|
||||||
|
explanation: 'Die richtige Antwort ist "Guten Tag".',
|
||||||
|
createdByUserId: ownerUserId
|
||||||
|
});
|
||||||
|
|
||||||
|
return exercises;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addGrammarExercisesToExistingCourses() {
|
||||||
|
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 Grammar-Lektionen ohne Übungen
|
||||||
|
const grammarLessons = await sequelize.query(
|
||||||
|
`SELECT l.id, l.title, l.course_id, c.owner_user_id
|
||||||
|
FROM community.vocab_course_lesson l
|
||||||
|
JOIN community.vocab_course c ON c.id = l.course_id
|
||||||
|
WHERE l.lesson_type = 'grammar'
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM community.vocab_grammar_exercise e
|
||||||
|
WHERE e.lesson_id = l.id
|
||||||
|
)
|
||||||
|
ORDER BY l.course_id, l.lesson_number`,
|
||||||
|
{
|
||||||
|
type: sequelize.QueryTypes.SELECT
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Gefunden: ${grammarLessons.length} Grammar-Lektionen ohne Übungen\n`);
|
||||||
|
|
||||||
|
if (grammarLessons.length === 0) {
|
||||||
|
console.log('✅ Alle Grammar-Lektionen haben bereits Übungen.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let addedCount = 0;
|
||||||
|
for (const lesson of grammarLessons) {
|
||||||
|
const exercises = createExampleGrammarExercises(lesson.id, lesson.title, lesson.owner_user_id);
|
||||||
|
|
||||||
|
for (const exercise of exercises) {
|
||||||
|
await VocabGrammarExercise.create(exercise);
|
||||||
|
addedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ ${exercises.length} Übungen zu "${lesson.title}" hinzugefügt`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n🎉 Zusammenfassung:`);
|
||||||
|
console.log(` ${addedCount} Grammatik-Übungen zu ${grammarLessons.length} Lektionen hinzugefügt`);
|
||||||
|
}
|
||||||
|
|
||||||
|
addGrammarExercisesToExistingCourses()
|
||||||
|
.then(() => {
|
||||||
|
sequelize.close();
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('❌ Fehler:', error);
|
||||||
|
sequelize.close();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
327
backend/scripts/create-bisaya-course-content.js
Normal file
327
backend/scripts/create-bisaya-course-content.js
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Script zum Erstellen von sprachspezifischem Content für Bisaya-Kurse
|
||||||
|
*
|
||||||
|
* Verwendung:
|
||||||
|
* node backend/scripts/create-bisaya-course-content.js
|
||||||
|
*
|
||||||
|
* Erstellt Grammatik-Übungen für alle Lektionen in Bisaya-Kursen basierend auf dem Thema der Lektion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
// Bisaya-spezifische Übungen basierend auf Lektionsthemen
|
||||||
|
const BISAYA_EXERCISES = {
|
||||||
|
// Lektion 1: Begrüßungen & Höflichkeit
|
||||||
|
'Begrüßungen & Höflichkeit': [
|
||||||
|
{
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
title: 'Wie sagt man "Wie geht es dir?" auf Bisaya?',
|
||||||
|
instruction: 'Wähle die richtige Begrüßung aus.',
|
||||||
|
questionData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Wie sagt man "Wie geht es dir?" auf Bisaya?',
|
||||||
|
options: ['Kumusta ka?', 'Maayo', 'Salamat', 'Palihug']
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
},
|
||||||
|
explanation: '"Kumusta ka?" ist die Standard-Begrüßung auf Bisaya, ähnlich wie "Wie geht es dir?"'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 1, // gap_fill
|
||||||
|
title: 'Begrüßungen vervollständigen',
|
||||||
|
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
||||||
|
questionData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
text: 'Kumusta ka? Maayo {gap}. Salamat {gap} palihug.',
|
||||||
|
gaps: 2
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
answers: ['ko', 'ug']
|
||||||
|
},
|
||||||
|
explanation: '"Maayo ko" bedeutet "Mir geht es gut" und "ug" verbindet die Wörter.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
title: 'Was bedeutet "Salamat"?',
|
||||||
|
instruction: 'Wähle die richtige Übersetzung.',
|
||||||
|
questionData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Was bedeutet "Salamat"?',
|
||||||
|
options: ['Danke', 'Bitte', 'Entschuldigung', 'Auf Wiedersehen']
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
},
|
||||||
|
explanation: '"Salamat" bedeutet "Danke" auf Bisaya.'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Lektion 15: Zeitformen - Grundlagen
|
||||||
|
'Zeitformen - Grundlagen': [
|
||||||
|
{
|
||||||
|
exerciseTypeId: 4, // transformation
|
||||||
|
title: 'Vergangenheit verstehen',
|
||||||
|
instruction: 'Was bedeutet "Ni-kaon ko"?',
|
||||||
|
questionData: {
|
||||||
|
type: 'transformation',
|
||||||
|
text: 'Ni-kaon ko',
|
||||||
|
sourceLanguage: 'Bisaya',
|
||||||
|
targetLanguage: 'Deutsch'
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'transformation',
|
||||||
|
correct: 'Ich habe gegessen',
|
||||||
|
alternatives: ['I ate', 'I have eaten']
|
||||||
|
},
|
||||||
|
explanation: 'Das Präfix "Ni-" zeigt die Vergangenheit an. "Ni-kaon ko" bedeutet "Ich habe gegessen".'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 4, // transformation
|
||||||
|
title: 'Zukunft verstehen',
|
||||||
|
instruction: 'Was bedeutet "Mo-kaon ko"?',
|
||||||
|
questionData: {
|
||||||
|
type: 'transformation',
|
||||||
|
text: 'Mo-kaon ko',
|
||||||
|
sourceLanguage: 'Bisaya',
|
||||||
|
targetLanguage: 'Deutsch'
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'transformation',
|
||||||
|
correct: 'Ich werde essen',
|
||||||
|
alternatives: ['I will eat', 'I am going to eat']
|
||||||
|
},
|
||||||
|
explanation: 'Das Präfix "Mo-" zeigt die Zukunft an. "Mo-kaon ko" bedeutet "Ich werde essen".'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 1, // gap_fill
|
||||||
|
title: 'Zeitformen erkennen',
|
||||||
|
instruction: 'Setze die richtigen Präfixe ein.',
|
||||||
|
questionData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
text: '{gap}-kaon ko (Vergangenheit) | {gap}-kaon ko (Zukunft)',
|
||||||
|
gaps: 2
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
answers: ['Ni', 'Mo']
|
||||||
|
},
|
||||||
|
explanation: 'Ni- für Vergangenheit, Mo- für Zukunft.'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Lektion 25: Höflichkeitsformen
|
||||||
|
'Höflichkeitsformen': [
|
||||||
|
{
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
title: 'Wie sagt man "Bitte langsam"?',
|
||||||
|
instruction: 'Wähle die höfliche Form aus.',
|
||||||
|
questionData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Wie sagt man "Bitte langsam" auf Bisaya?',
|
||||||
|
options: ['Hinay-hinay lang', 'Palihug', 'Salamat', 'Maayo']
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
},
|
||||||
|
explanation: '"Hinay-hinay lang" bedeutet "Bitte langsam" und ist sehr höflich.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 1, // gap_fill
|
||||||
|
title: 'Höfliche Sätze vervollständigen',
|
||||||
|
instruction: 'Fülle die Lücken mit höflichen Wörtern.',
|
||||||
|
questionData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
text: '{gap} lang, wala ko kasabot. {gap} ka mubalik?',
|
||||||
|
gaps: 2
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'gap_fill',
|
||||||
|
answers: ['Hinay-hinay', 'Palihug']
|
||||||
|
},
|
||||||
|
explanation: '"Hinay-hinay lang" = "Bitte langsam", "Palihug" = "Bitte".'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
title: 'Was bedeutet "Palihug"?',
|
||||||
|
instruction: 'Wähle die richtige Übersetzung.',
|
||||||
|
questionData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Was bedeutet "Palihug"?',
|
||||||
|
options: ['Bitte', 'Danke', 'Entschuldigung', 'Gern geschehen']
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
},
|
||||||
|
explanation: '"Palihug" bedeutet "Bitte" auf Bisaya und wird für höfliche Bitten verwendet.'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExercisesForLesson(lessonTitle) {
|
||||||
|
// Suche nach exaktem Titel
|
||||||
|
if (BISAYA_EXERCISES[lessonTitle]) {
|
||||||
|
return BISAYA_EXERCISES[lessonTitle];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Suche nach Teilstring
|
||||||
|
for (const [key, exercises] of Object.entries(BISAYA_EXERCISES)) {
|
||||||
|
if (lessonTitle.includes(key) || key.includes(lessonTitle)) {
|
||||||
|
return exercises;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard-Übungen für unbekannte Lektionen
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
title: `${lessonTitle} - Übung 1`,
|
||||||
|
instruction: 'Wähle die richtige Antwort aus.',
|
||||||
|
questionData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Was ist die richtige Übersetzung?',
|
||||||
|
options: ['Option A', 'Option B', 'Option C', 'Option D']
|
||||||
|
},
|
||||||
|
answerData: {
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
},
|
||||||
|
explanation: 'Dies ist eine Beispiel-Übung. Bitte füge sprachspezifische Inhalte hinzu.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createBisayaCourseContent() {
|
||||||
|
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 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 totalExercisesAdded = 0;
|
||||||
|
let totalLessonsProcessed = 0;
|
||||||
|
|
||||||
|
for (const course of courses) {
|
||||||
|
console.log(`📚 Kurs: ${course.title} (ID: ${course.id})`);
|
||||||
|
|
||||||
|
const lessons = await VocabCourseLesson.findAll({
|
||||||
|
where: { courseId: course.id },
|
||||||
|
order: [['lessonNumber', 'ASC']]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(` ${lessons.length} Lektionen gefunden\n`);
|
||||||
|
|
||||||
|
for (const lesson of lessons) {
|
||||||
|
// Prüfe, ob bereits Übungen existieren
|
||||||
|
const existingCount = await VocabGrammarExercise.count({
|
||||||
|
where: { lessonId: lesson.id }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingCount > 0) {
|
||||||
|
console.log(` ⏭️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - bereits ${existingCount} Übung(en) vorhanden`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hole Übungen für diese Lektion
|
||||||
|
const exercises = getExercisesForLesson(lesson.title);
|
||||||
|
|
||||||
|
if (exercises.length === 0) {
|
||||||
|
console.log(` ⚠️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - keine Übungen definiert`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erstelle Ü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.ownerUserId || systemUser.id
|
||||||
|
});
|
||||||
|
totalExercisesAdded++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` ✅ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${exercises.length} Übung(en) erstellt`);
|
||||||
|
totalLessonsProcessed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n🎉 Zusammenfassung:`);
|
||||||
|
console.log(` ${totalLessonsProcessed} Lektionen bearbeitet`);
|
||||||
|
console.log(` ${totalExercisesAdded} Grammatik-Übungen erstellt`);
|
||||||
|
}
|
||||||
|
|
||||||
|
createBisayaCourseContent()
|
||||||
|
.then(() => {
|
||||||
|
sequelize.close();
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('❌ Fehler:', error);
|
||||||
|
sequelize.close();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
import { sequelize } from '../utils/sequelize.js';
|
import { sequelize } from '../utils/sequelize.js';
|
||||||
import VocabCourse from '../models/community/vocab_course.js';
|
import VocabCourse from '../models/community/vocab_course.js';
|
||||||
import VocabCourseLesson from '../models/community/vocab_course_lesson.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';
|
import User from '../models/community/user.js';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
@@ -330,8 +331,9 @@ async function createCourseForLanguage(targetLanguageId, nativeLanguageId, langu
|
|||||||
console.log(` ✅ Kurs erstellt: "${course.title}" (ID: ${course.id}, Share-Code: ${shareCode})`);
|
console.log(` ✅ Kurs erstellt: "${course.title}" (ID: ${course.id}, Share-Code: ${shareCode})`);
|
||||||
|
|
||||||
// Erstelle Lektionen
|
// Erstelle Lektionen
|
||||||
|
const createdLessons = [];
|
||||||
for (const lessonData of LESSON_TEMPLATE) {
|
for (const lessonData of LESSON_TEMPLATE) {
|
||||||
await VocabCourseLesson.create({
|
const lesson = await VocabCourseLesson.create({
|
||||||
courseId: course.id,
|
courseId: course.id,
|
||||||
chapterId: null,
|
chapterId: null,
|
||||||
lessonNumber: lessonData.num,
|
lessonNumber: lessonData.num,
|
||||||
@@ -345,12 +347,78 @@ async function createCourseForLanguage(targetLanguageId, nativeLanguageId, langu
|
|||||||
targetScorePercent: lessonData.targetScore,
|
targetScorePercent: lessonData.targetScore,
|
||||||
requiresReview: lessonData.review
|
requiresReview: lessonData.review
|
||||||
});
|
});
|
||||||
|
createdLessons.push({ lesson, lessonData });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(` ✅ ${LESSON_TEMPLATE.length} Lektionen erstellt`);
|
console.log(` ✅ ${LESSON_TEMPLATE.length} Lektionen erstellt`);
|
||||||
|
|
||||||
|
// Erstelle Beispiel-Grammatik-Übungen für Grammar-Lektionen
|
||||||
|
let grammarExerciseCount = 0;
|
||||||
|
for (const { lesson, lessonData } of createdLessons) {
|
||||||
|
if (lessonData.type === 'grammar') {
|
||||||
|
// Erstelle 2-3 Beispiel-Übungen für jede Grammar-Lektion
|
||||||
|
const exercises = createExampleGrammarExercises(lesson.id, lessonData, ownerUserId);
|
||||||
|
for (const exercise of exercises) {
|
||||||
|
await VocabGrammarExercise.create(exercise);
|
||||||
|
grammarExerciseCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grammarExerciseCount > 0) {
|
||||||
|
console.log(` ✅ ${grammarExerciseCount} Grammatik-Übungen erstellt`);
|
||||||
|
}
|
||||||
|
|
||||||
return course;
|
return course;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Erstelle Beispiel-Grammatik-Übungen für eine Grammar-Lektion
|
||||||
|
function createExampleGrammarExercises(lessonId, lessonData, ownerUserId) {
|
||||||
|
const exercises = [];
|
||||||
|
|
||||||
|
// Beispiel-Übung 1: Gap Fill (Lückentext)
|
||||||
|
exercises.push({
|
||||||
|
lessonId: lessonId,
|
||||||
|
exerciseTypeId: 1, // gap_fill
|
||||||
|
exerciseNumber: 1,
|
||||||
|
title: `${lessonData.title} - Übung 1`,
|
||||||
|
instruction: 'Fülle die Lücken mit den richtigen Wörtern.',
|
||||||
|
questionData: JSON.stringify({
|
||||||
|
type: 'gap_fill',
|
||||||
|
text: 'Hallo! Wie geht es {gap}? Mir geht es {gap}, danke!',
|
||||||
|
gaps: 2
|
||||||
|
}),
|
||||||
|
answerData: JSON.stringify({
|
||||||
|
type: 'gap_fill',
|
||||||
|
answers: ['dir', 'gut']
|
||||||
|
}),
|
||||||
|
explanation: 'Die richtigen Antworten sind "dir" und "gut".',
|
||||||
|
createdByUserId: ownerUserId
|
||||||
|
});
|
||||||
|
|
||||||
|
// Beispiel-Übung 2: Multiple Choice
|
||||||
|
exercises.push({
|
||||||
|
lessonId: lessonId,
|
||||||
|
exerciseTypeId: 2, // multiple_choice
|
||||||
|
exerciseNumber: 2,
|
||||||
|
title: `${lessonData.title} - Übung 2`,
|
||||||
|
instruction: 'Wähle die richtige Antwort aus.',
|
||||||
|
questionData: JSON.stringify({
|
||||||
|
type: 'multiple_choice',
|
||||||
|
question: 'Wie sagt man "Guten Tag" auf ' + lessonData.title.split(' - ')[0] + '?',
|
||||||
|
options: ['Option A', 'Option B', 'Option C', 'Option D']
|
||||||
|
}),
|
||||||
|
answerData: JSON.stringify({
|
||||||
|
type: 'multiple_choice',
|
||||||
|
correctAnswer: 0
|
||||||
|
}),
|
||||||
|
explanation: 'Die richtige Antwort ist Option A.',
|
||||||
|
createdByUserId: ownerUserId
|
||||||
|
});
|
||||||
|
|
||||||
|
return exercises;
|
||||||
|
}
|
||||||
|
|
||||||
async function findOrCreateSystemUser() {
|
async function findOrCreateSystemUser() {
|
||||||
// Versuche zuerst einen System-Benutzer zu finden (z.B. mit username "system" oder "admin")
|
// Versuche zuerst einen System-Benutzer zu finden (z.B. mit username "system" oder "admin")
|
||||||
let systemUser = await User.findOne({
|
let systemUser = await User.findOne({
|
||||||
|
|||||||
Reference in New Issue
Block a user