Improve conferences, guest entry, Afia, and cross-app scheduling.
Deploy Ladill Meet / deploy (push) Successful in 50s

Route guests through silent SSO to the Meet product page, fix Afia context
query, add conference green-room UX and copy, and extend service API for
Care/CRM/Invoice calendar integration.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-01 20:12:57 +00:00
co-authored by Cursor
parent be8f76cd47
commit 799c302e2a
32 changed files with 601 additions and 89 deletions
+130
View File
@@ -67,6 +67,20 @@ class MeetWebTest extends TestCase
$this->get('/dashboard')->assertRedirect();
}
public function test_guest_root_uses_silent_sso_not_interactive_auth(): void
{
$response = $this->get('/');
$response->assertRedirect(route('sso.connect'));
$this->assertStringNotContainsString('interactive=1', (string) $response->headers->get('Location'));
}
public function test_sso_callback_sends_guest_without_session_to_marketing_page(): void
{
$this->get('/sso/callback?error=login_required')
->assertRedirect(config('ladill.marketing_url'));
}
public function test_onboarded_user_can_view_dashboard(): void
{
$this->actingAs($this->user)
@@ -464,6 +478,7 @@ class MeetWebTest extends TestCase
public function test_service_api_can_create_room(): void
{
\Illuminate\Support\Facades\Http::fake();
config(['meet.service_api_keys.care' => 'test-care-key']);
$this->postJson('/api/service/v1/rooms', [
@@ -482,6 +497,51 @@ class MeetWebTest extends TestCase
]);
}
public function test_service_api_resolves_organization_from_owner_ref(): void
{
\Illuminate\Support\Facades\Http::fake();
config(['meet.service_api_keys.crm' => 'test-crm-key']);
$this->postJson('/api/service/v1/rooms', [
'owner_ref' => $this->user->public_id,
'host_user_ref' => $this->user->public_id,
'title' => 'CRM follow-up',
'scheduled_at' => now()->addDay()->toIso8601String(),
'source' => ['app' => 'crm', 'entity_type' => 'deal', 'entity_id' => '42'],
], ['Authorization' => 'Bearer test-crm-key'])
->assertCreated()
->assertJsonPath('room.organization_id', $this->organization->id);
}
public function test_scheduled_room_syncs_to_ladill_mail_calendar(): void
{
\Illuminate\Support\Facades\Http::fake([
'mail.ladill.com/*' => \Illuminate\Support\Facades\Http::response(['data' => ['id' => 99]], 201),
]);
config([
'meet.calendar.mail.api_url' => 'https://mail.ladill.com/api/service/v1',
'meet.calendar.mail.api_key' => 'mail-test-key',
]);
$this->actingAs($this->user)
->post('/meetings', [
'title' => 'Calendar sync test',
'scheduled_at' => now()->addDay()->format('Y-m-d H:i'),
'duration_minutes' => 30,
])
->assertRedirect();
$room = \App\Models\Room::where('title', 'Calendar sync test')->first();
$this->assertNotNull($room);
$this->assertSame('99', (string) $room->calendar_event_id);
\Illuminate\Support\Facades\Http::assertSent(function ($request) {
return str_contains($request->url(), '/calendar/events')
&& $request['mailbox_email'] === strtolower($this->user->email);
});
}
public function test_invitation_rsvp_accepts(): void
{
$room = $this->createRoom();
@@ -614,6 +674,55 @@ class MeetWebTest extends TestCase
]);
}
public function test_host_can_end_conference_and_view_details(): void
{
$room = Room::create([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'host_user_ref' => $this->user->public_id,
'title' => 'NextGen Summit',
'type' => 'town_hall',
'status' => 'live',
'scheduled_at' => now()->addHour(),
'timezone' => 'UTC',
'settings' => array_merge(config('meet.default_settings'), [
'green_room' => true,
'stage_mode' => true,
'presenter_refs' => [],
]),
]);
$session = Session::create([
'owner_ref' => $this->user->public_id,
'room_id' => $room->id,
'media_room_name' => 'meet-'.$room->uuid,
'status' => 'live',
'session_mode' => 'live',
'started_at' => now(),
]);
$participant = \App\Models\Participant::create([
'owner_ref' => $this->user->public_id,
'session_id' => $session->id,
'user_ref' => $this->user->public_id,
'display_name' => $this->user->name,
'role' => 'host',
'status' => 'joined',
'joined_at' => now(),
]);
$this->actingAs($this->user)
->withSession(["meet.participant.{$session->uuid}" => $participant->uuid])
->post('/room/'.$session->uuid.'/end')
->assertRedirect(route('meet.conferences.show', $room))
->assertSessionHas('success', 'Conference ended.');
$this->actingAs($this->user)
->get(route('meet.conferences.show', $room))
->assertOk()
->assertSee('NextGen Summit');
}
public function test_host_can_create_space_room(): void
{
$this->actingAs($this->user)
@@ -629,6 +738,27 @@ class MeetWebTest extends TestCase
]);
}
public function test_afia_chat_returns_reply_when_ai_configured(): void
{
config([
'afia.api_key' => 'test-openai-key',
'afia.platform_api_key' => '',
]);
Http::fake([
'api.openai.com/*' => Http::response([
'choices' => [['message' => ['content' => 'Go to Meetings and click Schedule meeting.']]],
]),
]);
$this->createRoom(['title' => 'Upcoming sync']);
$this->actingAs($this->user)
->postJson('/ai/chat', ['message' => 'How do I schedule a meeting?'])
->assertOk()
->assertJson(['reply' => 'Go to Meetings and click Schedule meeting.']);
}
protected function createRoom(array $overrides = []): Room
{
return Room::create(array_merge([