Improve guest photo downloads with preview/original variants
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-02-07 14:31:48 +01:00
parent 3ba4d11d92
commit ddbfa38db1
7 changed files with 356 additions and 14 deletions

View File

@@ -0,0 +1,149 @@
<?php
namespace Tests\Feature\Api\Event;
use App\Models\Event;
use App\Models\EventMediaAsset;
use App\Models\MediaStorageTarget;
use App\Models\Photo;
use App\Services\EventJoinTokenService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class EventGalleryDownloadTest extends TestCase
{
use RefreshDatabase;
public function test_gallery_download_uses_preview_variant_when_configured(): void
{
Storage::fake('public');
$event = Event::factory()->create([
'status' => 'published',
'settings' => [
'guest_download_variant' => 'preview',
],
]);
$token = app(EventJoinTokenService::class)->createToken($event, ['label' => 'download-preview'])->plain_token;
$storageTarget = $this->createPublicStorageTarget();
$originalPath = "events/{$event->id}/photos/original.jpg";
$previewPath = "events/{$event->id}/photos/previews/preview.jpg";
$thumbnailPath = "events/{$event->id}/photos/thumbs/thumb.jpg";
Storage::disk('public')->put($originalPath, 'original-content');
Storage::disk('public')->put($previewPath, 'preview-content');
Storage::disk('public')->put($thumbnailPath, 'thumb-content');
$photo = Photo::factory()->for($event)->create([
'tenant_id' => $event->tenant_id,
'status' => 'approved',
'file_path' => $originalPath,
'thumbnail_path' => $thumbnailPath,
]);
$originalAsset = EventMediaAsset::create([
'event_id' => $event->id,
'media_storage_target_id' => $storageTarget->id,
'photo_id' => $photo->id,
'variant' => 'original',
'disk' => 'public',
'path' => $originalPath,
'status' => 'hot',
'processed_at' => now(),
'mime_type' => 'image/jpeg',
]);
EventMediaAsset::create([
'event_id' => $event->id,
'media_storage_target_id' => $storageTarget->id,
'photo_id' => $photo->id,
'variant' => 'preview',
'disk' => 'public',
'path' => $previewPath,
'status' => 'hot',
'processed_at' => now(),
'mime_type' => 'image/jpeg',
]);
$photo->update(['media_asset_id' => $originalAsset->id]);
$photosResponse = $this->getJson("/api/v1/gallery/{$token}/photos");
$downloadUrl = (string) $photosResponse->json('data.0.download_url');
$photosResponse->assertOk();
$this->assertNotEmpty($downloadUrl);
$downloadResponse = $this->get($downloadUrl);
$downloadResponse->assertOk();
$this->assertSame('preview-content', $downloadResponse->streamedContent());
$this->assertStringContainsString(
'attachment;',
(string) $downloadResponse->headers->get('Content-Disposition')
);
}
public function test_gallery_download_falls_back_to_original_when_preview_is_missing(): void
{
Storage::fake('public');
$event = Event::factory()->create([
'status' => 'published',
'settings' => [
'guest_download_variant' => 'preview',
],
]);
$token = app(EventJoinTokenService::class)->createToken($event, ['label' => 'download-fallback'])->plain_token;
$storageTarget = $this->createPublicStorageTarget();
$originalPath = "events/{$event->id}/photos/original.jpg";
$thumbnailPath = "events/{$event->id}/photos/thumbs/thumb.jpg";
Storage::disk('public')->put($originalPath, 'original-content');
Storage::disk('public')->put($thumbnailPath, 'thumb-content');
$photo = Photo::factory()->for($event)->create([
'tenant_id' => $event->tenant_id,
'status' => 'approved',
'file_path' => $originalPath,
'thumbnail_path' => $thumbnailPath,
]);
$originalAsset = EventMediaAsset::create([
'event_id' => $event->id,
'media_storage_target_id' => $storageTarget->id,
'photo_id' => $photo->id,
'variant' => 'original',
'disk' => 'public',
'path' => $originalPath,
'status' => 'hot',
'processed_at' => now(),
'mime_type' => 'image/jpeg',
]);
$photo->update(['media_asset_id' => $originalAsset->id]);
$photosResponse = $this->getJson("/api/v1/gallery/{$token}/photos");
$downloadUrl = (string) $photosResponse->json('data.0.download_url');
$photosResponse->assertOk();
$this->assertNotEmpty($downloadUrl);
$downloadResponse = $this->get($downloadUrl);
$downloadResponse->assertOk();
$this->assertSame('original-content', $downloadResponse->streamedContent());
}
private function createPublicStorageTarget(): MediaStorageTarget
{
return MediaStorageTarget::create([
'key' => 'public',
'name' => 'Public',
'driver' => 'local',
'is_hot' => true,
'is_default' => true,
'is_active' => true,
]);
}
}

View File

@@ -59,6 +59,10 @@ class EventPhotosLocaleTest extends TestCase
$responseEn->assertJsonPath('data.0.emotion.icon', '🙂');
$responseEn->assertJsonPath('data.0.emotion.color', '#FF00AA');
$responseEn->assertJsonPath('data.0.is_mine', true);
$this->assertStringContainsString('/api/v1/gallery/'.$token.'/photos/', (string) $responseEn->json('data.0.full_url'));
$this->assertStringContainsString('/api/v1/gallery/'.$token.'/photos/', (string) $responseEn->json('data.0.thumbnail_url'));
$this->assertStringContainsString('/api/v1/gallery/'.$token.'/photos/', (string) $responseEn->json('data.0.download_url'));
$this->assertStringContainsString('/download', (string) $responseEn->json('data.0.download_url'));
$etag = $responseEn->headers->get('ETag');
$this->assertNotEmpty($etag);