Fix stuck recording processing and add invoice service API test.
Deploy Ladill Meet / deploy (push) Successful in 52s
Deploy Ladill Meet / deploy (push) Successful in 52s
Capture stage spotlight video for browser recordings, fail incomplete uploads, allow post-session host uploads, and expire stale processing recordings automatically. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -431,11 +431,25 @@ class MeetingRoomController extends Controller
|
||||
|
||||
public function stopRecording(Request $request, Session $session): JsonResponse
|
||||
{
|
||||
$participant = $this->currentParticipant($request, $session);
|
||||
abort_unless($participant->isHost(), 403);
|
||||
$participant = $this->recordingHost($request, $session);
|
||||
|
||||
$recording = $session->recordings()->where('status', 'recording')->firstOrFail();
|
||||
$recording = $this->recordings->stop($recording, $participant->user_ref ?? $participant->uuid);
|
||||
$actorRef = $participant->user_ref ?? $participant->uuid;
|
||||
|
||||
if ($request->boolean('failed')) {
|
||||
$recording = $this->recordings->fail(
|
||||
$recording,
|
||||
(string) $request->input('reason', 'Recording capture did not complete.'),
|
||||
$actorRef,
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'status' => 'failed',
|
||||
'recording_uuid' => $recording->uuid,
|
||||
]);
|
||||
}
|
||||
|
||||
$recording = $this->recordings->stop($recording, $actorRef);
|
||||
|
||||
return response()->json([
|
||||
'status' => 'processing',
|
||||
@@ -443,10 +457,27 @@ class MeetingRoomController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function failRecording(Request $request, Session $session, Recording $recording): JsonResponse
|
||||
{
|
||||
$participant = $this->recordingHost($request, $session);
|
||||
abort_unless($recording->session_id === $session->id, 404);
|
||||
abort_if(! in_array($recording->status, ['recording', 'processing'], true), 422);
|
||||
|
||||
$recording = $this->recordings->fail(
|
||||
$recording,
|
||||
(string) $request->input('reason', 'Recording capture did not complete.'),
|
||||
$participant->user_ref ?? $participant->uuid,
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'status' => $recording->status,
|
||||
'recording_uuid' => $recording->uuid,
|
||||
]);
|
||||
}
|
||||
|
||||
public function uploadRecording(Request $request, Session $session, Recording $recording): JsonResponse
|
||||
{
|
||||
$participant = $this->currentParticipant($request, $session);
|
||||
abort_unless($participant->isHost(), 403);
|
||||
$participant = $this->recordingHost($request, $session);
|
||||
abort_unless($recording->session_id === $session->id, 404);
|
||||
|
||||
$maxKb = max(1, (int) config('meet.recordings.max_mb', 512)) * 1024;
|
||||
@@ -529,4 +560,33 @@ class MeetingRoomController extends Controller
|
||||
->firstOrFail()
|
||||
);
|
||||
}
|
||||
|
||||
/** Host/co-host in the room session, or the room host after the meeting ended. */
|
||||
protected function recordingHost(Request $request, Session $session): Participant
|
||||
{
|
||||
$participantUuid = $request->session()->get("meet.participant.{$session->uuid}");
|
||||
if ($participantUuid) {
|
||||
$participant = Participant::query()
|
||||
->where('uuid', $participantUuid)
|
||||
->where('session_id', $session->id)
|
||||
->first();
|
||||
|
||||
if ($participant?->isHost()) {
|
||||
return $this->sessions->syncEventsSpeakerRole($request, $participant);
|
||||
}
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
abort_unless($user, 403);
|
||||
|
||||
$hostParticipant = $session->participants()
|
||||
->where('user_ref', $user->ownerRef())
|
||||
->whereIn('role', ['host', 'co_host'])
|
||||
->orderByRaw("case when role = 'host' then 0 else 1 end")
|
||||
->first();
|
||||
|
||||
abort_unless($hostParticipant, 403);
|
||||
|
||||
return $hostParticipant;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class RecordingController extends Controller
|
||||
$this->authorizeAbility($request, 'meetings.view');
|
||||
$this->authorizeOwner($request, $recording);
|
||||
$recording->load(['session.room', 'session.aiSummaries', 'session.participants']);
|
||||
$recording = $this->recordings->ensureStorageValid($recording);
|
||||
$recording = $this->recordings->resolveProcessingState($recording);
|
||||
|
||||
$canManage = app(\App\Services\Meet\MeetPermissions::class)
|
||||
->can($this->member($request), 'meetings.manage');
|
||||
@@ -52,7 +52,7 @@ class RecordingController extends Controller
|
||||
{
|
||||
$this->authorizeAbility($request, 'meetings.view');
|
||||
$this->authorizeOwner($request, $recording);
|
||||
$recording = $this->recordings->ensureStorageValid($recording);
|
||||
$recording = $this->recordings->resolveProcessingState($recording);
|
||||
abort_unless($recording->hasPlayableFile(), 404, 'Recording file is not available.');
|
||||
abort_unless(app(\App\Services\Meet\MeetBillingService::class)->storageIsAccessible($recording), 402, 'Recording storage billing is overdue. Top up your Ladill wallet to download this recording.');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user