ordered() ->withCount('files') ->get(); $activeCategory = $request->query('category'); $query = File::with(['category', 'uploader']) ->whereHas('category', fn ($q) => $q->where('is_active', true)) ->latest(); if ($activeCategory) { $query->whereHas('category', fn ($q) => $q->where('slug', $activeCategory)); } // Nicht-Staff-Nutzer sehen nur Dateien ohne Team-Zuordnung oder aus eigenen Teams $user = auth()->user(); if (!$user->canAccessAdminPanel()) { $userTeamIds = $user->accessibleTeamIds(); $query->where(function ($q) use ($userTeamIds) { $q->whereDoesntHave('teams') ->orWhereHas('teams', fn ($tq) => $tq->whereIn('teams.id', $userTeamIds)); }); } $files = $query->paginate(25)->withQueryString(); return view('files.index', compact('categories', 'files', 'activeCategory')); } public function download(File $file): StreamedResponse { $this->authorizeFileAccess($file); $path = $file->getStoragePath(); if (!Storage::disk('local')->exists($path)) { abort(404); } return Storage::disk('local')->download($path, $file->original_name); } public function preview(File $file) { $this->authorizeFileAccess($file); if (!$file->isImage() && !$file->isPdf()) { abort(404); } $path = $file->getStoragePath(); if (!Storage::disk('local')->exists($path)) { abort(404); } return response()->file( Storage::disk('local')->path($path), ['Content-Type' => $file->mime_type] ); } /** * Autorisierung: User muss Zugriff auf die Datei-Kategorie haben. * Admins/Coaches duerfen alles, Eltern nur Dateien aus aktiven Kategorien * die einem ihrer Teams zugeordnet sind oder allgemein verfuegbar sind. */ private function authorizeFileAccess(File $file): void { $user = auth()->user(); // Staff darf alles if ($user->canAccessAdminPanel()) { return; } // Datei muss zu einer aktiven Kategorie gehoeren if (!$file->category || !$file->category->is_active) { abort(403); } // Pruefen ob Datei einem Team zugeordnet ist, auf das der User Zugriff hat $userTeamIds = $user->accessibleTeamIds(); $fileTeamIds = $file->teams()->pluck('teams.id'); // Datei ohne Team-Zuordnung = allgemein verfuegbar if ($fileTeamIds->isEmpty()) { return; } // Mindestens ein Team muss uebereinstimmen if ($fileTeamIds->intersect($userTeamIds)->isEmpty()) { abort(403); } } }