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>
This commit is contained in:
Rhino
2026-03-02 07:30:37 +01:00
commit 2e24a40d68
9633 changed files with 1300799 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Providers;
use App\Services\GeocodingService;
use App\Services\HtmlSanitizerService;
use App\Services\InvitationService;
use App\Services\SupportApiService;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(HtmlSanitizerService::class);
$this->app->singleton(GeocodingService::class);
$this->app->singleton(InvitationService::class);
$this->app->singleton(SupportApiService::class);
// During installation: ensure .env exists, APP_KEY is set,
// and session/cache use file driver (database may not exist yet).
// This must happen in register() — before middleware and any cache access.
if (! file_exists(storage_path('installed'))) {
$envPath = base_path('.env');
if (! file_exists($envPath) && file_exists(base_path('.env.example'))) {
copy(base_path('.env.example'), $envPath);
}
if (file_exists($envPath) && empty(config('app.key'))) {
$key = 'base64:'.base64_encode(random_bytes(32));
$envContent = file_get_contents($envPath);
$envContent = preg_replace('/^APP_KEY=.*$/m', 'APP_KEY='.$key, $envContent);
file_put_contents($envPath, $envContent);
config(['app.key' => $key]);
}
// Session und Cache auf Datei-basiert umschalten.
// Die .env hat SESSION_DRIVER=database und CACHE_STORE=database,
// aber vor der Installation existiert die Datenbank noch nicht.
config([
'session.driver' => 'file',
'cache.default' => 'file',
'session.cookie' => 'handball_installer_session',
'session.encrypt' => false, // Verschluesselung braucht stabilen Key; bei Erstinstall unnoetig
]);
}
}
public function boot(): void
{
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)->by($request->input('email') . '|' . $request->ip());
});
RateLimiter::for('registration', function (Request $request) {
return Limit::perHour(5)->by($request->ip());
});
RateLimiter::for('user-actions', function (Request $request) {
return Limit::perMinute(30)->by($request->user()?->id ?: $request->ip());
});
RateLimiter::for('geocoding', function (Request $request) {
return Limit::perMinute(30)->by($request->ip());
});
}
}