Files
fotospiel-app/tests/Feature/Api/PhotoShareLinkTest.php
Codex Agent b14435df8b
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Fix share assets, shared photo UI, and live show expiry
2026-02-06 07:30:30 +01:00

117 lines
3.9 KiB
PHP

<?php
namespace Tests\Feature\Api;
use App\Models\Event;
use App\Models\Photo;
use App\Models\PhotoShareLink;
use App\Models\Task;
use App\Models\Tenant;
use App\Services\EventJoinTokenService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class PhotoShareLinkTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
Config::set('share-links.ttl_hours', 2);
}
public function test_guest_can_create_share_link(): void
{
$tenant = Tenant::factory()->create();
$event = Event::factory()->for($tenant)->create(['status' => 'published']);
$photo = Photo::factory()->for($event)->create([
'status' => 'approved',
]);
$token = app(EventJoinTokenService::class)->createToken($event)->plain_token;
$response = $this->withHeaders([
'X-Device-Id' => 'device-share',
'Accept' => 'application/json',
])->postJson("/api/v1/events/{$token}/photos/{$photo->id}/share");
$response->assertOk();
$response->assertJsonStructure(['slug', 'url', 'expires_at']);
$this->assertDatabaseHas('photo_share_links', [
'photo_id' => $photo->id,
'slug' => $response->json('slug'),
]);
}
public function test_share_link_cannot_be_created_for_unrelated_photo(): void
{
$event = Event::factory()->create(['status' => 'published']);
$otherEvent = Event::factory()->create(['status' => 'published']);
$photo = Photo::factory()->for($otherEvent)->create(['status' => 'approved']);
$token = app(EventJoinTokenService::class)->createToken($event)->plain_token;
$response = $this->withHeaders([
'X-Device-Id' => 'device-share',
'Accept' => 'application/json',
])->postJson("/api/v1/events/{$token}/photos/{$photo->id}/share");
$response->assertNotFound();
}
public function test_share_payload_exposes_public_photo_data(): void
{
Config::set('filesystems.default', 'public');
Storage::fake('public');
$tenant = Tenant::factory()->create();
$event = Event::factory()->for($tenant)->create(['status' => 'published']);
$task = Task::factory()->for($tenant)->create();
$photo = Photo::factory()->for($event)->create([
'status' => 'approved',
'task_id' => $task->id,
'file_path' => 'photos/share-test.jpg',
'thumbnail_path' => 'photos/thumbnails/share-test.jpg',
]);
Storage::disk('public')->put('photos/share-test.jpg', 'photo');
$share = PhotoShareLink::factory()->for($photo)->create([
'expires_at' => now()->addDay(),
]);
$response = $this->getJson("/api/v1/photo-shares/{$share->slug}");
$response->assertOk();
$response->assertJsonPath('photo.id', $photo->id);
$response->assertJsonPath('photo.image_urls.full', fn ($value) => str_contains($value, '/photo-shares/'));
$response->assertJsonPath('event.id', $event->id);
$response->assertJsonStructure([
'branding' => [
'primary_color',
'secondary_color',
'background_color',
'logo_mode',
'logo_value',
'palette',
'typography',
'logo',
'buttons',
],
]);
$assetUrl = $response->json('photo.image_urls.full');
$this->assertIsString($assetUrl);
$this->assertNotNull(parse_url($assetUrl, PHP_URL_SCHEME));
$parsed = parse_url($assetUrl);
$path = (string) ($parsed['path'] ?? '');
$query = $parsed['query'] ?? null;
$assetResponse = $this->get($path.($query ? "?{$query}" : ''));
$assetResponse->assertOk();
}
}