Fix anonymous guests inheriting the host participant record.
Deploy Ladill Meet / deploy (push) Successful in 35s
Deploy Ladill Meet / deploy (push) Successful in 35s
Guest joins without email were matching any active participant, overwriting the host row and granting host controls; header now always shows room host. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -91,12 +91,7 @@ class SessionService
|
||||
?string $email = null,
|
||||
): Participant {
|
||||
$userRef = $user?->ownerRef();
|
||||
|
||||
$existing = $session->participants()
|
||||
->when($userRef, fn ($q) => $q->where('user_ref', $userRef))
|
||||
->when(! $userRef && $email, fn ($q) => $q->where('email', $email))
|
||||
->whereIn('status', ['invited', 'waiting', 'joined'])
|
||||
->first();
|
||||
$existing = $this->findExistingParticipant($session, $userRef, $email);
|
||||
|
||||
if ($existing) {
|
||||
$existing->update([
|
||||
@@ -136,6 +131,37 @@ class SessionService
|
||||
return $participant;
|
||||
}
|
||||
|
||||
protected function findExistingParticipant(Session $session, ?string $userRef, ?string $email): ?Participant
|
||||
{
|
||||
$active = fn ($q) => $q->whereIn('status', ['invited', 'waiting', 'joined']);
|
||||
|
||||
if ($userRef) {
|
||||
return $session->participants()
|
||||
->where('user_ref', $userRef)
|
||||
->where($active)
|
||||
->first();
|
||||
}
|
||||
|
||||
if ($email) {
|
||||
return $session->participants()
|
||||
->whereNull('user_ref')
|
||||
->where('email', $email)
|
||||
->where($active)
|
||||
->first();
|
||||
}
|
||||
|
||||
$guestUuid = (string) request()?->session()?->get("meet.participant.{$session->uuid}", '');
|
||||
if ($guestUuid === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $session->participants()
|
||||
->where('uuid', $guestUuid)
|
||||
->whereNull('user_ref')
|
||||
->where($active)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function rememberParticipantSession(Request $request, Participant $participant, ?Session $session = null): void
|
||||
{
|
||||
$session ??= $participant->session;
|
||||
|
||||
@@ -41,6 +41,7 @@ function meetRoom() {
|
||||
connectionStatus: 'Connecting…',
|
||||
participants: [],
|
||||
sessionParticipants: [],
|
||||
roomHost: null,
|
||||
floatingReactions: [],
|
||||
pollTimer: null,
|
||||
config: {},
|
||||
@@ -95,6 +96,12 @@ function meetRoom() {
|
||||
this.sessionParticipants = [];
|
||||
}
|
||||
|
||||
try {
|
||||
this.roomHost = JSON.parse(el.dataset.roomHost || 'null');
|
||||
} catch {
|
||||
this.roomHost = null;
|
||||
}
|
||||
|
||||
if (this.config.configured && this.config.token) {
|
||||
this.connectLiveKit();
|
||||
} else {
|
||||
@@ -318,8 +325,20 @@ function meetRoom() {
|
||||
|
||||
hostParticipant() {
|
||||
const hosts = this.sessionParticipants.filter((p) => p.role === 'host' || p.role === 'co_host');
|
||||
if (hosts.length) {
|
||||
return hosts[0];
|
||||
}
|
||||
|
||||
return hosts[0] || this.sessionParticipants[0] || null;
|
||||
if (this.roomHost?.user_ref) {
|
||||
const inCall = this.sessionParticipants.find((p) => p.user_ref === this.roomHost.user_ref);
|
||||
if (inCall) {
|
||||
return inCall;
|
||||
}
|
||||
|
||||
return this.roomHost;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
participantCount() {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</head>
|
||||
<body class="h-full overflow-hidden bg-slate-950 font-sans text-white" x-data="meetRoom()" x-init="init()">
|
||||
@php
|
||||
use App\Models\User;
|
||||
use App\Services\Meet\ParticipantPresenter;
|
||||
|
||||
$joined = $session->participants->where('status', 'joined');
|
||||
@@ -17,6 +18,12 @@
|
||||
$joinedParticipants = $joined
|
||||
->map(fn ($p) => ParticipantPresenter::toArray($p, $participantAvatars, $room->host_user_ref))
|
||||
->values();
|
||||
$roomHostUser = User::query()->where('public_id', $room->host_user_ref)->first();
|
||||
$roomHost = [
|
||||
'user_ref' => $room->host_user_ref,
|
||||
'display_name' => $roomHostUser?->name ?? 'Host',
|
||||
'avatar_url' => $roomHostUser?->avatarUrl(),
|
||||
];
|
||||
@endphp
|
||||
<div id="meet-config"
|
||||
data-token="{{ $mediaToken }}"
|
||||
@@ -55,6 +62,7 @@
|
||||
data-passcode="{{ $room->passcode ?? '' }}"
|
||||
data-csrf="{{ csrf_token() }}"
|
||||
data-initial-participants='@json($joinedParticipants)'
|
||||
data-room-host='@json($roomHost)'
|
||||
hidden></div>
|
||||
|
||||
@if (! $mediaConfigured)
|
||||
|
||||
@@ -152,6 +152,50 @@ class MeetWebTest extends TestCase
|
||||
->assertSee('data-display-name="Guest User"', false);
|
||||
}
|
||||
|
||||
public function test_anonymous_guest_does_not_take_over_host_participant(): void
|
||||
{
|
||||
$room = $this->createRoom([
|
||||
'settings' => array_merge(config('meet.default_settings'), [
|
||||
'join_before_host' => true,
|
||||
]),
|
||||
]);
|
||||
$session = Session::create([
|
||||
'owner_ref' => $this->user->public_id,
|
||||
'room_id' => $room->id,
|
||||
'media_room_name' => 'room-'.$room->uuid,
|
||||
'status' => 'live',
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$room->update(['status' => 'live']);
|
||||
|
||||
$hostParticipant = \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->post('/r/'.$room->uuid.'/enter', [
|
||||
'display_name' => 'Guest User',
|
||||
])->assertRedirect(route('meet.room', $session));
|
||||
|
||||
$hostParticipant->refresh();
|
||||
$this->assertSame('host', $hostParticipant->role);
|
||||
$this->assertSame($this->user->name, $hostParticipant->display_name);
|
||||
|
||||
$guest = \App\Models\Participant::query()
|
||||
->where('session_id', $session->id)
|
||||
->where('display_name', 'Guest User')
|
||||
->first();
|
||||
|
||||
$this->assertNotNull($guest);
|
||||
$this->assertSame('guest', $guest->role);
|
||||
$this->assertNotSame($hostParticipant->uuid, $guest->uuid);
|
||||
}
|
||||
|
||||
public function test_authenticated_user_can_join_live_meeting_without_display_name(): void
|
||||
{
|
||||
$room = $this->createRoom();
|
||||
|
||||
Reference in New Issue
Block a user