diff --git a/app/Http/Controllers/Meet/MeetingFeaturesController.php b/app/Http/Controllers/Meet/MeetingFeaturesController.php index 1f64c0e..b0291a0 100644 --- a/app/Http/Controllers/Meet/MeetingFeaturesController.php +++ b/app/Http/Controllers/Meet/MeetingFeaturesController.php @@ -356,7 +356,16 @@ class MeetingFeaturesController extends Controller protected function hostOnly(Request $request, Session $session): Participant { $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; } diff --git a/app/Http/Controllers/Meet/MeetingRoomController.php b/app/Http/Controllers/Meet/MeetingRoomController.php index af11c57..53b7cdf 100644 --- a/app/Http/Controllers/Meet/MeetingRoomController.php +++ b/app/Http/Controllers/Meet/MeetingRoomController.php @@ -66,6 +66,9 @@ class MeetingRoomController extends Controller $spaces = app(SpaceService::class); $isAudioOnly = $room->isAudioOnly(); $stageLayout = app(StageLayoutService::class); + $authUser = $request->user(); + $isRoomHost = $authUser && $authUser->ownerRef() === $room->host_user_ref; + $canManageConference = $participant->isHost() || $isRoomHost; return view('meet.room.show', [ 'session' => $session, @@ -90,6 +93,7 @@ class MeetingRoomController extends Controller 'isAttendee' => $participant->isAttendee() || $spaces->isListener($room, $participant), 'usesStageLayout' => $stageLayout->usesStageLayout($room), 'stageConfig' => $stageLayout->config($room), + 'canManageConference' => $canManageConference, ]); } diff --git a/app/Services/Meet/SessionService.php b/app/Services/Meet/SessionService.php index 1aa9867..99d9193 100644 --- a/app/Services/Meet/SessionService.php +++ b/app/Services/Meet/SessionService.php @@ -108,6 +108,12 @@ class SessionService $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); return $existing; diff --git a/app/Services/Meet/TownHallService.php b/app/Services/Meet/TownHallService.php index 3e330af..4f88f39 100644 --- a/app/Services/Meet/TownHallService.php +++ b/app/Services/Meet/TownHallService.php @@ -103,6 +103,7 @@ class TownHallService $session->participants() ->where('user_ref', $userRef) ->where('status', 'joined') + ->whereNotIn('role', ['host', 'co_host']) ->update(['role' => 'panelist']); return $session->fresh(); diff --git a/resources/views/meet/room/show.blade.php b/resources/views/meet/room/show.blade.php index eeb4bb9..b235934 100644 --- a/resources/views/meet/room/show.blade.php +++ b/resources/views/meet/room/show.blade.php @@ -34,7 +34,7 @@ data-configured="{{ $mediaConfigured ? '1' : '0' }}" data-participant="{{ $participant->uuid }}" 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-ended-url="{{ route('meet.ended', $session) }}" data-chat-url="{{ route('meet.room.chat', $session) }}" @@ -59,9 +59,9 @@ data-is-conference="{{ ($isConference ?? false) ? '1' : '0' }}" data-is-green-room="{{ ($isGreenRoom ?? false) ? '1' : '0' }}" data-session-mode="{{ $session->session_mode }}" - data-go-live-url="{{ ($isConference ?? false) && ($isGreenRoom ?? false) && $participant->isHost() ? route('meet.room.townhall.live', $session) : '' }}" - data-add-presenter-url="{{ ($isConference ?? false) && $participant->isHost() ? route('meet.room.townhall.presenters', $session) : '' }}" - data-stage-update-url="{{ ($usesStageLayout ?? false) && $participant->isHost() ? route('meet.room.stage.update', $session) : '' }}" + data-go-live-url="{{ ($isConference ?? false) && ($isGreenRoom ?? false) && ($canManageConference ?? $participant->isHost()) ? route('meet.room.townhall.live', $session) : '' }}" + data-add-presenter-url="{{ ($isConference ?? false) && ($canManageConference ?? $participant->isHost()) ? route('meet.room.townhall.presenters', $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-panel-discussions="{{ ($stageConfig['panel_discussions'] ?? false) ? '1' : '0' }}" data-stage-layout="{{ $stageConfig['stage_layout'] ?? 'plenary' }}" @@ -143,13 +143,13 @@
+ 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">

Green room

Only hosts and speakers are visible. Attendees join after you go live.

-
-