feat: add guest notification center
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<?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\Services\GuestNotificationService;
|
||||
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);
|
||||
|
||||
$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);
|
||||
|
||||
$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']);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user