141 lines
4.6 KiB
PHP
141 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Tenant;
|
|
|
|
use App\Enums\GuestNotificationAudience;
|
|
use App\Enums\GuestNotificationType;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Tenant\BroadcastGuestNotificationRequest;
|
|
use App\Http\Resources\Tenant\GuestNotificationResource;
|
|
use App\Models\Event;
|
|
use App\Models\GuestNotification;
|
|
use App\Models\GuestPolicySetting;
|
|
use App\Services\GuestNotificationService;
|
|
use App\Support\TenantMemberPermissions;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class EventGuestNotificationController extends Controller
|
|
{
|
|
public function __construct(private readonly GuestNotificationService $notifications) {}
|
|
|
|
public function index(Request $request, Event $event): JsonResponse
|
|
{
|
|
$this->assertEventTenant($request, $event);
|
|
TenantMemberPermissions::ensureEventPermission($request, $event, 'guest-notifications:manage');
|
|
|
|
$limit = max(1, min(100, (int) $request->integer('limit', 25)));
|
|
|
|
$notifications = GuestNotification::query()
|
|
->forEvent($event)
|
|
->orderByDesc('id')
|
|
->limit($limit)
|
|
->get();
|
|
|
|
return GuestNotificationResource::collection($notifications)->response();
|
|
}
|
|
|
|
public function store(BroadcastGuestNotificationRequest $request, Event $event): JsonResponse
|
|
{
|
|
$this->assertEventTenant($request, $event);
|
|
TenantMemberPermissions::ensureEventPermission($request, $event, 'guest-notifications:manage');
|
|
|
|
$data = $request->validated();
|
|
|
|
$type = $this->resolveType($data['type'] ?? null);
|
|
$audience = $this->resolveAudience($data['audience'] ?? null);
|
|
$targetIdentifier = $audience === GuestNotificationAudience::GUEST
|
|
? $this->sanitizeIdentifier($data['guest_identifier'] ?? '')
|
|
: null;
|
|
|
|
if ($audience === GuestNotificationAudience::GUEST && ! $targetIdentifier) {
|
|
throw ValidationException::withMessages([
|
|
'guest_identifier' => __('Ein Gastname oder Geräte-Token wird benötigt.'),
|
|
]);
|
|
}
|
|
|
|
$expiresAt = null;
|
|
if (! empty($data['expires_in_minutes'])) {
|
|
$expiresAt = now()->addMinutes((int) $data['expires_in_minutes']);
|
|
} else {
|
|
$policyTtl = GuestPolicySetting::current()->guest_notification_ttl_hours;
|
|
if ($policyTtl !== null && $policyTtl > 0) {
|
|
$expiresAt = now()->addHours((int) $policyTtl);
|
|
}
|
|
}
|
|
|
|
$payload = null;
|
|
if (! empty($data['cta'])) {
|
|
$payload = [
|
|
'cta' => [
|
|
'label' => $data['cta']['label'],
|
|
'href' => $data['cta']['url'],
|
|
],
|
|
];
|
|
}
|
|
|
|
$notification = $this->notifications->createNotification(
|
|
$event,
|
|
$type,
|
|
$data['title'],
|
|
$data['message'],
|
|
[
|
|
'payload' => $payload,
|
|
'audience_scope' => $audience,
|
|
'target_identifier' => $targetIdentifier,
|
|
'expires_at' => $expiresAt,
|
|
'priority' => $data['priority'] ?? 1,
|
|
]
|
|
);
|
|
|
|
return (new GuestNotificationResource($notification))
|
|
->response()
|
|
->setStatusCode(Response::HTTP_CREATED);
|
|
}
|
|
|
|
private function assertEventTenant(Request $request, Event $event): void
|
|
{
|
|
$tenantId = $request->attributes->get('tenant_id');
|
|
|
|
if ($tenantId === null || (int) $event->tenant_id !== (int) $tenantId) {
|
|
abort(403, 'Event belongs to a different tenant.');
|
|
}
|
|
}
|
|
|
|
private function resolveType(?string $value): GuestNotificationType
|
|
{
|
|
if (! $value) {
|
|
return GuestNotificationType::BROADCAST;
|
|
}
|
|
|
|
foreach (GuestNotificationType::cases() as $type) {
|
|
if ($type->value === $value) {
|
|
return $type;
|
|
}
|
|
}
|
|
|
|
return GuestNotificationType::BROADCAST;
|
|
}
|
|
|
|
private function resolveAudience(?string $value): GuestNotificationAudience
|
|
{
|
|
if (! $value) {
|
|
return GuestNotificationAudience::ALL;
|
|
}
|
|
|
|
return $value === GuestNotificationAudience::GUEST->value
|
|
? GuestNotificationAudience::GUEST
|
|
: GuestNotificationAudience::ALL;
|
|
}
|
|
|
|
private function sanitizeIdentifier(string $value): ?string
|
|
{
|
|
$normalized = preg_replace('/[^A-Za-z0-9 _\-]/', '', $value) ?? '';
|
|
$normalized = trim(mb_substr($normalized, 0, 120));
|
|
|
|
return $normalized === '' ? null : $normalized;
|
|
}
|
|
}
|