E-Mail-Praeferenzen: Opt-out je Mail-Typ + One-Click-Unsubscribe ohne Login
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
06d80b255b
commit
51da374173
21 changed files with 746 additions and 9 deletions
83
app/Http/Controllers/EmailUnsubscribeController.php
Normal file
83
app/Http/Controllers/EmailUnsubscribeController.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\EmailNotificationType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* One-Click-Abmeldung von Benachrichtigungs-Mails, ohne Login.
|
||||
*
|
||||
* Die Links in den Mail-Footern sind signiert und ohne Ablauf (Links aus
|
||||
* alten Mails bleiben gültig). Der GET-Aufruf trägt den Empfänger direkt
|
||||
* aus und zeigt die Bestätigungsseite mit der Möglichkeit, die Abmeldung
|
||||
* rückgängig zu machen. Der POST auf dieselbe URL bedient den
|
||||
* List-Unsubscribe-Header (RFC 8058) — Mail-Clients senden ihn ohne
|
||||
* Nutzer-Interaktion auf der Seite.
|
||||
*/
|
||||
class EmailUnsubscribeController extends Controller
|
||||
{
|
||||
public function show(Request $request, User $user, string $type): View
|
||||
{
|
||||
$notificationType = $this->resolveType($type);
|
||||
|
||||
if (! $request->hasValidSignature()) {
|
||||
return view('web.email-unsubscribe', [
|
||||
'state' => 'invalid',
|
||||
'notificationType' => $notificationType,
|
||||
]);
|
||||
}
|
||||
|
||||
$user->optOutOfEmailNotification($notificationType);
|
||||
|
||||
return view('web.email-unsubscribe', [
|
||||
'state' => 'unsubscribed',
|
||||
'notificationType' => $notificationType,
|
||||
'resubscribeUrl' => URL::signedRoute('email-preferences.resubscribe', [
|
||||
'user' => $user->id,
|
||||
'type' => $notificationType->value,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC-8058-Endpunkt: Mail-Clients senden `List-Unsubscribe=One-Click`
|
||||
* per POST, ohne die Seite zu öffnen. Antwort bewusst schlicht (2xx).
|
||||
*/
|
||||
public function oneClickUnsubscribe(Request $request, User $user, string $type): Response
|
||||
{
|
||||
abort_unless($request->hasValidSignature(), 403);
|
||||
|
||||
$user->optOutOfEmailNotification($this->resolveType($type));
|
||||
|
||||
return response('Sie wurden erfolgreich abgemeldet.');
|
||||
}
|
||||
|
||||
public function resubscribe(Request $request, User $user, string $type): View|RedirectResponse
|
||||
{
|
||||
abort_unless($request->hasValidSignature(), 403);
|
||||
|
||||
$notificationType = $this->resolveType($type);
|
||||
|
||||
$user->optIntoEmailNotification($notificationType);
|
||||
|
||||
return view('web.email-unsubscribe', [
|
||||
'state' => 'resubscribed',
|
||||
'notificationType' => $notificationType,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveType(string $type): EmailNotificationType
|
||||
{
|
||||
$notificationType = EmailNotificationType::tryFrom($type);
|
||||
|
||||
abort_if($notificationType === null, 404);
|
||||
|
||||
return $notificationType;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue