Deploy Ladill Events / deploy (push) Successful in 1m17s
Meet can attach existing conference or webinar rooms to event virtual sessions so registration stays in Events. Co-authored-by: Cursor <cursoragent@cursor.com>
149 lines
5.9 KiB
PHP
149 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Meet;
|
|
|
|
use App\Models\QrCode;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Str;
|
|
|
|
class EventMeetRoomLinkService
|
|
{
|
|
public function __construct(private readonly EventMeetSyncService $sync) {}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function linkableEvents(User $owner): array
|
|
{
|
|
return QrCode::query()
|
|
->where('user_id', $owner->id)
|
|
->where('type', QrCode::TYPE_EVENT)
|
|
->orderByDesc('updated_at')
|
|
->get()
|
|
->filter(function (QrCode $event) {
|
|
$format = (string) ($event->content()['format'] ?? 'in_person');
|
|
|
|
return in_array($format, ['virtual', 'hybrid'], true);
|
|
})
|
|
->map(fn (QrCode $event) => $this->summarizeEvent($event))
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $payload
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function linkRoom(User $owner, QrCode $event, array $payload): array
|
|
{
|
|
abort_unless($event->user_id === $owner->id, 403);
|
|
abort_unless($event->type === QrCode::TYPE_EVENT, 422);
|
|
|
|
$format = (string) ($event->content()['format'] ?? 'in_person');
|
|
abort_unless(in_array($format, ['virtual', 'hybrid'], true), 422, 'Only virtual or hybrid events can be linked.');
|
|
|
|
$roomUuid = trim((string) ($payload['meet_room_uuid'] ?? ''));
|
|
$roomType = in_array($payload['meet_room_type'] ?? '', ['town_hall', 'webinar'], true)
|
|
? (string) $payload['meet_room_type']
|
|
: 'town_hall';
|
|
abort_unless($roomUuid !== '', 422, 'meet_room_uuid is required.');
|
|
|
|
$joinUrl = trim((string) ($payload['join_url'] ?? ''));
|
|
$title = trim((string) ($payload['title'] ?? $event->label ?? 'Virtual session'));
|
|
$sessionId = trim((string) ($payload['virtual_session_id'] ?? ''));
|
|
|
|
$content = $event->content();
|
|
$sessions = array_values(array_filter(
|
|
(array) ($content['virtual_sessions'] ?? []),
|
|
fn ($session) => is_array($session),
|
|
));
|
|
|
|
$matchedIndex = null;
|
|
if ($sessionId !== '') {
|
|
foreach ($sessions as $index => $session) {
|
|
if ((string) ($session['id'] ?? '') === $sessionId) {
|
|
$matchedIndex = $index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($matchedIndex === null) {
|
|
foreach ($sessions as $index => $session) {
|
|
$existingUuid = trim((string) ($session['meet_room_uuid'] ?? ''));
|
|
$existingType = (string) ($session['meet_room_type'] ?? 'town_hall');
|
|
if ($existingUuid === '' && $existingType === $roomType) {
|
|
$matchedIndex = $index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($matchedIndex === null) {
|
|
$sessionId = $sessionId !== '' ? $sessionId : 'vs-'.Str::lower(Str::random(12));
|
|
$sessions[] = [
|
|
'id' => $sessionId,
|
|
'title' => $title,
|
|
'meet_room_type' => $roomType,
|
|
'scheduled_at' => $payload['scheduled_at'] ?? $content['starts_at'] ?? null,
|
|
'duration_minutes' => max(15, (int) ($payload['duration_minutes'] ?? 60)),
|
|
];
|
|
$matchedIndex = count($sessions) - 1;
|
|
} else {
|
|
$sessionId = (string) ($sessions[$matchedIndex]['id'] ?? $sessionId);
|
|
}
|
|
|
|
$sessions[$matchedIndex] = array_merge($sessions[$matchedIndex], [
|
|
'id' => $sessionId,
|
|
'title' => $title !== '' ? $title : (string) ($sessions[$matchedIndex]['title'] ?? 'Virtual session'),
|
|
'meet_room_type' => $roomType,
|
|
'meet_room_uuid' => $roomUuid,
|
|
'join_url' => $joinUrl !== '' ? $joinUrl : ($sessions[$matchedIndex]['join_url'] ?? null),
|
|
'scheduled_at' => $payload['scheduled_at'] ?? $sessions[$matchedIndex]['scheduled_at'] ?? null,
|
|
'duration_minutes' => max(15, (int) ($payload['duration_minutes'] ?? ($sessions[$matchedIndex]['duration_minutes'] ?? 60))),
|
|
]);
|
|
|
|
$payloadData = (array) ($event->payload ?? []);
|
|
$payloadData['content'] = array_merge($content, ['virtual_sessions' => $sessions]);
|
|
$event->payload = $payloadData;
|
|
$event->save();
|
|
|
|
$event = $this->sync->sync($event->fresh(), $owner);
|
|
|
|
return array_merge($this->summarizeEvent($event), [
|
|
'entity_id' => $sessionId,
|
|
'meet_room_uuid' => $roomUuid,
|
|
'join_url' => $joinUrl,
|
|
]);
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
private function summarizeEvent(QrCode $event): array
|
|
{
|
|
$content = $event->content();
|
|
$sessions = collect((array) ($content['virtual_sessions'] ?? []))
|
|
->filter(fn ($session) => is_array($session))
|
|
->map(fn (array $session) => [
|
|
'id' => (string) ($session['id'] ?? ''),
|
|
'title' => (string) ($session['title'] ?? ''),
|
|
'meet_room_type' => (string) ($session['meet_room_type'] ?? 'town_hall'),
|
|
'meet_room_uuid' => ($uuid = trim((string) ($session['meet_room_uuid'] ?? ''))) !== '' ? $uuid : null,
|
|
'scheduled_at' => $session['scheduled_at'] ?? null,
|
|
'duration_minutes' => (int) ($session['duration_minutes'] ?? 60),
|
|
])
|
|
->values()
|
|
->all();
|
|
|
|
return [
|
|
'id' => $event->id,
|
|
'title' => (string) ($content['title'] ?? $event->label ?? 'Event'),
|
|
'format' => (string) ($content['format'] ?? 'in_person'),
|
|
'short_code' => $event->short_code,
|
|
'registration_url' => $event->publicUrl(),
|
|
'admin_url' => url('/events/'.$event->id.'/attendees'),
|
|
'edit_url' => url('/events/'.$event->id),
|
|
'virtual_sessions' => $sessions,
|
|
];
|
|
}
|
|
}
|