user()->isAdmin()) { abort(403); } $allSettings = Setting::all()->keyBy('key'); // Event-Default-Keys separieren — immer alle liefern (auch wenn nicht in DB) $eventDefaults = collect(); foreach (['home_game', 'away_game', 'training', 'tournament', 'meeting'] as $type) { foreach (['players', 'catering', 'timekeepers'] as $field) { $key = "default_min_{$field}_{$type}"; $eventDefaults[$key] = $allSettings[$key]->value ?? null; } } $settings = $allSettings->filter(fn ($s) => !str_starts_with($s->key, 'default_min_') && !str_starts_with($s->key, 'visibility_') && !str_starts_with($s->key, 'feature_') && !str_starts_with($s->key, 'impressum_html_') && !str_starts_with($s->key, 'datenschutz_html_') && !str_starts_with($s->key, 'password_reset_email_') ); $fileCategories = FileCategory::ordered()->withCount('files')->get(); // Verfügbare Sprachen und deren locale-spezifische Settings $availableLocales = ['de', 'en', 'pl', 'ru', 'ar', 'tr']; $localeSettings = []; foreach ($availableLocales as $locale) { $localeSettings[$locale] = [ 'impressum_html' => $allSettings["impressum_html_{$locale}"]->value ?? '', 'datenschutz_html' => $allSettings["datenschutz_html_{$locale}"]->value ?? '', 'password_reset_email' => $allSettings["password_reset_email_{$locale}"]->value ?? '', ]; } $seasons = Season::orderByDesc('start_date')->get(); return view('admin.settings.edit', compact( 'settings', 'eventDefaults', 'fileCategories', 'availableLocales', 'localeSettings', 'seasons' )); } public function update(Request $request): RedirectResponse { if (!auth()->user()->isAdmin()) { abort(403, 'Nur Admins koennen Einstellungen aendern.'); } // Bild-Uploads verarbeiten (vor der normalen Settings-Schleife) $imageUploads = [ 'favicon' => ['setting' => 'app_favicon', 'dir' => 'favicon', 'max' => 512], 'logo_login' => ['setting' => 'app_logo_login', 'dir' => 'logos', 'max' => 1024], 'logo_app' => ['setting' => 'app_logo_app', 'dir' => 'logos', 'max' => 1024], ]; foreach ($imageUploads as $field => $config) { if ($request->hasFile($field)) { $request->validate([ $field => 'file|mimes:ico,png,svg,jpg,jpeg,gif,webp|max:' . $config['max'], ]); $oldFile = Setting::get($config['setting']); if ($oldFile) { Storage::disk('public')->delete($oldFile); } $file = $request->file($field); $filename = Str::uuid() . '.' . $file->guessExtension(); $path = $file->storeAs($config['dir'], $filename, 'public'); Setting::set($config['setting'], $path); } elseif ($request->has("remove_{$field}")) { $oldFile = Setting::get($config['setting']); if ($oldFile) { Storage::disk('public')->delete($oldFile); } Setting::set($config['setting'], null); } } $inputSettings = $request->input('settings', []); // Whitelist: Nur erlaubte Setting-Keys akzeptieren $allowedLocales = ['de', 'en', 'pl', 'ru', 'ar', 'tr']; $allowedPrefixes = ['default_min_']; $allowedLocaleKeys = []; foreach ($allowedLocales as $loc) { $allowedLocaleKeys[] = "impressum_html_{$loc}"; $allowedLocaleKeys[] = "datenschutz_html_{$loc}"; $allowedLocaleKeys[] = "password_reset_email_{$loc}"; } $oldValues = Setting::whereIn('key', array_keys($inputSettings))->pluck('value', 'key')->toArray(); foreach ($inputSettings as $key => $value) { // Whitelist-Pruefung: Nur bekannte Keys oder erlaubte Prefixe $isExistingSetting = Setting::where('key', $key)->exists(); $isAllowedLocaleKey = in_array($key, $allowedLocaleKeys); $isAllowedPrefix = false; foreach ($allowedPrefixes as $prefix) { if (str_starts_with($key, $prefix)) { $isAllowedPrefix = true; break; } } if (!$isExistingSetting && !$isAllowedLocaleKey && !$isAllowedPrefix) { continue; // Unbekannten Key ignorieren } $setting = Setting::where('key', $key)->first(); if ($setting) { if ($setting->type === 'html' || $setting->type === 'richtext') { $value = $this->sanitizer->sanitize($value ?? ''); } elseif ($setting->type === 'number') { $value = $value !== null && $value !== '' ? (int) $value : null; } else { $value = strip_tags($value ?? ''); } $setting->update(['value' => $value]); } elseif ($isAllowedLocaleKey) { // Locale-suffixed legal/email settings: upsert mit HTML-Sanitisierung $value = $this->sanitizer->sanitize($value ?? ''); $localeSetting = Setting::where('key', $key)->first(); if ($localeSetting) { $localeSetting->update(['value' => $value]); } else { $localeSetting = new Setting(['label' => $key, 'type' => 'html', 'value' => $value]); $localeSetting->key = $key; $localeSetting->save(); } } elseif ($isAllowedPrefix) { // Event-Defaults: upsert — anlegen wenn nicht vorhanden $prefixSetting = new Setting([ 'label' => $key, 'type' => 'number', 'value' => $value !== null && $value !== '' ? (int) $value : null, ]); $prefixSetting->key = $key; $prefixSetting->save(); } } Setting::clearCache(); $newValues = Setting::whereIn('key', array_keys($inputSettings))->pluck('value', 'key')->toArray(); ActivityLog::logWithChanges('updated', __('admin.log_settings_updated'), 'Setting', null, $oldValues, $newValues); return back()->with('success', __('admin.settings_saved')); } }