validated(); $email = mb_strtolower($validated['email']); $subscription = DB::transaction(function () use ($request, $validated, $email): NewsletterSubscription { $subscription = NewsletterSubscription::withoutGlobalScopes() ->where('portal', $validated['portal']) ->where('email', $email) ->lockForUpdate() ->first(); // Nur ein fremder, tatsächlich gesetzter Eigentümer blockiert (409). // Verwaiste Datensätze (user_id NULL nach Konto-Löschung/Legacy-Import) // dürfen neu gebunden werden — sonst wäre die portal+email-Kombination // dauerhaft nicht mehr abonnierbar. if ($subscription !== null && $subscription->user_id !== null && $subscription->user_id !== $request->user()->id) { abort(409, 'This email address is already subscribed.'); } if ($subscription === null) { return NewsletterSubscription::withoutGlobalScopes()->create([ 'portal' => $validated['portal'], 'email' => $email, 'user_id' => $request->user()->id, 'salutation_key' => $validated['salutation_key'] ?? null, 'first_name' => $validated['first_name'] ?? null, 'last_name' => $validated['last_name'] ?? null, 'ip_address' => $request->ip(), 'is_confirmed' => false, 'confirmation_token' => Str::random(32), 'subscribed_at' => now(), 'unsubscribed_at' => null, ]); } $attributes = [ 'user_id' => $request->user()->id, 'salutation_key' => $validated['salutation_key'] ?? null, 'first_name' => $validated['first_name'] ?? null, 'last_name' => $validated['last_name'] ?? null, 'ip_address' => $request->ip(), 'subscribed_at' => now(), 'unsubscribed_at' => null, ]; if (! $subscription->is_confirmed) { $attributes['confirmation_token'] = Str::random(32); } $subscription->update($attributes); return $subscription; }); return response()->json([ 'message' => 'Newsletter subscription created.', 'data' => [ 'id' => $subscription->id, 'portal' => $subscription->portal->value, 'email' => $subscription->email, 'is_confirmed' => $subscription->is_confirmed, ], ], 201); } }