From 085ea7c3ca89a182ebbe0b5dddc7b0da39f9c1dd Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 May 2026 15:09:14 +0000 Subject: [PATCH] feat: Fragen-Export (JSON) und -Import im Admin-Bereich --- .../Controllers/Admin/QuestionController.php | 61 +++++++++++++++++++ .../views/admin/questions/index.blade.php | 32 +++++++++- routes/web.php | 2 + 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Admin/QuestionController.php b/app/Http/Controllers/Admin/QuestionController.php index dc6421f..0c07d42 100644 --- a/app/Http/Controllers/Admin/QuestionController.php +++ b/app/Http/Controllers/Admin/QuestionController.php @@ -5,6 +5,7 @@ use App\Models\Question; use App\Models\Subject; use App\Models\AnswerOption; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class QuestionController extends Controller { public function index(Request $r) { $subjects = Subject::all(); @@ -97,4 +98,64 @@ class QuestionController extends Controller { $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); + } } diff --git a/resources/views/admin/questions/index.blade.php b/resources/views/admin/questions/index.blade.php index e9827ee..23b7aec 100644 --- a/resources/views/admin/questions/index.blade.php +++ b/resources/views/admin/questions/index.blade.php @@ -1,7 +1,7 @@ @extends('layouts.admin') @section('title','Fragen') @section('content') -
+
- + Neue Frage +
+ {{-- Export --}} + + ⬇ Export JSON + + {{-- Import trigger --}} + + + Neue Frage +
+ + {{-- Import panel --}} +
+
+

Fragen importieren

+

JSON-Datei im gleichen Format wie der Export. Bestehende Fragen bleiben erhalten.

+
+ @csrf + + +
+
+
diff --git a/routes/web.php b/routes/web.php index aa7848c..a4c3e19 100755 --- a/routes/web.php +++ b/routes/web.php @@ -17,6 +17,8 @@ Route::middleware(['auth','admin'])->prefix('admin')->name('admin.')->group(func Route::get('/', [Admin\DashboardController::class, 'index'])->name('dashboard'); Route::resource('users', Admin\UserController::class); Route::post('users/{user}/reset', [Admin\UserController::class, 'reset'])->name('users.reset'); + Route::get ('questions/export', [Admin\QuestionController::class,'export'])->name('questions.export'); + Route::post('questions/import', [Admin\QuestionController::class,'import'])->name('questions.import'); Route::resource('questions',Admin\QuestionController::class); Route::resource('rewards', Admin\RewardController::class)->except('show'); Route::get ('redemptions', [Admin\RedemptionController::class,'index']) ->name('redemptions.index');