- 83 Komponenten: Livewire\Volt\Component → Livewire\Component
- 73 Routen (admin, auth, customer): Volt::route() → Route::livewire()
- 88 Testdateien: Volt::test/actingAs → Livewire::test/actingAs
- VoltServiceProvider gelöscht; composer remove livewire/volt
- config/livewire.php auf v4-Schlüssel (component_layout, component_placeholder,
component_locations, make_command: SFC ohne ⚡). Der alte Schlüssel layout war
wirkungslos; alle gerouteten Komponenten setzen ihr Layout selbst.
- CLAUDE.md, AGENTS.md, boost.json, .cursorrules, Skill volt-development
- Roadmap: erledigt; Larastan erfasst SFCs weiterhin nicht (Blade-Dateien)
Suite 2.325 grün, einer übersprungen; Larastan und Pint ohne Meldung;
route:cache und view:cache laufen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
514 lines
21 KiB
PHP
514 lines
21 KiB
PHP
<?php
|
|
|
|
use App\Enums\AiImageDeclaration;
|
|
use App\Enums\ConfirmationChannel;
|
|
use App\Enums\Portal;
|
|
use App\Mail\PressReleaseImageConfirmationRequested;
|
|
use App\Models\ArchiveEntry;
|
|
use App\Models\Category;
|
|
use App\Models\Company;
|
|
use App\Models\ImageRightsConfirmation;
|
|
use App\Models\LegalDocument;
|
|
use App\Models\LegalText;
|
|
use App\Models\PressRelease;
|
|
use App\Models\PressReleaseImage;
|
|
use App\Models\User;
|
|
use App\Services\PressRelease\Images\CustomerImageConfirmation;
|
|
use App\Services\PressRelease\Images\ImageUploadException;
|
|
use Database\Seeders\LegalDocumentSeeder;
|
|
use Database\Seeders\LegalTextSeeder;
|
|
use Database\Seeders\RolesAndPermissionsSeeder;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Bildkennzeichnung Block B: Formular v2 im Titelbild-Manager, Admin-Upload
|
|
* mit Kundenbestätigung, Entfernen mit Sofortlöschung.
|
|
*/
|
|
beforeEach(function (): void {
|
|
/** @var TestCase $this */
|
|
$this->seed(RolesAndPermissionsSeeder::class);
|
|
$this->seed(LegalDocumentSeeder::class);
|
|
$this->seed(LegalTextSeeder::class);
|
|
Storage::fake('public');
|
|
Storage::fake('local');
|
|
config()->set('images.rights_v2', true);
|
|
});
|
|
|
|
/**
|
|
* @return array{owner: User, pr: PressRelease, company: Company}
|
|
*/
|
|
function makeRightsV2Draft(): array
|
|
{
|
|
$owner = User::factory()->create(['is_active' => true]);
|
|
$owner->assignRole('customer');
|
|
|
|
$company = Company::factory()->presseecho()->create(['name' => 'Beispiel AG']);
|
|
$owner->companies()->attach($company->id, ['role' => 'owner']);
|
|
|
|
$pr = PressRelease::factory()->create([
|
|
'user_id' => $owner->id,
|
|
'company_id' => $company->id,
|
|
'category_id' => Category::factory()->create()->id,
|
|
'portal' => $company->portal->value,
|
|
'status' => 'draft',
|
|
]);
|
|
|
|
return compact('owner', 'pr', 'company');
|
|
}
|
|
|
|
function rightsV2Fixture(string $name): UploadedFile
|
|
{
|
|
return UploadedFile::fake()->createWithContent($name, (string) file_get_contents(base_path('tests/Fixtures/images/'.$name)));
|
|
}
|
|
|
|
/**
|
|
* Veröffentlichte PM mit öffentlicher Detailseite auf presseecho.
|
|
*
|
|
* @return array{owner: User, pr: PressRelease, company: Company}
|
|
*/
|
|
function makeRightsV2Published(): array
|
|
{
|
|
$owner = User::factory()->create(['is_active' => true]);
|
|
$owner->assignRole('customer');
|
|
|
|
$category = Category::factory()->create(['portal' => Portal::Presseecho]);
|
|
$category->translations()->create(['locale' => 'de', 'name' => 'Energie', 'slug' => 'energie-'.$category->id]);
|
|
$company = Company::factory()->presseecho()->create(['name' => 'Beispiel AG', 'is_active' => true]);
|
|
$owner->companies()->attach($company->id, ['role' => 'owner']);
|
|
|
|
$pr = PressRelease::factory()->published()->forPortal(Portal::Presseecho)->for($category)->for($company)->create([
|
|
'user_id' => $owner->id,
|
|
'slug' => 'rights-v2-'.fake()->unique()->numberBetween(1, 99999),
|
|
'published_at' => now()->subDay(),
|
|
'published_ever_at' => now()->subDay(),
|
|
]);
|
|
|
|
return compact('owner', 'pr', 'company');
|
|
}
|
|
|
|
/**
|
|
* Simuliert Deploy 3: neue AGB-Fassung ab heute samt daran gebundenem
|
|
* Bestätigungstext. LegalText::currentFor wählt den an die aktuelle
|
|
* AGB-Fassung gebundenen Text, bisher gilt img-confirm-v2 (AGB 0.6).
|
|
*/
|
|
function activateRightsTextV4(): void
|
|
{
|
|
LegalDocument::factory()->agb()->create(['version' => '0.9-test', 'effective_from' => today()]);
|
|
|
|
$body = 'Neue Fassung der Bestätigung der Bildrechte (AGB {agb_version}).';
|
|
|
|
LegalText::query()->create([
|
|
'key' => 'img-confirm-v4',
|
|
'type' => LegalText::TYPE_IMAGE_RIGHTS_CONFIRMATION,
|
|
'locale' => 'de',
|
|
'title' => 'Bestätigung der Bildrechte',
|
|
'body' => $body,
|
|
'short_body' => 'Ich bestätige die Rechte am Bild (AGB {agb_version}).',
|
|
'bound_agb_version' => '0.9-test',
|
|
'body_sha256' => hash('sha256', $body),
|
|
'effective_from' => today(),
|
|
'note' => 'Testfassung',
|
|
]);
|
|
}
|
|
|
|
test('the edit page embeds the v2 manager only while the flag is on', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('customer.press-releases.edit', ['id' => $pr->id])
|
|
->assertSeeLivewire('components.press-release-images-manager-v2');
|
|
|
|
config()->set('images.rights_v2', false);
|
|
|
|
Livewire::test('customer.press-releases.edit', ['id' => $pr->id])
|
|
->assertSeeLivewire('components.press-release-images-manager')
|
|
->assertDontSeeLivewire('components.press-release-images-manager-v2');
|
|
});
|
|
|
|
test('nachweis, kennzeichnung and the confirmation are the only required inputs', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newCopyright', '')
|
|
->call('saveImage')
|
|
->assertHasErrors(['newCopyright', 'newAiDeclaration', 'newRightsConfirmed'])
|
|
->assertHasNoErrors(['newTitle', 'newLicenseUrl', 'newSourceUrl']);
|
|
|
|
expect($pr->images()->count())->toBe(0);
|
|
});
|
|
|
|
test('without metadata the company name is suggested as credit and the state says so', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->assertSet('newCopyright', 'Beispiel AG')
|
|
->assertSet('provenanceStatus', 'absent')
|
|
->assertSee('Keine Herkunftsdaten in der Datei gefunden.');
|
|
});
|
|
|
|
test('iptc and xmp metadata prefill credit and ai declaration and can be changed', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
$component = Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', rightsV2Fixture('camera-iptc.jpg'))
|
|
->assertSet('newCopyright', 'Musterfirma GmbH / Anna Beispiel')
|
|
->assertSet('newAiDeclaration', '')
|
|
->assertSee('Angaben aus den Metadaten der Datei vorbelegt.');
|
|
|
|
$component
|
|
->set('newImage', rightsV2Fixture('xmp-ai-generated.jpg'))
|
|
->assertSet('newCopyright', 'KI-Bild / Musterfirma')
|
|
->assertSet('newAiDeclaration', 'ai_generated')
|
|
->assertSee('Sie können die Auswahl ändern')
|
|
->set('newAiDeclaration', 'original');
|
|
|
|
expect($component->get('newAiDeclaration'))->toBe('original');
|
|
});
|
|
|
|
test('a manual credit survives a file change but the confirmation toggle does not', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('a.jpg', 640, 480))
|
|
->set('newCopyright', 'Eigener Nachweis')
|
|
->set('newRightsConfirmed', true)
|
|
->set('newImage', rightsV2Fixture('camera-iptc.jpg'))
|
|
->assertSet('newCopyright', 'Eigener Nachweis')
|
|
->assertSet('newRightsConfirmed', false);
|
|
});
|
|
|
|
test('an unreadable file shows the error state and is not accepted', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', rightsV2Fixture('broken.jpg'))
|
|
->assertHasErrors(['newImage']);
|
|
});
|
|
|
|
test('a valid upload stores the image under the new rules with a confirmation and shows it on the card', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', rightsV2Fixture('camera-iptc.jpg'))
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->set('newTitle', 'Werkshalle')
|
|
->set('newLicenseUrl', 'https://example.com/lizenz')
|
|
->set('focus', '100,0')
|
|
->set('newRightsConfirmed', true)
|
|
->call('saveImage')
|
|
->assertHasNoErrors()
|
|
->assertSet('isUploadFormOpen', false)
|
|
->assertDispatched('title-image-changed')
|
|
->assertSee('Rechte bestätigt am')
|
|
->assertSee('img-confirm-v2');
|
|
|
|
$image = $pr->images()->sole();
|
|
|
|
expect($image->rules_version)->toBe(config('images.rules_version'))
|
|
->and($image->copyright)->toBe('Musterfirma GmbH / Anna Beispiel')
|
|
->and($image->credit_source?->value)->toBe('metadata')
|
|
->and($image->title)->toBe('Werkshalle')
|
|
->and($image->license_url)->toBe('https://example.com/lizenz')
|
|
->and($image->focus_x)->toBe(100)
|
|
->and($image->focus_y)->toBe(0)
|
|
->and($image->license_type)->toBeNull()
|
|
->and($image->people_rights_status)->toBeNull()
|
|
->and(Storage::disk('local')->exists($image->original_path))->toBeTrue()
|
|
->and($image->hasValidRightsConfirmation())->toBeTrue();
|
|
|
|
$confirmation = ImageRightsConfirmation::query()->sole();
|
|
|
|
expect($confirmation->channel)->toBe(ConfirmationChannel::Form)
|
|
->and($confirmation->user_id)->toBe($owner->id)
|
|
->and($confirmation->legal_text_key)->toBe('img-confirm-v2')
|
|
->and($confirmation->text_snapshot)->toContain('/de/agb');
|
|
});
|
|
|
|
test('an admin upload skips the confirmation, mails the customer and blocks nothing else', function () {
|
|
/** @var TestCase $this */
|
|
Mail::fake();
|
|
['pr' => $pr, 'owner' => $owner] = makeRightsV2Draft();
|
|
$admin = User::factory()->create(['is_active' => true]);
|
|
$admin->assignRole('admin');
|
|
$this->actingAs($admin);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newCopyright', 'Beispiel AG')
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->assertSee('Sie laden im Auftrag des Kunden hoch')
|
|
->call('saveImage')
|
|
->assertHasNoErrors()
|
|
->assertSee('wartet auf Kundenbestätigung');
|
|
|
|
$image = $pr->images()->sole();
|
|
|
|
expect($image->customer_confirmation_requested_at)->not->toBeNull()
|
|
->and($image->awaitsCustomerConfirmation())->toBeTrue()
|
|
->and(ImageRightsConfirmation::query()->count())->toBe(0);
|
|
|
|
Mail::assertQueued(PressReleaseImageConfirmationRequested::class, fn ($mail) => $mail->hasTo($owner->email) && $mail->image->is($image));
|
|
});
|
|
|
|
test('the customer confirms an admin upload on the detail page with the magic link channel', function () {
|
|
/** @var TestCase $this */
|
|
['pr' => $pr, 'owner' => $owner] = makeRightsV2Draft();
|
|
$image = PressReleaseImage::factory()->for($pr)->rulesV2()->create([
|
|
'rights_confirmed_at' => null,
|
|
'customer_confirmation_requested_at' => now(),
|
|
]);
|
|
$this->actingAs($owner);
|
|
|
|
Livewire::test('customer.press-releases.show', ['id' => $pr->id])
|
|
->assertSee('Titelbild bestätigen')
|
|
->call('confirmImageRights')
|
|
->assertHasErrors(['imageRightsConfirmed'])
|
|
->set('imageRightsConfirmed', true)
|
|
->call('confirmImageRights')
|
|
->assertHasNoErrors()
|
|
->assertDontSee('Titelbild bestätigen');
|
|
|
|
$confirmation = $image->rightsConfirmations()->sole();
|
|
|
|
expect($confirmation->channel)->toBe(ConfirmationChannel::MagicLink)
|
|
->and($confirmation->user_id)->toBe($owner->id)
|
|
->and($confirmation->file_sha256)->toBe($image->original_sha256)
|
|
->and($image->fresh()->awaitsCustomerConfirmation())->toBeFalse()
|
|
->and($image->fresh()->rights_confirmed_at)->not->toBeNull();
|
|
});
|
|
|
|
test('removing a never published image deletes original, derivatives and confirmation for good', function () {
|
|
/** @var TestCase $this */
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
$component = Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->set('newRightsConfirmed', true)
|
|
->call('saveImage')
|
|
->assertHasNoErrors();
|
|
|
|
$image = $pr->images()->sole();
|
|
expect(Storage::disk('local')->allFiles())->not->toBe([]);
|
|
|
|
$component->call('remove', $image->id)->assertDispatched('title-image-changed');
|
|
|
|
expect(PressReleaseImage::withTrashed()->whereKey($image->id)->exists())->toBeFalse()
|
|
->and(ImageRightsConfirmation::query()->count())->toBe(0)
|
|
->and(Storage::disk('local')->allFiles())->toBe([]);
|
|
});
|
|
|
|
test('removing a once published image moves original and confirmation into the evidence archive and only soft deletes', function () {
|
|
/** @var TestCase $this */
|
|
Storage::fake('archive');
|
|
config()->set('archive.key', 'base64:'.base64_encode(random_bytes(32)));
|
|
['owner' => $owner, 'pr' => $pr] = makeRightsV2Draft();
|
|
$admin = User::factory()->create(['is_active' => true]);
|
|
$admin->assignRole('admin');
|
|
$this->actingAs($admin);
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newCopyright', 'Beispiel AG')
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->call('saveImage')
|
|
->assertHasNoErrors();
|
|
|
|
$image = $pr->images()->sole();
|
|
$image->forceFill(['published_ever_at' => now()])->save();
|
|
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('remove', $image->id);
|
|
|
|
$trashed = PressReleaseImage::withTrashed()->whereKey($image->id)->sole();
|
|
|
|
// Neue Semantik (Umsetzungsaudit 25.09.2026): Original und Bestätigung
|
|
// liegen im Beweisarchiv, die lokale Beweisdatei ist weg, der Pfad an
|
|
// der Zeile geleert (Bestätigungszeilen bleiben bis zum Fristende —
|
|
// siehe EvidenceArchiveTest).
|
|
expect($trashed->trashed())->toBeTrue()
|
|
->and(ArchiveEntry::query()->where('event', 'image_removed')->where('subject_id', $image->id)->exists())->toBeTrue()
|
|
->and(Storage::disk('local')->exists($image->original_path))->toBeFalse()
|
|
->and($trashed->original_path)->toBeNull()
|
|
->and(Storage::disk('local')->exists($image->path))->toBeFalse();
|
|
});
|
|
|
|
test('an admin upload on a published press release stays hidden on page, og and media route until the owner confirms it', function () {
|
|
/** @var TestCase $this */
|
|
Mail::fake();
|
|
['pr' => $pr, 'owner' => $owner] = makeRightsV2Published();
|
|
$admin = User::factory()->create(['is_active' => true]);
|
|
$admin->assignRole('admin');
|
|
|
|
$this->actingAs($admin);
|
|
Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newCopyright', 'Beispiel AG')
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->call('saveImage')
|
|
->assertHasNoErrors();
|
|
|
|
$image = $pr->images()->sole();
|
|
$mediaUrl = route('media.press-release-images.show', ['image' => $image->id, 'variant' => 'cover']);
|
|
$pageUrl = 'https://presseecho.test/de/press-release/'.$pr->slug;
|
|
|
|
expect($image->isPubliclyDeliverable())->toBeFalse()
|
|
->and(PressReleaseImage::query()->publiclyVisible()->whereKey($image->id)->exists())->toBeFalse();
|
|
|
|
// Berechtigte interne Ansicht bleibt, aber ohne öffentlichen Cache.
|
|
$this->get($mediaUrl)->assertSuccessful()->assertHeader('Cache-Control', 'no-store, private');
|
|
|
|
auth()->logout();
|
|
$this->get($pageUrl)->assertSuccessful()->assertDontSee('media/press-release-images/'.$image->id, false);
|
|
$this->get($mediaUrl)->assertNotFound();
|
|
|
|
$this->actingAs($owner);
|
|
Livewire::test('customer.press-releases.show', ['id' => $pr->id])
|
|
->assertSee('Titelbild bestätigen')
|
|
->set('imageRightsConfirmed', true)
|
|
->call('confirmImageRights')
|
|
->assertHasNoErrors();
|
|
|
|
$image = $image->fresh();
|
|
|
|
expect($image->rights_confirmed_at)->not->toBeNull()
|
|
->and($image->isPubliclyDeliverable())->toBeTrue()
|
|
->and($image->published_snapshot_path)->not->toBeNull()
|
|
->and($image->rightsConfirmations()->sole()->channel)->toBe(ConfirmationChannel::MagicLink);
|
|
|
|
auth()->logout();
|
|
$this->get($pageUrl)
|
|
->assertSuccessful()
|
|
->assertSee('<meta property="og:image" content="'.route('media.press-release-images.show', ['image' => $image->id, 'variant' => 'og']).'">', false);
|
|
$this->get($mediaUrl)->assertSuccessful()->assertHeader('Cache-Control', 'max-age=86400, public');
|
|
});
|
|
|
|
test('only the account owner may confirm an admin upload: team member, super admin and a repeat are refused', function () {
|
|
/** @var TestCase $this */
|
|
['pr' => $pr, 'owner' => $owner, 'company' => $company] = makeRightsV2Draft();
|
|
$image = PressReleaseImage::factory()->for($pr)->rulesV2()->create([
|
|
'rights_confirmed_at' => null,
|
|
'customer_confirmation_requested_at' => now(),
|
|
]);
|
|
|
|
$member = User::factory()->create(['is_active' => true]);
|
|
$member->assignRole('customer');
|
|
$member->companies()->attach($company->id, ['role' => 'member']);
|
|
$superAdmin = User::factory()->superAdmin()->create(['is_active' => true]);
|
|
|
|
expect($member->can('update', $pr))->toBeTrue()
|
|
->and($member->can('confirmImageRights', $pr))->toBeFalse()
|
|
->and($superAdmin->can('update', $pr))->toBeTrue()
|
|
->and($superAdmin->can('confirmImageRights', $pr))->toBeFalse()
|
|
->and($owner->can('confirmImageRights', $pr))->toBeTrue();
|
|
|
|
$this->actingAs($member);
|
|
Livewire::test('customer.press-releases.show', ['id' => $pr->id])
|
|
->assertDontSee('Titelbild bestätigen')
|
|
->set('imageRightsConfirmed', true)
|
|
->call('confirmImageRights')
|
|
->assertForbidden();
|
|
|
|
$confirm = app(CustomerImageConfirmation::class);
|
|
|
|
// Der Service prüft die Identität unabhängig von der Policy.
|
|
expect(fn () => $confirm->confirm($image, $member, 'img-confirm-v2', null, null))
|
|
->toThrow(ImageUploadException::class, 'Kontoinhaber');
|
|
|
|
expect(ImageRightsConfirmation::query()->count())->toBe(0);
|
|
|
|
$confirm->confirm($image->fresh(), $owner, 'img-confirm-v2', null, null);
|
|
|
|
expect(fn () => $confirm->confirm($image->fresh(), $owner, 'img-confirm-v2', null, null))
|
|
->toThrow(ImageUploadException::class, 'keine Bestätigung aus');
|
|
|
|
expect(ImageRightsConfirmation::query()->count())->toBe(1);
|
|
});
|
|
|
|
test('a confirmation text replaced between render and save must be read and confirmed again in the manager', function () {
|
|
/** @var TestCase $this */
|
|
['pr' => $pr, 'owner' => $owner] = makeRightsV2Draft();
|
|
$this->actingAs($owner);
|
|
|
|
$component = Livewire::test('components.press-release-images-manager-v2', ['pressReleaseId' => $pr->id])
|
|
->assertSet('legalTextKey', 'img-confirm-v2')
|
|
->call('openUploadForm')
|
|
->set('newImage', UploadedFile::fake()->image('foto.jpg', 1200, 800))
|
|
->set('newCopyright', 'Beispiel AG')
|
|
->set('newAiDeclaration', AiImageDeclaration::Original->value)
|
|
->set('newRightsConfirmed', true);
|
|
|
|
activateRightsTextV4();
|
|
|
|
$component->call('saveImage')
|
|
->assertHasErrors(['newRightsConfirmed'])
|
|
->assertSet('newRightsConfirmed', false)
|
|
->assertSet('legalTextKey', 'img-confirm-v4');
|
|
|
|
expect($pr->images()->count())->toBe(0);
|
|
|
|
$component->set('newRightsConfirmed', true)
|
|
->call('saveImage')
|
|
->assertHasNoErrors();
|
|
|
|
expect($pr->images()->sole()->rightsConfirmations()->sole()->legal_text_key)->toBe('img-confirm-v4');
|
|
});
|
|
|
|
test('the confirmation on the detail page is bound to the text version shown', function () {
|
|
/** @var TestCase $this */
|
|
['pr' => $pr, 'owner' => $owner] = makeRightsV2Draft();
|
|
$image = PressReleaseImage::factory()->for($pr)->rulesV2()->create([
|
|
'rights_confirmed_at' => null,
|
|
'customer_confirmation_requested_at' => now(),
|
|
]);
|
|
$this->actingAs($owner);
|
|
|
|
$component = Livewire::test('customer.press-releases.show', ['id' => $pr->id])
|
|
->assertSet('imageLegalTextKey', 'img-confirm-v2')
|
|
->set('imageRightsConfirmed', true);
|
|
|
|
activateRightsTextV4();
|
|
|
|
$component->call('confirmImageRights')
|
|
->assertHasErrors(['imageRightsConfirmed'])
|
|
->assertSet('imageRightsConfirmed', false)
|
|
->assertSet('imageLegalTextKey', 'img-confirm-v4');
|
|
|
|
expect(ImageRightsConfirmation::query()->count())->toBe(0);
|
|
|
|
$component->set('imageRightsConfirmed', true)
|
|
->call('confirmImageRights')
|
|
->assertHasNoErrors();
|
|
|
|
expect($image->rightsConfirmations()->sole()->legal_text_key)->toBe('img-confirm-v4');
|
|
});
|