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

@@ -53,6 +53,10 @@ class EventPublicController extends BaseController
private const BRANDING_SIGNED_TTL_SECONDS = 3600;
private const PREVIEW_MAX_EDGE = 1920;
private const PREVIEW_QUALITY = 86;
private ?GuestPolicySetting $guestPolicy = null;
public function __construct(
@@ -1451,17 +1455,34 @@ class EventPublicController extends BaseController
}
private function makeSignedGalleryDownloadUrl(string $token, Photo $photo): string
{
return $this->makeSignedGalleryDownloadUrlForId($token, (int) $photo->id);
}
private function makeSignedGalleryDownloadUrlForId(string $token, int $photoId): string
{
return URL::temporarySignedRoute(
'api.v1.gallery.photos.download',
now()->addSeconds(self::SIGNED_URL_TTL_SECONDS),
[
'token' => $token,
'photo' => $photo->id,
'photo' => $photoId,
]
);
}
private function galleryDownloadVariantPreference(Event $event): array
{
$settings = is_array($event->settings) ? $event->settings : [];
$configuredVariant = Arr::get($settings, 'guest_download_variant', 'preview');
if ($configuredVariant === 'original') {
return ['original'];
}
return ['preview', 'original'];
}
private function makeShareAssetUrl(PhotoShareLink $shareLink, string $variant): string
{
return URL::temporarySignedRoute(
@@ -1907,7 +1928,12 @@ class EventPublicController extends BaseController
);
}
return $this->streamGalleryPhoto($event, $record, ['original'], 'attachment');
return $this->streamGalleryPhoto(
$event,
$record,
$this->galleryDownloadVariantPreference($event),
'attachment'
);
}
public function event(Request $request, string $token)
@@ -2219,6 +2245,15 @@ class EventPublicController extends BaseController
$disk = $asset?->disk ?? $record->mediaAsset?->disk;
$path = $watermarked?->path ?? $asset?->path ?? ($record->thumbnail_path ?: $record->file_path);
$mime = $watermarked?->mime_type ?? $asset?->mime_type ?? 'image/jpeg';
} elseif ($variant === 'preview') {
$asset = EventMediaAsset::where('photo_id', $record->id)->where('variant', 'preview')->first();
$watermarked = $preferOriginals
? null
: EventMediaAsset::where('photo_id', $record->id)->where('variant', 'watermarked_preview')->first();
$fallbackAsset = $record->mediaAsset ?? EventMediaAsset::where('photo_id', $record->id)->where('variant', 'original')->first();
$disk = $watermarked?->disk ?? $asset?->disk ?? $fallbackAsset?->disk;
$path = $watermarked?->path ?? $asset?->path ?? $fallbackAsset?->path ?? ($record->file_path ?? null);
$mime = $watermarked?->mime_type ?? $asset?->mime_type ?? $fallbackAsset?->mime_type ?? ($record->mime_type ?? 'image/jpeg');
} else {
$watermarked = $preferOriginals
? null
@@ -2909,10 +2944,15 @@ class EventPublicController extends BaseController
$query->where('photos.created_at', '>', $since);
}
$rows = $query->get()->map(function ($r) use ($fallbacks, $token, $deviceId) {
$r->file_path = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'full')
$fullUrl = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'full')
?? $this->resolveSignedFallbackUrl((string) ($r->file_path ?? ''));
$r->thumbnail_path = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'thumbnail')
$thumbnailUrl = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'thumbnail')
?? $this->resolveSignedFallbackUrl((string) ($r->thumbnail_path ?? ''));
$r->file_path = $fullUrl;
$r->thumbnail_path = $thumbnailUrl;
$r->full_url = $fullUrl;
$r->thumbnail_url = $thumbnailUrl;
$r->download_url = $this->makeSignedGalleryDownloadUrlForId($token, (int) $r->id);
// Localize task title if present
if ($r->task_title) {
@@ -3346,10 +3386,19 @@ class EventPublicController extends BaseController
$thumbUrl = $thumbPath
? $this->resolveDiskUrl($disk, $thumbPath)
: $this->resolveDiskUrl($disk, $path);
$previewRel = "events/{$eventId}/photos/previews/{$baseName}_preview.jpg";
$previewPath = ImageHelper::makeThumbnailOnDisk(
$disk,
$path,
$previewRel,
self::PREVIEW_MAX_EDGE,
self::PREVIEW_QUALITY
);
// Create watermarked copies (non-destructive).
$watermarkedPath = $path;
$watermarkedThumb = $thumbPath ?: $path;
$watermarkedPreview = $previewPath ?: $path;
if ($watermarkConfig['type'] !== 'none' && ! empty($watermarkConfig['asset']) && ! ($watermarkConfig['serve_originals'] ?? false)) {
$watermarkedPath = ImageHelper::copyWithWatermark($disk, $path, "events/{$eventId}/photos/watermarked/{$baseName}.{$file->getClientOriginalExtension()}", $watermarkConfig) ?? $path;
if ($thumbPath) {
@@ -3362,6 +3411,17 @@ class EventPublicController extends BaseController
} else {
$watermarkedThumb = $watermarkedPath;
}
if ($previewPath) {
$watermarkedPreview = ImageHelper::copyWithWatermark(
$disk,
$previewPath,
"events/{$eventId}/photos/watermarked/{$baseName}_preview.jpg",
$watermarkConfig
) ?? $previewPath;
} else {
$watermarkedPreview = $watermarkedPath;
}
}
$url = $this->resolveDiskUrl($disk, $watermarkedPath);
@@ -3475,6 +3535,23 @@ class EventPublicController extends BaseController
],
]);
}
if ($previewPath) {
$this->eventStorageManager->recordAsset($eventModel, $disk, $previewPath, [
'variant' => 'preview',
'mime_type' => 'image/jpeg',
'status' => 'hot',
'processed_at' => now(),
'photo_id' => $photoId,
'size_bytes' => Storage::disk($disk)->exists($previewPath)
? Storage::disk($disk)->size($previewPath)
: null,
'meta' => [
'source_variant_id' => $asset->id,
],
]);
}
if ($watermarkedThumb !== $thumbPath) {
$this->eventStorageManager->recordAsset($eventModel, $disk, $watermarkedThumb, [
'variant' => 'watermarked_thumbnail',
@@ -3491,6 +3568,22 @@ class EventPublicController extends BaseController
]);
}
if ($watermarkedPreview !== $previewPath) {
$this->eventStorageManager->recordAsset($eventModel, $disk, $watermarkedPreview, [
'variant' => 'watermarked_preview',
'mime_type' => 'image/jpeg',
'status' => 'hot',
'processed_at' => now(),
'photo_id' => $photoId,
'size_bytes' => Storage::disk($disk)->exists($watermarkedPreview)
? Storage::disk($disk)->size($watermarkedPreview)
: null,
'meta' => [
'source_variant_id' => $watermarkedAsset?->id ?? $asset->id,
],
]);
}
DB::table('photos')
->where('id', $photoId)
->update(['media_asset_id' => $asset->id]);