Files
fotospiel-app/app/Http/Controllers/Api/Tenant/EventJoinTokenLayoutController.php
Codex Agent 64a5411fb9 - Reworked the tenant admin login page
- Updated the User model to implement Filament’s tenancy contracts
- Seeded a ready-to-use demo tenant (user, tenant, active package, purchase)
- Introduced a branded, translated 403 error page to replace the generic forbidden message for unauthorised admin hits
- Removed the public “Register” links from the marketing header
- hardened join event logic and improved error handling in the guest pwa.
2025-10-13 12:50:46 +02:00

131 lines
4.2 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Tenant;
use App\Http\Controllers\Controller;
use App\Models\Event;
use App\Models\EventJoinToken;
use App\Support\JoinTokenLayoutRegistry;
use Dompdf\Dompdf;
use Dompdf\Options;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class EventJoinTokenLayoutController extends Controller
{
public function index(Request $request, Event $event, EventJoinToken $joinToken)
{
$this->ensureBelongsToEvent($event, $joinToken);
$layouts = JoinTokenLayoutRegistry::toResponse(function (string $layoutId, string $format) use ($event, $joinToken) {
return route('tenant.events.join-tokens.layouts.download', [
'event' => $event,
'joinToken' => $joinToken,
'layout' => $layoutId,
'format' => $format,
]);
});
return response()->json([
'data' => $layouts,
]);
}
public function download(Request $request, Event $event, EventJoinToken $joinToken, string $layout, string $format)
{
$this->ensureBelongsToEvent($event, $joinToken);
$layoutConfig = JoinTokenLayoutRegistry::find($layout);
if (! $layoutConfig) {
abort(404, 'Layout nicht gefunden.');
}
if (! in_array($format, ['pdf', 'svg'], true)) {
abort(404, 'Unbekanntes Exportformat.');
}
$tokenUrl = url('/e/'.$joinToken->token);
$qrPngDataUri = 'data:image/png;base64,'.base64_encode(
QrCode::format('png')
->margin(0)
->size($layoutConfig['qr']['size_px'])
->generate($tokenUrl)
);
$backgroundStyle = $this->buildBackgroundStyle($layoutConfig);
$eventName = $this->resolveEventName($event);
$viewData = [
'layout' => $layoutConfig,
'event' => $event,
'eventName' => $eventName,
'token' => $joinToken,
'tokenUrl' => $tokenUrl,
'qrPngDataUri' => $qrPngDataUri,
'backgroundStyle' => $backgroundStyle,
];
$filename = sprintf('%s-%s.%s', Str::slug($eventName ?: 'event'), $layoutConfig['id'], $format);
if ($format === 'svg') {
$svg = view('layouts.join-token.svg', $viewData)->render();
return response($svg)
->header('Content-Type', 'image/svg+xml')
->header('Content-Disposition', 'attachment; filename="'.$filename.'"');
}
$html = view('layouts.join-token.pdf', $viewData)->render();
$options = new Options();
$options->set('isHtml5ParserEnabled', true);
$options->set('isRemoteEnabled', true);
$options->set('defaultFont', 'Helvetica');
$dompdf = new Dompdf($options);
$dompdf->setPaper(strtoupper($layoutConfig['paper']), $layoutConfig['orientation'] === 'landscape' ? 'landscape' : 'portrait');
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->render();
return response($dompdf->output())
->header('Content-Type', 'application/pdf')
->header('Content-Disposition', 'attachment; filename="'.$filename.'"');
}
private function ensureBelongsToEvent(Event $event, EventJoinToken $joinToken): void
{
if ($joinToken->event_id !== $event->id) {
abort(404);
}
}
private function resolveEventName(Event $event): string
{
$name = $event->name;
if (is_array($name)) {
$locale = $event->default_locale ?? 'de';
return $name[$locale] ?? $name['de'] ?? reset($name) ?: 'Event';
}
return is_string($name) && $name !== '' ? $name : 'Event';
}
private function buildBackgroundStyle(array $layout): string
{
$gradient = $layout['background_gradient'] ?? null;
if (is_array($gradient) && ! empty($gradient['stops'])) {
$angle = $gradient['angle'] ?? 180;
$stops = implode(',', $gradient['stops']);
return sprintf('linear-gradient(%ddeg,%s)', $angle, $stops);
}
return $layout['background'] ?? '#FFFFFF';
}
}