Bisher wurde der NullNewsletterSyncClient unbedingt gebunden - NEWSLETTER_SYNC_ENABLED=true mit echtem Provider haette stumm nichts getan. Jetzt: Platzhalter-Provider -> No-Op-Client, aktivierter aber nicht implementierter Provider -> RuntimeException (fail fast). Das Admin-UI weist beim Test-Sync auf den Platzhalter hin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
136 lines
5.5 KiB
PHP
136 lines
5.5 KiB
PHP
<?php
|
||
|
||
namespace App\Providers;
|
||
|
||
use App\Contracts\NewsletterSyncClient;
|
||
use App\Helpers\ThemeHelper;
|
||
use App\Http\Middleware\BlockAdminDuringImpersonation;
|
||
use App\Http\Middleware\EnsureUserIsAdmin;
|
||
use App\Http\Middleware\LogSlowAdminRequests;
|
||
use App\Http\Middleware\SetEdition;
|
||
use App\Listeners\ActivateUserAfterVerification;
|
||
use App\Listeners\SyncCompanyMembershipsOnLogin;
|
||
use App\Models\AdminPreset;
|
||
use App\Models\Category;
|
||
use App\Models\CategoryTranslation;
|
||
use App\Models\Company;
|
||
use App\Models\Contact;
|
||
use App\Models\NewsletterSubscription;
|
||
use App\Models\PressRelease;
|
||
use App\Models\User;
|
||
use App\Observers\AdminPerformanceCacheObserver;
|
||
use App\Services\Admin\AdminRequestPerformanceMetrics;
|
||
use App\Services\Newsletter\NullNewsletterSyncClient;
|
||
use App\Services\PressRelease\PressReleaseService;
|
||
use Illuminate\Auth\Events\Login;
|
||
use Illuminate\Auth\Events\Registered;
|
||
use Illuminate\Auth\Events\Verified;
|
||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||
use Illuminate\Database\Events\QueryExecuted;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Event;
|
||
use Illuminate\Support\Facades\Gate;
|
||
use Illuminate\Support\Facades\URL;
|
||
use Illuminate\Support\ServiceProvider;
|
||
use Laravel\Cashier\Cashier;
|
||
use Livewire\Livewire;
|
||
use Spatie\Permission\Models\Permission;
|
||
use Spatie\Permission\Models\Role;
|
||
|
||
class AppServiceProvider extends ServiceProvider
|
||
{
|
||
/**
|
||
* Register any application services.
|
||
*/
|
||
public function register(): void
|
||
{
|
||
$this->app->bind(NewsletterSyncClient::class, function (): NewsletterSyncClient {
|
||
$provider = (string) config('newsletter.sync.provider', 'placeholder');
|
||
|
||
// Es existiert bislang nur der No-Op-Client. Ein aktivierter, aber
|
||
// nicht implementierter Provider soll laut schlagen statt stumm
|
||
// ins Leere zu synchronisieren.
|
||
if (config('newsletter.sync.enabled') && $provider !== 'placeholder') {
|
||
throw new \RuntimeException(
|
||
"Newsletter-Sync-Provider [{$provider}] ist nicht implementiert – es existiert nur der Platzhalter-Client."
|
||
);
|
||
}
|
||
|
||
return new NullNewsletterSyncClient;
|
||
});
|
||
$this->app->singleton(PressReleaseService::class);
|
||
$this->app->singleton(AdminRequestPerformanceMetrics::class);
|
||
}
|
||
|
||
/**
|
||
* Bootstrap any application services.
|
||
*/
|
||
public function boot(): void
|
||
{
|
||
$scheme = request()->header('X-Forwarded-Proto')
|
||
?? request()->server('HTTP_X_FORWARDED_PROTO')
|
||
?? (request()->secure() ? 'https' : 'http');
|
||
|
||
if ($scheme === 'https') {
|
||
URL::forceScheme('https');
|
||
}
|
||
|
||
// Baseline für das Ausgabe-Präfix (de|en). Die SetEdition-Middleware
|
||
// überschreibt dies pro Request mit der tatsächlichen Ausgabe; der
|
||
// Default hier stellt sicher, dass route('…')-Aufrufe das {edition}-
|
||
// Segment auch außerhalb der HTTP-Middleware erhalten (Livewire-Tests,
|
||
// Konsole, Mails).
|
||
URL::defaults(['edition' => SetEdition::DEFAULT_EDITION]);
|
||
|
||
// Zugriffs-Gates als Single Source of Truth (auch in Blade via @can und in
|
||
// Policies nutzbar). Dieselbe Definition, die die Panel-Middleware prüfen.
|
||
Gate::define('access-admin', fn (User $user): bool => $user->canAccessAdmin());
|
||
Gate::define('access-customer', fn (User $user): bool => $user->canAccessCustomer());
|
||
|
||
// Registrierung → Verifizierungsmail; bestätigter Klick → Aktivierung.
|
||
Event::listen(Registered::class, SendEmailVerificationNotification::class);
|
||
Event::listen(Verified::class, ActivateUserAfterVerification::class);
|
||
|
||
// Bei jedem Login Firmen-/Kontakt-Zuordnungen (gleiche E-Mail) auffrischen.
|
||
Event::listen(Login::class, SyncCompanyMembershipsOnLogin::class);
|
||
|
||
// Stripe Tax berechnet die USt im Checkout automatisch nach den
|
||
// gleichen Regeln wie der VatResolver im MAN-Kreis (DE mit Steuer,
|
||
// EU nur mit USt-ID befreit, Drittland befreit). Aktiviert zugleich
|
||
// die USt-ID-Abfrage im Stripe Checkout.
|
||
Cashier::calculateTaxes();
|
||
|
||
AdminPreset::observe(AdminPerformanceCacheObserver::class);
|
||
Category::observe(AdminPerformanceCacheObserver::class);
|
||
CategoryTranslation::observe(AdminPerformanceCacheObserver::class);
|
||
Company::observe(AdminPerformanceCacheObserver::class);
|
||
Contact::observe(AdminPerformanceCacheObserver::class);
|
||
NewsletterSubscription::observe(AdminPerformanceCacheObserver::class);
|
||
PressRelease::observe(AdminPerformanceCacheObserver::class);
|
||
User::observe(AdminPerformanceCacheObserver::class);
|
||
Permission::observe(AdminPerformanceCacheObserver::class);
|
||
Role::observe(AdminPerformanceCacheObserver::class);
|
||
|
||
DB::listen(fn (QueryExecuted $query) => app(AdminRequestPerformanceMetrics::class)->record($query));
|
||
|
||
Livewire::addPersistentMiddleware([
|
||
BlockAdminDuringImpersonation::class,
|
||
EnsureUserIsAdmin::class,
|
||
LogSlowAdminRequests::class,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Set the asset URL dynamically based on the current theme
|
||
*/
|
||
protected function setDynamicAssetUrl(): void
|
||
{
|
||
try {
|
||
$assetUrl = ThemeHelper::getAssetUrl();
|
||
config(['app.asset_url' => $assetUrl]);
|
||
} catch (\Exception $e) {
|
||
// Fallback to default if theme detection fails
|
||
config(['app.asset_url' => 'https://assets.pressekonto.test']);
|
||
}
|
||
}
|
||
}
|