- press_release_images: Kundenangabe/Portalkennzeichnung getrennt, Herkunftsbefund, Beweisoriginal, Snapshot-Pfade, published_ever_at, rules_version, Fokus/Letterbox; Bestand unangetastet - legal_texts (insert-only) mit img-confirm-v1 (alter Wortlaut), v2 (AGB 0.6), v3 (AGB 0.7, noch ohne Datum); image-rights:backfill-confirmations - image_rights_confirmations polymorph, insert-only, IP als versionierter HMAC; Löschung nur für nie veröffentlichte Uploads - ImageProvenanceInspector (Imagick/exif): IPTC, XMP, EXIF; algorithmicallyEnhanced nur Vermerk; unlesbare Datei = error - PressReleaseImageUploader: Original vor Derivaten, Hash-Bindung, Titelbild-Regel unter Sperre, Dateien bei Fehlern zurückgerollt; Admin-Upload ohne Bestätigung - ImageService: kein Rückfall auf die Quelldatei, og-Variante, Fokuspunkt und no_crop Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
84 lines
3.1 KiB
PHP
84 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Enums\ConfirmationChannel;
|
|
use App\Models\ImageRightsConfirmation;
|
|
use App\Models\LegalText;
|
|
use App\Models\PressReleaseImage;
|
|
use Illuminate\Console\Command;
|
|
|
|
/**
|
|
* Bildkennzeichnung A.3: Die Bestätigungen des alten Formulars
|
|
* (`rights_confirmed_at`, ohne Kennung) bekommen rückwirkend je eine Zeile
|
|
* im Protokoll mit Verweis auf `img-confirm-v1`. Ohne IP und User-Agent —
|
|
* die wurden damals nicht erfasst. Idempotent.
|
|
*/
|
|
class BackfillImageRightsConfirmations extends Command
|
|
{
|
|
protected $signature = 'image-rights:backfill-confirmations {--dry-run : Nur zählen, nichts schreiben}';
|
|
|
|
protected $description = 'Legt für Bilder des alten Formulars rückwirkend einen Protokolleintrag mit img-confirm-v1 an';
|
|
|
|
public function handle(): int
|
|
{
|
|
$text = LegalText::findByKey('img-confirm-v1');
|
|
|
|
if ($text === null) {
|
|
$this->error('img-confirm-v1 fehlt — zuerst LegalTextSeeder ausführen.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$query = PressReleaseImage::query()
|
|
->withTrashed()
|
|
->whereNotNull('rights_confirmed_at')
|
|
->whereDoesntHave('rightsConfirmations')
|
|
->with('pressRelease');
|
|
|
|
$count = $query->count();
|
|
$this->info("Bilder mit alter Bestätigung ohne Protokoll: {$count}");
|
|
|
|
if ($this->option('dry-run') || $count === 0) {
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$written = 0;
|
|
|
|
$query->chunkById(200, function ($images) use ($text, &$written): void {
|
|
foreach ($images as $image) {
|
|
ImageRightsConfirmation::query()->create([
|
|
'subject_type' => $image->getMorphClass(),
|
|
'subject_id' => $image->getKey(),
|
|
'press_release_id' => $image->press_release_id,
|
|
'company_id' => $image->pressRelease?->company_id,
|
|
'user_id' => $image->pressRelease?->user_id,
|
|
'channel' => ConfirmationChannel::Form,
|
|
'legal_text_id' => $text->id,
|
|
'legal_text_key' => $text->key,
|
|
'text_snapshot' => $text->body,
|
|
'agb_version' => $text->bound_agb_version,
|
|
'locale' => $text->locale,
|
|
'file_sha256' => null,
|
|
'declaration_snapshot' => [
|
|
'copyright' => $image->copyright,
|
|
'author' => $image->author,
|
|
'license_type' => $image->license_type?->value,
|
|
'license_detail' => $image->license_detail,
|
|
'license_url' => $image->license_url,
|
|
'source_url' => $image->source_url,
|
|
'ai_declaration' => $image->ai_declaration?->value,
|
|
'backfilled' => true,
|
|
],
|
|
'confirmed_at' => $image->rights_confirmed_at,
|
|
'created_at' => now(),
|
|
]);
|
|
$written++;
|
|
}
|
|
});
|
|
|
|
$this->info("Protokolleinträge angelegt: {$written}");
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|