From 7743d91df66557a578613eccb4376f7b727db766 Mon Sep 17 00:00:00 2001 From: SEB Fotografie - soeren Date: Tue, 9 Sep 2025 21:22:20 +0200 Subject: [PATCH] feat: Implement public event and photo API --- .../Controllers/Api/EventPublicController.php | 32 ++++++++++++++++++- app/Models/Tenant.php | 13 ++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/EventPublicController.php b/app/Http/Controllers/Api/EventPublicController.php index fc4b948..7d268e6 100644 --- a/app/Http/Controllers/Api/EventPublicController.php +++ b/app/Http/Controllers/Api/EventPublicController.php @@ -13,6 +13,30 @@ use App\Support\ImageHelper; class EventPublicController extends BaseController { + private function toPublicUrl(?string $path): ?string + { + if (! $path) return null; + // Already absolute URL + if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) return $path; + // Already a public storage URL + if (str_starts_with($path, '/storage/')) return $path; + if (str_starts_with($path, 'storage/')) return '/' . $path; + + // Common relative paths stored in DB (e.g. 'photos/...', 'thumbnails/...', 'events/...') + if (str_starts_with($path, 'photos/') || str_starts_with($path, 'thumbnails/') || str_starts_with($path, 'events/')) { + return Storage::url($path); + } + + // Absolute server paths pointing into storage/app/public (Linux/Windows) + $normalized = str_replace('\\', '/', $path); + $needle = '/storage/app/public/'; + if (str_contains($normalized, $needle)) { + $rel = substr($normalized, strpos($normalized, $needle) + strlen($needle)); + return '/storage/' . ltrim($rel, '/'); + } + + return $path; // fallback as-is + } public function event(string $slug) { $event = DB::table('events')->where('slug', $slug)->first([ @@ -90,7 +114,11 @@ class EventPublicController extends BaseController $query->where('created_at', '>', $since); } - $rows = $query->get(); + $rows = $query->get()->map(function ($r) { + $r->file_path = $this->toPublicUrl((string)($r->file_path ?? '')); + $r->thumbnail_path = $this->toPublicUrl((string)($r->thumbnail_path ?? '')); + return $r; + }); $latestPhotoAt = DB::table('photos')->where('event_id', $eventId)->max('created_at'); $payload = [ 'data' => $rows, @@ -116,6 +144,8 @@ class EventPublicController extends BaseController if (! $row) { return response()->json(['error' => ['code' => 'not_found', 'message' => 'Photo not found']], 404); } + $row->file_path = $this->toPublicUrl((string)($row->file_path ?? '')); + $row->thumbnail_path = $this->toPublicUrl((string)($row->thumbnail_path ?? '')); return response()->json($row)->header('Cache-Control', 'no-store'); } diff --git a/app/Models/Tenant.php b/app/Models/Tenant.php index d47c7a6..25332dd 100644 --- a/app/Models/Tenant.php +++ b/app/Models/Tenant.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasManyThrough; class Tenant extends Model { @@ -18,4 +19,16 @@ class Tenant extends Model { return $this->hasMany(Event::class); } + + public function photos(): HasManyThrough + { + return $this->hasManyThrough( + Photo::class, + Event::class, + 'tenant_id', // Foreign key on events table... + 'event_id', // Foreign key on photos table... + 'id', // Local key on tenants table... + 'id' // Local key on events table... + ); + } }