archive: Beweisarchiv — verschlüsselte Einträge, Legal Hold, Purge mit Tombstone, Restore-Abgleich, Auslöser und Admin-Seite (Bildkennzeichnung Block F)
- archive_entries (append-only) + archive_access_log; Disk archive außerhalb des Web-Roots; eigener ARCHIVE_KEY (archive:key), AES-256-CBC, SHA-256 am Eintrag - EvidenceArchive: record/open/manifest/export (signiertes ZIP), setLegalHold/releaseLegalHold (Frist läuft neu), purgeDue, exportTombstones, reconcileAfterRestore - PressReleaseArchiver: image_removed (Original, Snapshot, Bestätigungen), pm_depublished (letzter veröffentlichter Stand), gdpr_change (Anonymisierung, Korrekturen), label_corrected - Hooks in Remover, depublish/archive/changeStatusFromAdmin/deleteFromAdmin, AnonymizationService, CorrectionService, ImageCorrectionService - Scheduler archive:purge 03:20 und archive:export-tombstones 03:30; archive:reconcile-after-restore im Runbook - Admin ▸ Management ▸ Beweisarchiv (Liste, Legal Hold mit Pflichtvermerk, Öffnen/Export nur mit Zweck) - Scope-Wächter: neue Befehle nutzen withoutGlobalScope(PortalScope::class) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
da167b713b
commit
b5b70416f2
30 changed files with 1746 additions and 6 deletions
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Services\PressRelease;
|
||||
|
||||
use App\Enums\ActivityType;
|
||||
use App\Enums\ArchiveReasonCategory;
|
||||
use App\Enums\LegalRequestStatus;
|
||||
use App\Enums\LegalRequestType;
|
||||
use App\Enums\LegalRequestVerificationMethod;
|
||||
|
|
@ -11,6 +12,7 @@ use App\Models\PressRelease;
|
|||
use App\Models\PressReleaseRedactionSnapshot;
|
||||
use App\Models\User;
|
||||
use App\Services\ActivityLog;
|
||||
use App\Services\Archive\PressReleaseArchiver;
|
||||
use App\Services\PressRelease\Classification\ClassificationManager;
|
||||
use App\Services\PressRelease\Classification\ClassificationResult;
|
||||
use App\Support\WebCaches;
|
||||
|
|
@ -148,6 +150,8 @@ class CorrectionService
|
|||
|
||||
$this->assertNotRateLimited($pressRelease);
|
||||
|
||||
$before = $pressRelease->only(self::CORRECTABLE_FIELDS);
|
||||
|
||||
$legalRequest = DB::transaction(function () use ($pressRelease, $newValues, $requesterEmail, $method, $classification): LegalRequest {
|
||||
$legalRequest = LegalRequest::query()->create([
|
||||
'press_release_id' => $pressRelease->id,
|
||||
|
|
@ -178,6 +182,16 @@ class CorrectionService
|
|||
|
||||
WebCaches::forgetSitemaps();
|
||||
|
||||
app(PressReleaseArchiver::class)->gdprChange(
|
||||
$pressRelease,
|
||||
$before,
|
||||
$pressRelease->fresh()?->only(self::CORRECTABLE_FIELDS) ?? [],
|
||||
$legalRequest,
|
||||
$actor,
|
||||
ArchiveReasonCategory::Correction,
|
||||
'Kleine Korrektur (Selbstbedienung)',
|
||||
);
|
||||
|
||||
$changedFields = collect($classification['fields'])
|
||||
->filter(fn (array $meta): bool => $meta['changed'])
|
||||
->keys()
|
||||
|
|
@ -231,6 +245,8 @@ class CorrectionService
|
|||
return false;
|
||||
}
|
||||
|
||||
$before = $pressRelease->only(self::CORRECTABLE_FIELDS);
|
||||
|
||||
DB::transaction(function () use ($pressRelease, $legalRequest, $classification, $newValues): void {
|
||||
$legalRequest->forceFill([
|
||||
'status' => LegalRequestStatus::Resolved->value,
|
||||
|
|
@ -249,6 +265,16 @@ class CorrectionService
|
|||
|
||||
WebCaches::forgetSitemaps();
|
||||
|
||||
app(PressReleaseArchiver::class)->gdprChange(
|
||||
$pressRelease,
|
||||
$before,
|
||||
$pressRelease->fresh()?->only(self::CORRECTABLE_FIELDS) ?? [],
|
||||
$legalRequest,
|
||||
$actor,
|
||||
ArchiveReasonCategory::Correction,
|
||||
'Kostenpflichtige Änderung',
|
||||
);
|
||||
|
||||
$changedFields = collect($classification['fields'])
|
||||
->filter(fn (array $meta): bool => $meta['changed'])
|
||||
->keys()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue