Files
WebAPP/app/Http/Controllers/ProfileController.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

208 lines
6.5 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers;
use App\Enums\UserRole;
use App\Models\ActivityLog;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class ProfileController extends Controller
{
public function edit(): View
{
$user = auth()->user();
$user->load('children.team');
return view('profile.edit', compact('user'));
}
public function update(Request $request): RedirectResponse
{
$supported = \App\Http\Middleware\SetLocaleMiddleware::supportedLocales();
$request->validate([
'name' => 'required|string|max:255',
'phone' => ['nullable', 'string', 'max:30'],
'locale' => ['nullable', 'string', 'in:' . implode(',', $supported)],
'profile_picture' => ['nullable', 'image', 'max:2048', 'mimes:jpg,jpeg,png,gif,webp'],
]);
$user = auth()->user();
// Handle profile picture upload
if ($request->hasFile('profile_picture')) {
// Delete old picture
if ($user->profile_picture) {
Storage::disk('public')->delete($user->profile_picture);
}
$file = $request->file('profile_picture');
$storedName = 'avatars/' . Str::uuid() . '.' . $file->guessExtension();
Storage::disk('public')->putFileAs('', $file, $storedName);
$user->profile_picture = $storedName;
}
$user->update([
'name' => $request->name,
'phone' => $request->input('phone'),
'locale' => $request->input('locale', 'de'),
'profile_picture' => $user->profile_picture,
]);
return back()->with('success', __('profile.updated'));
}
public function removePicture(): RedirectResponse
{
$user = auth()->user();
if ($user->profile_picture) {
Storage::disk('public')->delete($user->profile_picture);
$user->update(['profile_picture' => null]);
}
return back()->with('success', __('admin.picture_removed'));
}
public function uploadDsgvoConsent(Request $request): RedirectResponse
{
$request->validate([
'dsgvo_consent_file' => ['required', 'file', 'max:10240', 'mimes:pdf,jpg,jpeg,png,gif,webp'],
]);
$user = auth()->user();
// Alte Datei löschen falls vorhanden
if ($user->dsgvo_consent_file) {
Storage::disk('local')->delete($user->dsgvo_consent_file);
}
$file = $request->file('dsgvo_consent_file');
$storedName = 'dsgvo/' . Str::uuid() . '.' . $file->guessExtension();
Storage::disk('local')->putFileAs('', $file, $storedName);
// Bei Re-Upload: Bestätigung zurücksetzen
$user->dsgvo_consent_file = $storedName;
$user->dsgvo_accepted_at = null;
$user->dsgvo_accepted_by = null;
$user->save();
ActivityLog::log(
'dsgvo_consent_uploaded',
__('admin.log_dsgvo_consent_uploaded', ['name' => $user->name]),
'User',
$user->id
);
return back()->with('success', __('profile.dsgvo_uploaded'));
}
public function removeDsgvoConsent(): RedirectResponse
{
$user = auth()->user();
if ($user->dsgvo_consent_file) {
Storage::disk('local')->delete($user->dsgvo_consent_file);
$user->dsgvo_consent_file = null;
$user->dsgvo_accepted_at = null;
$user->dsgvo_accepted_by = null;
$user->save();
ActivityLog::log(
'dsgvo_consent_removed',
__('admin.log_dsgvo_consent_removed', ['name' => $user->name]),
'User',
$user->id
);
}
return back()->with('success', __('profile.dsgvo_removed'));
}
public function downloadDsgvoConsent(): BinaryFileResponse
{
$user = auth()->user();
if (!$user->dsgvo_consent_file || !str_starts_with($user->dsgvo_consent_file, 'dsgvo/') || !Storage::disk('local')->exists($user->dsgvo_consent_file)) {
abort(404);
}
$mimeType = Storage::disk('local')->mimeType($user->dsgvo_consent_file);
return response()->file(
Storage::disk('local')->path($user->dsgvo_consent_file),
['Content-Type' => $mimeType]
);
}
public function destroy(Request $request): RedirectResponse
{
$request->validate([
'password' => ['required', 'current_password'],
]);
$user = auth()->user();
// Admin (ID 1) kann nicht selbst löschen
if ($user->id === 1) {
return back()->with('error', __('profile.cannot_delete_admin'));
}
// Staff (Admin/Trainer) können sich nicht über die Profilseite löschen
if ($user->isStaff()) {
return back()->with('error', __('profile.cannot_delete_staff'));
}
// Verwaiste Kinder ermitteln und deaktivieren
$orphanedChildren = $user->getOrphanedChildren();
$orphanedChildNames = [];
foreach ($orphanedChildren as $child) {
$child->delete();
$orphanedChildNames[] = $child->full_name;
ActivityLog::log(
'child_auto_deactivated',
__('admin.log_child_auto_deactivated', [
'child' => $child->full_name,
'parent' => $user->name,
]),
'Player',
$child->id,
['parent_user_id' => $user->id, 'reason' => 'sole_parent_self_deleted']
);
}
// Selbstlöschung loggen
ActivityLog::logWithChanges(
'account_self_deleted',
__('admin.log_account_self_deleted', ['name' => $user->name]),
'User',
$user->id,
[
'name' => $user->name,
'email' => $user->email,
'role' => $user->role->value,
'orphaned_children' => $orphanedChildNames,
],
null
);
// Logout + Session invalidieren
auth()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
// User soft-deleten
$user->delete();
return redirect()->route('login')->with('success', __('profile.account_deleted'));
}
}