Deploy Ladill Events / deploy (push) Successful in 31s
Meet can persist the agenda locally when linking, even if the service-to-service Meet sync fails. Co-authored-by: Cursor <cursoragent@cursor.com>
214 lines
7.2 KiB
PHP
214 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Meet;
|
|
|
|
use App\Models\QrCode;
|
|
use App\Models\User;
|
|
use App\Services\Events\EventProgrammeService;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Str;
|
|
|
|
class EventMeetSyncService
|
|
{
|
|
public function __construct(private readonly EventProgrammeService $programmes) {}
|
|
|
|
public function sync(QrCode $event, User $owner): QrCode
|
|
{
|
|
if ($event->type !== QrCode::TYPE_EVENT) {
|
|
return $event;
|
|
}
|
|
|
|
$content = $event->content();
|
|
$format = (string) ($content['format'] ?? 'in_person');
|
|
|
|
if (! in_array($format, ['virtual', 'hybrid'], true)) {
|
|
$this->cancelRemovedSessions($event, $owner, []);
|
|
|
|
return $event;
|
|
}
|
|
|
|
if ((string) config('meet.key', '') === '') {
|
|
return $event;
|
|
}
|
|
|
|
$programmeSnapshot = $this->programmeSnapshotFor($event);
|
|
$sessions = (array) ($content['virtual_sessions'] ?? []);
|
|
$client = MeetClient::for($owner->public_id);
|
|
$synced = [];
|
|
$activeIds = [];
|
|
|
|
foreach ($sessions as $session) {
|
|
if (! is_array($session)) {
|
|
continue;
|
|
}
|
|
|
|
$sessionId = trim((string) ($session['id'] ?? ''));
|
|
if ($sessionId === '') {
|
|
$sessionId = 'vs-'.Str::lower(Str::random(12));
|
|
}
|
|
|
|
$activeIds[] = $sessionId;
|
|
$title = trim((string) ($session['title'] ?? ''));
|
|
if ($title === '') {
|
|
$synced[] = array_merge($session, ['id' => $sessionId]);
|
|
|
|
continue;
|
|
}
|
|
|
|
$roomType = in_array($session['meet_room_type'] ?? '', ['town_hall', 'webinar'], true)
|
|
? (string) $session['meet_room_type']
|
|
: 'town_hall';
|
|
|
|
$scheduledAt = $session['scheduled_at'] ?? $content['starts_at'] ?? null;
|
|
$itemRefs = (array) ($session['programme_item_refs'] ?? []);
|
|
$linkedItems = $this->programmes->itemsForRefs($programmeSnapshot, $itemRefs);
|
|
$inviteEmails = $this->inviteEmailsFromHosts($this->programmes->hostsFromItems($linkedItems));
|
|
|
|
$settings = [
|
|
'programme_snapshot' => $programmeSnapshot,
|
|
'linked_programme_items' => $linkedItems,
|
|
];
|
|
|
|
if ($roomType === 'town_hall' && $linkedItems !== []) {
|
|
$settings['panels'] = [[
|
|
'id' => 'panel-'.$sessionId,
|
|
'name' => $title,
|
|
'speaker_refs' => [],
|
|
]];
|
|
$settings['panel_discussions'] = true;
|
|
}
|
|
|
|
$roomPayload = [
|
|
'title' => $title,
|
|
'description' => trim((string) ($content['description'] ?? '')) ?: null,
|
|
'type' => $roomType,
|
|
'scheduled_at' => $scheduledAt,
|
|
'duration_minutes' => max(15, (int) ($session['duration_minutes'] ?? 60)),
|
|
'timezone' => config('app.timezone', 'UTC'),
|
|
'settings' => $settings,
|
|
'invite_emails' => $inviteEmails,
|
|
'source' => [
|
|
'app' => 'events',
|
|
'entity_type' => 'virtual_session',
|
|
'entity_id' => $sessionId,
|
|
'event_id' => (string) $event->id,
|
|
],
|
|
];
|
|
|
|
$existingRoomUuid = trim((string) ($session['meet_room_uuid'] ?? ''));
|
|
|
|
try {
|
|
$result = $existingRoomUuid !== ''
|
|
? $client->updateRoom($existingRoomUuid, $roomPayload)
|
|
: $client->upsertRoom($roomPayload);
|
|
} catch (\Throwable $e) {
|
|
Log::warning('Events Meet sync failed', [
|
|
'event_id' => $event->id,
|
|
'session_id' => $sessionId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
$synced[] = array_merge($session, ['id' => $sessionId]);
|
|
|
|
continue;
|
|
}
|
|
|
|
$room = (array) ($result['room'] ?? []);
|
|
$synced[] = array_merge($session, [
|
|
'id' => $sessionId,
|
|
'meet_room_uuid' => $room['uuid'] ?? $session['meet_room_uuid'] ?? null,
|
|
'join_url' => $result['join_url'] ?? $session['join_url'] ?? null,
|
|
]);
|
|
}
|
|
|
|
$this->cancelRemovedSessions($event, $owner, $activeIds);
|
|
|
|
$payload = (array) ($event->payload ?? []);
|
|
$payload['content'] = array_merge($content, ['virtual_sessions' => array_values($synced)]);
|
|
$event->payload = $payload;
|
|
$event->save();
|
|
|
|
return $event->fresh();
|
|
}
|
|
|
|
public function syncEventsForProgramme(QrCode $programme, User $owner): void
|
|
{
|
|
foreach ($this->programmes->eventsLinkedToProgramme($programme) as $event) {
|
|
$this->sync($event->fresh(), $owner);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $session
|
|
* @return array{programme_snapshot: array<string, mixed>|null, linked_programme_items: list<array<string, mixed>>}
|
|
*/
|
|
public function programmePayloadForSession(QrCode $event, array $session): array
|
|
{
|
|
$programmeSnapshot = $this->programmeSnapshotFor($event);
|
|
$itemRefs = (array) ($session['programme_item_refs'] ?? []);
|
|
|
|
return [
|
|
'programme_snapshot' => $programmeSnapshot,
|
|
'linked_programme_items' => $this->programmes->itemsForRefs($programmeSnapshot, $itemRefs),
|
|
];
|
|
}
|
|
|
|
/** @return array<string, mixed>|null */
|
|
private function programmeSnapshotFor(QrCode $event): ?array
|
|
{
|
|
$programmeId = (int) ($event->content()['programme_qr_id'] ?? 0);
|
|
if ($programmeId <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$programme = QrCode::where('id', $programmeId)
|
|
->where('user_id', $event->user_id)
|
|
->where('type', QrCode::TYPE_ITINERARY)
|
|
->first();
|
|
|
|
return $this->programmes->snapshot($programme);
|
|
}
|
|
|
|
/** @param list<string> $hosts */
|
|
private function inviteEmailsFromHosts(array $hosts): array
|
|
{
|
|
return collect($hosts)
|
|
->filter(fn ($host) => filter_var($host, FILTER_VALIDATE_EMAIL))
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
/** @param list<string> $keepIds */
|
|
private function cancelRemovedSessions(QrCode $event, User $owner, array $keepIds): void
|
|
{
|
|
if ((string) config('meet.key', '') === '') {
|
|
return;
|
|
}
|
|
|
|
$previous = (array) ($event->content()['virtual_sessions'] ?? []);
|
|
$client = MeetClient::for($owner->public_id);
|
|
|
|
foreach ($previous as $session) {
|
|
if (! is_array($session)) {
|
|
continue;
|
|
}
|
|
|
|
$sessionId = (string) ($session['id'] ?? '');
|
|
$roomUuid = (string) ($session['meet_room_uuid'] ?? '');
|
|
|
|
if ($sessionId === '' || in_array($sessionId, $keepIds, true) || $roomUuid === '') {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$client->cancelRoom($roomUuid);
|
|
} catch (\Throwable $e) {
|
|
Log::warning('Events Meet cancel failed', [
|
|
'event_id' => $event->id,
|
|
'session_id' => $sessionId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|