prefix('admin/me') ->name('me.') ->group(function () { Route::livewire('/', 'customer.dashboard')->name('dashboard'); Route::livewire('press-releases', 'customer.press-releases.index')->name('press-releases.index'); Route::livewire('press-releases/create', 'customer.press-releases.create')->name('press-releases.create'); Route::livewire('press-releases/{id}', 'customer.press-releases.show')->name('press-releases.show'); Route::livewire('press-releases/{id}/edit', 'customer.press-releases.edit')->name('press-releases.edit'); Route::get('press-releases/{id}/nachweis', ProofPdfController::class) ->where('id', '[0-9]+') ->name('press-releases.proof'); // Meldeverfahren (Phase 3): Eigentümer-Einstieg ohne Magic-Link — // die Zuordnung der PM ersetzt die Verifikation (logged_in). Route::post('press-releases/{pressReleaseId}/melden', [PressReleaseReportController::class, 'startFromCustomer']) ->where('pressReleaseId', '[0-9]+') ->name('press-releases.report'); Route::livewire('firmen', 'customer.press-kits.index')->name('press-kits.index'); Route::livewire('firmen/anlegen', 'customer.press-kits.create')->name('press-kits.create'); Route::livewire('firmen/{id}', 'customer.press-kits.show')->name('press-kits.show'); Route::redirect('pressemappen', '/admin/me/firmen', 301); Route::get('pressemappen/{id}', fn (string $id) => redirect("/admin/me/firmen/{$id}", 301)) ->where('id', '[0-9]+'); Route::livewire('buchungen-add-ons', 'customer.bookings')->name('bookings.index'); Route::get('checkout/abo/{planSlug}/{interval}', [CheckoutController::class, 'subscription']) ->whereIn('interval', ['monthly', 'yearly']) ->name('checkout.subscription'); Route::post('checkout/tarifwechsel/{planSlug}/{interval}', [CheckoutController::class, 'swap']) ->whereIn('interval', ['monthly', 'yearly']) ->name('checkout.swap'); Route::get('checkout/einzel-pm', [CheckoutController::class, 'singlePm']) ->name('checkout.single-pm'); Route::get('checkout/credits/{pack}', [CheckoutController::class, 'creditTopup']) ->name('checkout.credit-topup'); Route::get('checkout/depublikation/{pressReleaseId}', [CheckoutController::class, 'depublication']) ->where('pressReleaseId', '[0-9]+') ->name('checkout.depublication'); Route::get('checkout/aenderung/{pressReleaseId}', [CheckoutController::class, 'change']) ->where('pressReleaseId', '[0-9]+') ->name('checkout.change'); Route::get('checkout/abo-verwalten', [CheckoutController::class, 'billingPortal']) ->name('checkout.billing-portal'); Route::livewire('invoices', 'customer.invoices')->name('invoices.index'); Route::get('legacy-invoices/{legacyInvoice}/pdf', LegacyInvoicePdfController::class)->name('invoices.pdf'); Route::get('invoices/{invoice}/stripe', StripeInvoiceRedirectController::class)->name('invoices.stripe'); Route::get('invoices/{invoice}/pdf', InvoicePdfController::class)->name('invoices.manual-pdf'); Route::livewire('tokens', 'customer.tokens')->name('tokens.index'); Route::livewire('profile', 'customer.profile')->name('profile'); Route::livewire('security', 'customer.security')->name('security'); }); // ============================================================ // E-Mail-Benachrichtigungen: One-Click-Abmeldung ohne Login. // Signierte Links aus den Benachrichtigungs-Mails (kein Ablauf, damit // auch alte Mails funktionieren). Der POST auf die Abmelde-URL bedient // den List-Unsubscribe-Header (RFC 8058, ohne CSRF — Ausnahme in // bootstrap/app.php); der Wieder-Anmelden-POST kommt von der // Bestätigungsseite selbst. // ============================================================ Route::prefix('e-mail-benachrichtigungen') ->name('email-preferences.') ->middleware('throttle:30,1') ->group(function () { Route::get('abmelden/{user}/{type}', [EmailUnsubscribeController::class, 'show']) ->name('unsubscribe'); Route::post('abmelden/{user}/{type}', [EmailUnsubscribeController::class, 'oneClickUnsubscribe']) ->name('unsubscribe.one-click'); Route::post('anmelden/{user}/{type}', [EmailUnsubscribeController::class, 'resubscribe']) ->name('resubscribe'); // Roadmap 1d.3: Abmeldung für Empfänger ohne Konto (Pressekontakt, // Firmen-E-Mail einer API-Meldung) — adressbezogen, in der // Sperrliste geführt. Signiert, damit nur ein Link aus unserer Mail // eine Adresse abmelden kann. Route::get('abmelden-adresse', [EmailUnsubscribeController::class, 'showAddress']) ->name('unsubscribe-address'); Route::post('abmelden-adresse', [EmailUnsubscribeController::class, 'oneClickUnsubscribeAddress']) ->name('unsubscribe-address.one-click'); Route::post('anmelden-adresse', [EmailUnsubscribeController::class, 'resubscribeAddress']) ->name('resubscribe-address'); }); // ============================================================ // Legacy /customer/*-Pfade als 301-Redirect erhalten, // damit Bookmarks und alte Mails weiter funktionieren. // ============================================================ Route::prefix('customer')->group(function () { Route::redirect('/', '/admin/me', 301); Route::redirect('press-releases', '/admin/me/press-releases', 301); Route::redirect('press-releases/create', '/admin/me/press-releases/create', 301); Route::get('press-releases/{id}', fn (string $id) => redirect("/admin/me/press-releases/{$id}", 301)) ->where('id', '[0-9]+'); Route::get('press-releases/{id}/edit', fn (string $id) => redirect("/admin/me/press-releases/{$id}/edit", 301)) ->where('id', '[0-9]+'); Route::redirect('pressemappen', '/admin/me/firmen', 301); Route::get('pressemappen/{id}', fn (string $id) => redirect("/admin/me/firmen/{$id}", 301)) ->where('id', '[0-9]+'); Route::redirect('buchungen-add-ons', '/admin/me/buchungen-add-ons', 301); Route::redirect('invoices', '/admin/me/invoices', 301); Route::redirect('tokens', '/admin/me/tokens', 301); Route::redirect('profile', '/admin/me/profile', 301); Route::redirect('security', '/admin/me/security', 301); });