From 23026260d9dd30777ed7b7904dd863bfc89f6dbd Mon Sep 17 00:00:00 2001 From: isaacclad Date: Sat, 4 Jul 2026 22:12:12 +0000 Subject: [PATCH] Update existing Meet rooms by UUID when Events syncs programme data. Service API store now resolves meet_room_uuid before source lookup so programme snapshots apply to pre-linked rooms. Co-authored-by: Cursor --- .../Api/V1/ServiceRoomController.php | 15 +++++ tests/Feature/MeetWebTest.php | 58 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/app/Http/Controllers/Api/V1/ServiceRoomController.php b/app/Http/Controllers/Api/V1/ServiceRoomController.php index fc897f2..b71095c 100644 --- a/app/Http/Controllers/Api/V1/ServiceRoomController.php +++ b/app/Http/Controllers/Api/V1/ServiceRoomController.php @@ -34,6 +34,20 @@ class ServiceRoomController extends Controller $organization = $this->resolveOrganization($validated); abort_unless($organization->owner_ref === $validated['owner_ref'], 403); + $roomUuid = trim((string) ($validated['meet_room_uuid'] ?? '')); + if ($roomUuid !== '') { + $existing = Room::query() + ->where('uuid', $roomUuid) + ->where('owner_ref', $validated['owner_ref']) + ->first(); + + if ($existing) { + return $this->respondWithRoom( + $this->persistRoomUpdate($existing, $validated, $organization), + ); + } + } + $entityId = (string) ($validated['source']['entity_id'] ?? ''); if ($entityId !== '') { $existing = Room::query() @@ -148,6 +162,7 @@ class ServiceRoomController extends Controller 'source.event_id' => ['nullable', 'string'], 'invite_emails' => ['nullable', 'array'], 'invite_emails.*' => ['email'], + 'meet_room_uuid' => ['nullable', 'string', 'max:64'], ]); } diff --git a/tests/Feature/MeetWebTest.php b/tests/Feature/MeetWebTest.php index ebdce84..b470443 100644 --- a/tests/Feature/MeetWebTest.php +++ b/tests/Feature/MeetWebTest.php @@ -559,6 +559,64 @@ class MeetWebTest extends TestCase $this->assertSame(1, \App\Models\Room::where('source->entity_id', 'vs-dup')->count()); } + public function test_service_api_upserts_existing_room_by_meet_room_uuid(): void + { + \Illuminate\Support\Facades\Http::fake(); + config(['meet.service_api_keys.events' => 'test-events-key']); + + $room = \App\Models\Room::create([ + 'uuid' => 'prelinked-room-uuid', + 'owner_ref' => $this->user->public_id, + 'organization_id' => $this->organization->id, + 'host_user_ref' => $this->user->public_id, + 'title' => 'Prelinked town hall', + 'type' => 'town_hall', + 'status' => 'scheduled', + 'scheduled_at' => now()->addDay(), + 'timezone' => 'UTC', + 'settings' => config('meet.default_settings'), + ]); + + $programme = [ + 'title' => 'Summit programme', + 'days' => [ + [ + 'label' => 'Day 1', + 'items' => [ + ['time' => '09:00', 'title' => 'Opening keynote', 'host' => 'Alex'], + ], + ], + ], + ]; + + $this->postJson('/api/service/v1/rooms', [ + 'owner_ref' => $this->user->public_id, + 'host_user_ref' => $this->user->public_id, + 'meet_room_uuid' => $room->uuid, + 'title' => 'Opening keynote', + 'type' => 'town_hall', + 'scheduled_at' => now()->addDay()->toIso8601String(), + 'settings' => [ + 'programme_snapshot' => $programme, + 'linked_programme_items' => [], + ], + 'source' => [ + 'app' => 'events', + 'entity_type' => 'virtual_session', + 'entity_id' => 'vs-prelinked', + 'event_id' => '42', + ], + ], ['Authorization' => 'Bearer test-events-key']) + ->assertOk() + ->assertJsonPath('room.uuid', $room->uuid) + ->assertJsonPath('room.settings.programme_snapshot.title', 'Summit programme'); + + $this->assertSame(1, \App\Models\Room::count()); + $room->refresh(); + $this->assertSame('Summit programme', $room->setting('programme_snapshot')['title'] ?? null); + $this->assertSame('vs-prelinked', $room->source['entity_id'] ?? null); + } + public function test_service_api_lookup_by_source(): void { \Illuminate\Support\Facades\Http::fake();