admin: Mail-Sperrliste, Markierung nicht erreichbarer Newsrooms (Roadmap 1b.6, Schritt 4)
Admin ▸ Mail-Sperrliste mit Freigabe, manueller Sperre, nicht lesbaren Rückläufern und Breaker-Zustand. Firmenseite markiert gesperrte Firmen-E-Mail und Pressekontakte. Die Claim-Seite zählt gesperrte Adressen nicht mehr als Empfänger und erklärt, warum kein Link geht. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f9c97ccf2f
commit
e7e12b9436
12 changed files with 426 additions and 9 deletions
|
|
@ -42,6 +42,7 @@ class NewsroomClaimController extends Controller
|
|||
return view('web.newsroom-claim', [
|
||||
'company' => $company,
|
||||
'recipients' => $this->claims->maskedRecipients($company),
|
||||
'unreachable' => $this->claims->isUnreachable($company),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ class NewsroomClaimController extends Controller
|
|||
RateLimiter::hit($this->companyKey($company->getKey()), 86400);
|
||||
|
||||
if ($this->claims->recipients($company)->isEmpty()) {
|
||||
return back()->with('newsroom-claim-none', true);
|
||||
return back()->with($this->claims->isUnreachable($company) ? 'newsroom-claim-unreachable' : 'newsroom-claim-none', true);
|
||||
}
|
||||
|
||||
// Enumeration-sicher: dieselbe Meldung, ob ein Konto deaktiviert ist
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Enums\ConversionSource;
|
|||
use App\Models\Company;
|
||||
use App\Scopes\PortalScope;
|
||||
use App\Services\Auth\ContactAccessService;
|
||||
use App\Services\Mail\EmailSuppressionService;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
@ -26,7 +27,10 @@ use Illuminate\Support\Str;
|
|||
*/
|
||||
class NewsroomClaimService
|
||||
{
|
||||
public function __construct(private readonly ContactAccessService $contactAccess) {}
|
||||
public function __construct(
|
||||
private readonly ContactAccessService $contactAccess,
|
||||
private readonly EmailSuppressionService $suppressions,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Firma zu einem Slug auf diesen Portalen — auch ohne veröffentlichte
|
||||
|
|
@ -48,16 +52,42 @@ class NewsroomClaimService
|
|||
/**
|
||||
* Empfänger des Anmeldelinks: die Firmen-E-Mail, sonst die Adressen der
|
||||
* Pressekontakte. Bewusst nicht beides — ein Klick eines Fremden soll
|
||||
* nicht fünf Postfächer treffen.
|
||||
* nicht fünf Postfächer treffen. Gesperrte Adressen (Bounce-Suppression,
|
||||
* 1b.6) zählen nicht: Ein Newsroom, dessen einzige Adresse tot ist, ist
|
||||
* nicht beanspruchbar — siehe isUnreachable().
|
||||
*
|
||||
* @return Collection<int, string>
|
||||
*/
|
||||
public function recipients(Company $company): Collection
|
||||
{
|
||||
$candidates = $this->candidateRecipients($company);
|
||||
|
||||
if ($candidates === []) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$suppressed = $this->suppressions->suppressedAmong($candidates);
|
||||
|
||||
return collect(array_values(array_filter($candidates, fn (string $email): bool => ! in_array($email, $suppressed, true))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Es gäbe Adressen, aber alle sind gesperrt.
|
||||
*/
|
||||
public function isUnreachable(Company $company): bool
|
||||
{
|
||||
return $this->candidateRecipients($company) !== [] && $this->recipients($company)->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function candidateRecipients(Company $company): array
|
||||
{
|
||||
$companyEmail = Company::emailKey($company->email);
|
||||
|
||||
if ($companyEmail !== null) {
|
||||
return collect([$companyEmail]);
|
||||
return [$companyEmail];
|
||||
}
|
||||
|
||||
$emails = [];
|
||||
|
|
@ -70,7 +100,7 @@ class NewsroomClaimService
|
|||
}
|
||||
}
|
||||
|
||||
return collect(array_values($emails));
|
||||
return array_values($emails);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue