presseportale/app/Services/PressRelease/Images/CustomerImageConfirmation.php
Kevin Adametz 3d3ddc2dc8 images: Titelbild-Formular v2, Admin-Upload mit Kundenbestätigung, Entfernen mit Sofortlöschung (Bildkennzeichnung Block B)
- press-release-images-manager-v2 hinter IMAGE_RIGHTS_V2: drei Blöcke, Vorbelegung aus Metadaten, Bestätigung mit archiviertem Wortlaut, Bild-Bindung über Hash, Fokuspunkt und Letterbox, Zustände absent/prefilled/error
- CustomerImageConfirmation: Magic-Link an den Kontoinhaber, Karte auf der Kundenseite, Kanal magic_link
- PressReleaseImageRemover: nie veröffentlicht = alles sofort weg, veröffentlicht = Soft Delete, Original bleibt
- ConversionSource::MailImageConfirmation

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 09:31:32 +00:00

83 lines
2.7 KiB
PHP

<?php
namespace App\Services\PressRelease\Images;
use App\Enums\ConfirmationChannel;
use App\Enums\ConversionSource;
use App\Mail\PressReleaseImageConfirmationRequested;
use App\Models\ImageRightsConfirmation;
use App\Models\PressReleaseImage;
use App\Models\User;
use App\Services\Auth\MagicLinkGenerator;
use Illuminate\Support\Facades\Mail;
/**
* Kundenbestätigung für Admin-Uploads (Decision-Update E10, Block B.4):
* Der Kontoinhaber der Meldung bekommt einen Magic-Link „Bild bestätigen",
* der ihn auf die Meldung im Konto führt. Dort gibt er dieselbe Bestätigung
* ab wie beim eigenen Upload; das Protokoll trägt den Kanal `magic_link`.
*/
class CustomerImageConfirmation
{
public const LINK_TTL_MINUTES = 60 * 24 * 3;
public function __construct(
private readonly MagicLinkGenerator $magicLinks,
private readonly PressReleaseImageUploader $uploader,
) {}
/**
* Link erzeugen und Mail an den Kontoinhaber schicken. Erneut aufrufbar;
* ein neuer Link entwertet den alten (MagicLinkGenerator).
*/
public function request(PressReleaseImage $image, ?string $requestedIp = null): bool
{
$pressRelease = $image->pressRelease;
$owner = $pressRelease?->user;
if ($pressRelease === null || $owner === null || blank($owner->email)) {
return false;
}
$link = $this->magicLinks->createLoginLink(
$owner,
$requestedIp,
self::LINK_TTL_MINUTES,
ConversionSource::MailImageConfirmation,
[
'company_id' => $pressRelease->company_id,
'press_release_id' => $pressRelease->id,
'image_confirmation' => $image->id,
],
);
if ($image->customer_confirmation_requested_at === null) {
$image->forceFill(['customer_confirmation_requested_at' => now()])->save();
}
Mail::to($owner->email)->queue(
(new PressReleaseImageConfirmationRequested(
$pressRelease,
$image,
route('magic-links.consume', ['token' => $link['plain_token']]),
$link['expires_at'],
$owner->name,
))->afterCommit(),
);
return true;
}
/**
* Bestätigung des Kontoinhabers im Konto (Kanal magic_link).
*/
public function confirm(PressReleaseImage $image, User $customer, ?string $legalTextKey, ?string $ip, ?string $userAgent, ?string $agbUrl = null): ImageRightsConfirmation
{
return $this->uploader->confirmExisting(
$image,
new ImageUploadActor($customer, ConfirmationChannel::MagicLink, null, $ip, $userAgent),
$legalTextKey,
$agbUrl,
);
}
}