Fix green room Go live and Panels hidden for conference hosts.
Deploy Ladill Meet / deploy (push) Successful in 34s

Stop registerPresenter from demoting hosts to panelists, recognize room owners as managers, and show stage controls in the green room banner.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-01 22:54:15 +00:00
co-authored by Cursor
parent 0a8cd2b4f9
commit 712dc487c6
6 changed files with 66 additions and 8 deletions
@@ -356,7 +356,16 @@ class MeetingFeaturesController extends Controller
protected function hostOnly(Request $request, Session $session): Participant protected function hostOnly(Request $request, Session $session): Participant
{ {
$participant = $this->participant($request, $session); $participant = $this->participant($request, $session);
abort_unless($participant->isHost(), 403); $user = $request->user();
$isRoomHost = $user && $user->ownerRef() === $session->room->host_user_ref;
abort_unless($participant->isHost() || $isRoomHost, 403);
if ($isRoomHost && ! $participant->isHost()) {
$participant->update(['role' => 'host']);
return $participant->fresh();
}
return $participant; return $participant;
} }
@@ -66,6 +66,9 @@ class MeetingRoomController extends Controller
$spaces = app(SpaceService::class); $spaces = app(SpaceService::class);
$isAudioOnly = $room->isAudioOnly(); $isAudioOnly = $room->isAudioOnly();
$stageLayout = app(StageLayoutService::class); $stageLayout = app(StageLayoutService::class);
$authUser = $request->user();
$isRoomHost = $authUser && $authUser->ownerRef() === $room->host_user_ref;
$canManageConference = $participant->isHost() || $isRoomHost;
return view('meet.room.show', [ return view('meet.room.show', [
'session' => $session, 'session' => $session,
@@ -90,6 +93,7 @@ class MeetingRoomController extends Controller
'isAttendee' => $participant->isAttendee() || $spaces->isListener($room, $participant), 'isAttendee' => $participant->isAttendee() || $spaces->isListener($room, $participant),
'usesStageLayout' => $stageLayout->usesStageLayout($room), 'usesStageLayout' => $stageLayout->usesStageLayout($room),
'stageConfig' => $stageLayout->config($room), 'stageConfig' => $stageLayout->config($room),
'canManageConference' => $canManageConference,
]); ]);
} }
+6
View File
@@ -108,6 +108,12 @@ class SessionService
$updates['joined_at'] = $existing->joined_at ?? now(); $updates['joined_at'] = $existing->joined_at ?? now();
} }
if (in_array($role, ['host', 'co_host'], true)) {
$updates['role'] = $role;
} elseif ($existing->role === 'guest' && $role !== 'guest') {
$updates['role'] = $role;
}
$existing->update($updates); $existing->update($updates);
return $existing; return $existing;
+1
View File
@@ -103,6 +103,7 @@ class TownHallService
$session->participants() $session->participants()
->where('user_ref', $userRef) ->where('user_ref', $userRef)
->where('status', 'joined') ->where('status', 'joined')
->whereNotIn('role', ['host', 'co_host'])
->update(['role' => 'panelist']); ->update(['role' => 'panelist']);
return $session->fresh(); return $session->fresh();
+7 -7
View File
@@ -34,7 +34,7 @@
data-configured="{{ $mediaConfigured ? '1' : '0' }}" data-configured="{{ $mediaConfigured ? '1' : '0' }}"
data-participant="{{ $participant->uuid }}" data-participant="{{ $participant->uuid }}"
data-display-name="{{ $participant->display_name }}" data-display-name="{{ $participant->display_name }}"
data-is-host="{{ $participant->isHost() ? '1' : '0' }}" data-is-host="{{ ($canManageConference ?? $participant->isHost()) ? '1' : '0' }}"
data-poll-url="{{ route('meet.room.poll', $session) }}" data-poll-url="{{ route('meet.room.poll', $session) }}"
data-ended-url="{{ route('meet.ended', $session) }}" data-ended-url="{{ route('meet.ended', $session) }}"
data-chat-url="{{ route('meet.room.chat', $session) }}" data-chat-url="{{ route('meet.room.chat', $session) }}"
@@ -59,9 +59,9 @@
data-is-conference="{{ ($isConference ?? false) ? '1' : '0' }}" data-is-conference="{{ ($isConference ?? false) ? '1' : '0' }}"
data-is-green-room="{{ ($isGreenRoom ?? false) ? '1' : '0' }}" data-is-green-room="{{ ($isGreenRoom ?? false) ? '1' : '0' }}"
data-session-mode="{{ $session->session_mode }}" data-session-mode="{{ $session->session_mode }}"
data-go-live-url="{{ ($isConference ?? false) && ($isGreenRoom ?? false) && $participant->isHost() ? route('meet.room.townhall.live', $session) : '' }}" data-go-live-url="{{ ($isConference ?? false) && ($isGreenRoom ?? false) && ($canManageConference ?? $participant->isHost()) ? route('meet.room.townhall.live', $session) : '' }}"
data-add-presenter-url="{{ ($isConference ?? false) && $participant->isHost() ? route('meet.room.townhall.presenters', $session) : '' }}" data-add-presenter-url="{{ ($isConference ?? false) && ($canManageConference ?? $participant->isHost()) ? route('meet.room.townhall.presenters', $session) : '' }}"
data-stage-update-url="{{ ($usesStageLayout ?? false) && $participant->isHost() ? route('meet.room.stage.update', $session) : '' }}" data-stage-update-url="{{ ($usesStageLayout ?? false) && ($canManageConference ?? $participant->isHost()) ? route('meet.room.stage.update', $session) : '' }}"
data-uses-stage-layout="{{ ($usesStageLayout ?? false) ? '1' : '0' }}" data-uses-stage-layout="{{ ($usesStageLayout ?? false) ? '1' : '0' }}"
data-panel-discussions="{{ ($stageConfig['panel_discussions'] ?? false) ? '1' : '0' }}" data-panel-discussions="{{ ($stageConfig['panel_discussions'] ?? false) ? '1' : '0' }}"
data-stage-layout="{{ $stageConfig['stage_layout'] ?? 'plenary' }}" data-stage-layout="{{ $stageConfig['stage_layout'] ?? 'plenary' }}"
@@ -143,13 +143,13 @@
</header> </header>
<div x-show="isConference && isGreenRoom" x-cloak <div x-show="isConference && isGreenRoom" x-cloak
class="flex shrink-0 items-center justify-between gap-3 border-b border-violet-500/30 bg-violet-500/15 px-4 py-2.5"> class="flex shrink-0 flex-col gap-2 border-b border-violet-500/30 bg-violet-500/15 px-4 py-2.5 sm:flex-row sm:items-center sm:justify-between sm:gap-3">
<div class="min-w-0 text-sm text-violet-100"> <div class="min-w-0 text-sm text-violet-100">
<p class="font-medium">Green room</p> <p class="font-medium">Green room</p>
<p class="truncate text-xs text-violet-200/90">Only hosts and speakers are visible. Attendees join after you go live.</p> <p class="truncate text-xs text-violet-200/90">Only hosts and speakers are visible. Attendees join after you go live.</p>
</div> </div>
<div class="flex shrink-0 items-center gap-2"> <div class="flex shrink-0 flex-wrap items-center gap-2">
<button x-show="isHost && usesStageLayout && panelDiscussions" @click="panelSetupOpen = true" type="button" <button x-show="isHost && usesStageLayout" @click="panelSetupOpen = true" type="button"
class="shrink-0 rounded-lg border border-violet-400/40 bg-violet-500/20 px-3 py-1.5 text-xs font-semibold text-violet-100 transition-colors hover:bg-violet-500/30"> class="shrink-0 rounded-lg border border-violet-400/40 bg-violet-500/20 px-3 py-1.5 text-xs font-semibold text-violet-100 transition-colors hover:bg-violet-500/30">
@include('meet.room.partials.meet-icon', ['icon' => 'panel', 'class' => 'mr-1 inline h-3.5 w-3.5']) @include('meet.room.partials.meet-icon', ['icon' => 'panel', 'class' => 'mr-1 inline h-3.5 w-3.5'])
Panels Panels
+38
View File
@@ -749,6 +749,44 @@ class MeetWebTest extends TestCase
]); ]);
} }
public function test_green_room_register_presenter_keeps_host_role(): 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' => config('meet.default_settings'),
]);
$session = Session::create([
'owner_ref' => $this->user->public_id,
'room_id' => $room->id,
'media_room_name' => 'meet-'.$room->uuid.'-green',
'status' => 'live',
'session_mode' => 'green_room',
'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(),
]);
app(\App\Services\Meet\ConferenceService::class)->registerPresenter($session, $this->user, 'host');
$this->assertSame('host', $participant->fresh()->role);
}
public function test_host_can_end_conference_and_view_details(): void public function test_host_can_end_conference_and_view_details(): void
{ {
$room = Room::create([ $room = Room::create([