Files
WebAPP/app/Http/Controllers/Admin/TeamController.php
Rhino 2e24a40d68 Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er)
- Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link
- Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest
- Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen)
- Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:30:37 +01:00

210 lines
6.8 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers\Admin;
use App\Enums\UserRole;
use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\File;
use App\Models\FileCategory;
use App\Models\Player;
use App\Models\Team;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\View\View;
class TeamController extends Controller
{
public function index(): View
{
$teams = Team::withCount(['players', 'events'])->latest()->paginate(20);
return view('admin.teams.index', compact('teams'));
}
public function create(): View
{
return view('admin.teams.create');
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'name' => ['required', 'string', 'max:255'],
'year_group' => ['nullable', 'string', 'max:20'],
'is_active' => ['boolean'],
]);
$validated['is_active'] = $request->boolean('is_active', true);
Team::create($validated);
return redirect()->route('admin.teams.index')
->with('success', __('admin.team_created'));
}
public function edit(Team $team): View
{
$team->load([
'coaches',
'players' => fn ($q) => $q->orderBy('last_name'),
'files.category',
]);
$allCoaches = User::where('role', UserRole::Coach)
->where('is_active', true)
->orderBy('name')
->get();
$parentReps = $team->parentReps();
$allTeams = Team::active()->orderBy('name')->get();
$fileCategories = FileCategory::active()->ordered()
->with(['files' => fn ($q) => $q->latest()])
->get();
return view('admin.teams.edit', compact(
'team', 'allCoaches', 'parentReps', 'allTeams', 'fileCategories'
));
}
public function update(Request $request, Team $team): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'year_group' => ['nullable', 'string', 'max:20'],
'is_active' => ['boolean'],
'notes' => ['nullable', 'string', 'max:5000'],
'coach_ids' => ['nullable', 'array'],
'coach_ids.*' => ['integer', 'exists:users,id', function ($attr, $value, $fail) {
$user = User::find($value);
if (!$user || $user->role !== \App\Enums\UserRole::Coach) {
$fail(__('validation.exists', ['attribute' => $attr]));
}
}],
'existing_files' => ['nullable', 'array'],
'existing_files.*' => ['integer', 'exists:files,id'],
'new_files' => ['nullable', 'array'],
'new_files.*' => ['file', 'max:10240', 'mimes:pdf,docx,xlsx,jpg,jpeg,png,gif,webp'],
'new_file_categories' => ['nullable', 'array'],
'new_file_categories.*' => ['integer', 'exists:file_categories,id'],
]);
$oldData = [
'name' => $team->name,
'year_group' => $team->year_group,
'is_active' => $team->is_active,
'notes' => $team->notes,
];
$team->update([
'name' => $request->input('name'),
'year_group' => $request->input('year_group'),
'is_active' => $request->boolean('is_active', true),
'notes' => $request->input('notes'),
]);
// Trainer-Zuordnung sync
$coachIds = $request->input('coach_ids', []);
$team->coaches()->sync(array_map('intval', $coachIds));
// Dateien sync
$this->syncTeamFiles($team, $request);
$newData = [
'name' => $team->name,
'year_group' => $team->year_group,
'is_active' => $team->is_active,
'notes' => $team->notes,
];
ActivityLog::logWithChanges('updated', __('admin.log_team_updated', ['name' => $team->name]), 'Team', $team->id, $oldData, $newData);
return redirect()->route('admin.teams.edit', $team)
->with('success', __('admin.team_updated'));
}
public function updatePlayerTeam(Request $request, Team $team): JsonResponse
{
$validated = $request->validate([
'player_id' => ['required', 'integer', 'exists:players,id'],
'new_team_id' => ['required', 'integer', 'exists:teams,id'],
]);
$player = Player::findOrFail($validated['player_id']);
// Spieler muss aktuell im Route-Team sein
if ($player->team_id !== $team->id) {
return response()->json(['error' => 'Forbidden'], 403);
}
// Ziel-Team muss existieren und aktiv sein
$newTeam = Team::where('id', $validated['new_team_id'])->where('is_active', true)->first();
if (!$newTeam) {
return response()->json(['error' => 'Ziel-Team nicht gefunden oder inaktiv'], 422);
}
$oldTeamId = $player->team_id;
$player->update(['team_id' => $newTeam->id]);
ActivityLog::logWithChanges(
'updated',
__('admin.log_player_team_changed', ['name' => $player->full_name]),
'Player',
$player->id,
['team_id' => $oldTeamId],
['team_id' => (int) $validated['new_team_id']]
);
return response()->json(['success' => true]);
}
private function syncTeamFiles(Team $team, Request $request): void
{
$existingFileIds = $request->input('existing_files', []);
$newFileIds = [];
$newFiles = $request->file('new_files', []);
$newCategories = $request->input('new_file_categories', []);
foreach ($newFiles as $index => $uploadedFile) {
if (!$uploadedFile || !$uploadedFile->isValid()) {
continue;
}
$categoryId = $newCategories[$index] ?? null;
if (!$categoryId) {
continue;
}
$extension = $uploadedFile->guessExtension();
$storedName = Str::uuid() . '.' . $extension;
Storage::disk('local')->putFileAs('files', $uploadedFile, $storedName);
$file = new File([
'file_category_id' => $categoryId,
'original_name' => $uploadedFile->getClientOriginalName(),
'mime_type' => $uploadedFile->getClientMimeType(),
'size' => $uploadedFile->getSize(),
]);
$file->stored_name = $storedName;
$file->disk = 'private';
$file->uploaded_by = auth()->id();
$file->save();
$newFileIds[] = $file->id;
}
$allFileIds = array_merge(
array_map('intval', $existingFileIds),
$newFileIds
);
$team->files()->sync($allFileIds);
}
}