latest(); if ($r->filled('subject')) $query->where('subject_id', $r->subject); $questions = $query->paginate(20)->withQueryString(); return view('admin.questions.index', compact('questions','subjects')); } public function create() { $subjects = Subject::all(); return view('admin.questions.create', compact('subjects')); } public function store(Request $r) { $r->validate([ 'subject_id' => 'required|exists:subjects,id', 'question_text' => 'required|string', 'type' => 'required|in:multiple_choice,number_input', 'difficulty' => 'required|in:1,2,3', 'options' => 'required_if:type,multiple_choice|array|min:2', 'options.*' => 'required|string', 'correct' => 'required_if:type,multiple_choice|integer', 'number_answer' => 'required_if:type,number_input', ]); $pts = [1=>5, 2=>10, 3=>20][$r->difficulty]; $q = Question::create([ 'subject_id' => $r->subject_id, 'question_text' => $r->question_text, 'type' => $r->type, 'difficulty' => $r->difficulty, 'points_value' => $pts, 'active' => true, ]); if ($r->type === 'multiple_choice') { foreach ($r->options as $i => $text) { if (trim($text) === '') continue; AnswerOption::create([ 'question_id' => $q->id, 'text' => $text, 'is_correct' => ($i == $r->correct), 'sort_order' => $i, ]); } } else { AnswerOption::create([ 'question_id' => $q->id, 'text' => $r->number_answer, 'is_correct' => true, 'sort_order' => 0, ]); } return redirect()->route('admin.questions.index')->with('success','Frage gespeichert.'); } public function edit(Question $question) { $subjects = Subject::all(); $question->load('answerOptions'); return view('admin.questions.edit', compact('question','subjects')); } public function update(Request $r, Question $question) { $r->validate([ 'subject_id' => 'required|exists:subjects,id', 'question_text' => 'required|string', 'difficulty' => 'required|in:1,2,3', 'options' => 'array', 'options.*' => 'string', 'correct' => 'integer', ]); $pts = [1=>5, 2=>10, 3=>20][$r->difficulty]; $question->update([ 'subject_id' => $r->subject_id, 'question_text' => $r->question_text, 'difficulty' => $r->difficulty, 'points_value' => $pts, 'active' => $r->boolean('active', true), ]); if ($r->filled('options')) { $question->answerOptions()->delete(); foreach ($r->options as $i => $text) { if (trim($text) === '') continue; AnswerOption::create([ 'question_id' => $question->id, 'text' => $text, 'is_correct' => ($i == $r->correct), 'sort_order' => $i, ]); } } return redirect()->route('admin.questions.index')->with('success','Gespeichert.'); } public function destroy(Question $question) { $question->delete(); return redirect()->route('admin.questions.index')->with('success','Frage gelöscht.'); } public function export(Request $r) { $query = Question::with(['subject','answerOptions'])->latest(); if ($r->filled('subject')) $query->where('subject_id', $r->subject); $data = $query->get()->map(fn($q) => [ 'subject' => $q->subject->slug, 'question_text' => $q->question_text, 'type' => $q->type, 'difficulty' => $q->difficulty, 'points_value' => $q->points_value, 'active' => (bool)$q->active, 'options' => $q->answerOptions->map(fn($o) => [ 'text' => $o->text, 'is_correct' => (bool)$o->is_correct, ])->values(), ]); $filename = 'fragen-' . now()->format('Y-m-d') . '.json'; return response()->streamDownload( fn() => print(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)), $filename, ['Content-Type' => 'application/json'] ); } public function import(Request $r) { $r->validate(['file' => 'required|file|mimes:json|max:2048']); $raw = json_decode(file_get_contents($r->file('file')->getRealPath()), true); if (!is_array($raw)) { return back()->with('error', 'Ungültiges JSON-Format.'); } $subjects = Subject::pluck('id','slug'); $imported = 0; $skipped = 0; DB::transaction(function() use ($raw, $subjects, &$imported, &$skipped) { foreach ($raw as $item) { if (empty($item['subject']) || !isset($subjects[$item['subject']])) { $skipped++; continue; } if (empty($item['question_text'])) { $skipped++; continue; } $q = Question::create([ 'subject_id' => $subjects[$item['subject']], 'question_text' => $item['question_text'], 'type' => $item['type'] ?? 'multiple_choice', 'difficulty' => $item['difficulty'] ?? 1, 'points_value' => $item['points_value'] ?? 5, 'active' => $item['active'] ?? true, ]); foreach (($item['options'] ?? []) as $i => $opt) { AnswerOption::create([ 'question_id' => $q->id, 'text' => $opt['text'], 'is_correct' => $opt['is_correct'] ?? false, 'sort_order' => $i, ]); } $imported++; } }); $msg = "{$imported} Fragen importiert."; if ($skipped) $msg .= " {$skipped} übersprungen (unbekanntes Fach oder fehlender Text)."; return back()->with('success', $msg); } }