presseportale/app/Http/Controllers/Web/PressReleaseAttachmentMediaController.php
Kevin Adametz 6250b0bab4 media: PM-Medien privat ausliefern + Vorschau-Signatur (M4, M5, Fix#4/#5)
- Neue PM-Bilder/Anhänge liegen auf der privaten local-Disk; Auslieferung
  über kontrollierte Media-Routen mit gemeinsamer Zugriffslogik
  (AuthorizesPressReleaseMediaAccess). Öffentliche Medien werden aus den
  geladenen Modellen ermittelt (weniger Queries) und länger gecacht.
- Anonyme Token-Vorschau lädt Bilder über temporär signierte URLs (Fix#5).
- API-Resource baut Variant-URLs über die Media-Route statt /storage
  (Fix#4). Storage-Schicht prüft zusätzlich den serverseitigen MIME-Type (M5).
- press-releases:privatize-media migriert Bestandsmedien.

Deployment: einmalig `php artisan press-releases:privatize-media` ausführen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:48:06 +00:00

39 lines
1.4 KiB
PHP

<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Web\Concerns\AuthorizesPressReleaseMediaAccess;
use App\Models\PressRelease;
use App\Models\PressReleaseAttachment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\StreamedResponse;
class PressReleaseAttachmentMediaController extends Controller
{
use AuthorizesPressReleaseMediaAccess;
public function __invoke(Request $request, int $attachment): StreamedResponse
{
$attachment = PressReleaseAttachment::query()
->with(['pressRelease' => fn ($query) => $query
->withoutGlobalScopes()
->with(['company' => fn ($company) => $company->withoutGlobalScopes()])])
->findOrFail($attachment);
$pressRelease = $attachment->pressRelease;
abort_unless($pressRelease instanceof PressRelease, 404);
$isPublic = $this->pressReleaseMediaIsPublic($pressRelease);
$this->authorizePressReleaseMediaAccess($request, $pressRelease, $isPublic);
return Storage::disk($attachment->disk)->download(
$attachment->path,
$attachment->original_name,
[
'Cache-Control' => $this->mediaCacheControl($isPublic),
'X-Content-Type-Options' => 'nosniff',
],
);
}
}