mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-30 13:49:00 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc9d8fdc0c |
@@ -198,37 +198,3 @@ class IsPresentInMeeting(permissions.BasePermission):
|
||||
return False
|
||||
except ParticipantsManagementException:
|
||||
return False
|
||||
|
||||
|
||||
class RoomCapabilityPermission(permissions.BasePermission):
|
||||
"""Wip."""
|
||||
|
||||
capability = None
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""Wip."""
|
||||
user = request.user
|
||||
|
||||
if not user or not user.is_authenticated:
|
||||
return False
|
||||
|
||||
if obj.is_administrator_or_owner(user):
|
||||
return True
|
||||
|
||||
if not obj.configuration.get(self.capability, True):
|
||||
return False
|
||||
|
||||
try:
|
||||
return ParticipantsManagement().check_if_in_meeting(
|
||||
room_name=str(obj.pk), identity=str(user.sub)
|
||||
)
|
||||
except ParticipantNotFoundException:
|
||||
return False
|
||||
except ParticipantsManagementException:
|
||||
return False
|
||||
|
||||
|
||||
class CanRecord(RoomCapabilityPermission):
|
||||
"""Wip."""
|
||||
|
||||
capability = "authenticated_can_record"
|
||||
|
||||
@@ -330,7 +330,6 @@ class RoomConfiguration(BaseModel):
|
||||
|
||||
can_publish_sources: list[TrackSource] | None = None
|
||||
everyone_can_mute: bool | None = None
|
||||
authenticated_can_record: bool | None = None
|
||||
|
||||
model_config = {"extra": "forbid"}
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ class RoomViewSet(
|
||||
methods=["post"],
|
||||
url_path="start-recording",
|
||||
permission_classes=[
|
||||
permissions.CanRecord,
|
||||
permissions.HasPrivilegesOnRoom,
|
||||
],
|
||||
)
|
||||
@FeatureFlag.require("recording")
|
||||
@@ -394,30 +394,11 @@ class RoomViewSet(
|
||||
mode=mode,
|
||||
options=options.model_dump(exclude_none=True) if options else {},
|
||||
)
|
||||
|
||||
if room.is_administrator_or_owner(request.user):
|
||||
models.RecordingAccess.objects.create(
|
||||
user=self.request.user,
|
||||
role=models.RoleChoices.OWNER,
|
||||
recording=recording,
|
||||
)
|
||||
else:
|
||||
# todo - encapsulate it in a clear method which replicate privileges role on obj
|
||||
accesses = models.ResourceAccess.objects.filter(
|
||||
resource=room,
|
||||
role__in=[models.RoleChoices.OWNER, models.RoleChoices.ADMIN],
|
||||
).values_list("user_id", "role")
|
||||
|
||||
models.RecordingAccess.objects.bulk_create(
|
||||
[
|
||||
models.RecordingAccess(
|
||||
user_id=user_id,
|
||||
role=role,
|
||||
recording=recording,
|
||||
)
|
||||
for user_id, role in accesses
|
||||
]
|
||||
)
|
||||
models.RecordingAccess.objects.create(
|
||||
user=self.request.user,
|
||||
role=models.RoleChoices.OWNER,
|
||||
recording=recording,
|
||||
)
|
||||
|
||||
except (DjangoValidationError, IntegrityError):
|
||||
# DjangoValidationError covers the Python-level check (full_clean);
|
||||
@@ -461,7 +442,7 @@ class RoomViewSet(
|
||||
methods=["post"],
|
||||
url_path="stop-recording",
|
||||
permission_classes=[
|
||||
permissions.CanRecord,
|
||||
permissions.HasPrivilegesOnRoom,
|
||||
],
|
||||
)
|
||||
@FeatureFlag.require("recording")
|
||||
|
||||
@@ -59,9 +59,10 @@ export const Avatar = React.memo(
|
||||
<text
|
||||
x="50"
|
||||
y="50"
|
||||
dy="-0.08em"
|
||||
textAnchor="middle"
|
||||
dominantBaseline="central"
|
||||
fontSize={initials.length > 1 ? 48 : 52}
|
||||
fontSize="52"
|
||||
fontWeight="500"
|
||||
fill="currentColor"
|
||||
>
|
||||
|
||||
@@ -98,7 +98,6 @@ export const NoAccessView = ({
|
||||
)}
|
||||
</Text>
|
||||
</VStack>
|
||||
{/*todo - update the message here to adapt to room configuration */}
|
||||
{!isLoggedIn && (
|
||||
<LoginPrompt
|
||||
heading={t(`${i18nKey}.login.heading`)}
|
||||
|
||||
@@ -29,7 +29,6 @@ import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||
import { FeatureFlags } from '@/features/analytics/enums'
|
||||
import { LimitDescription } from './LimitDescription'
|
||||
import { useCanRecord } from '@/features/recording/hooks/useCanRecord'
|
||||
|
||||
export const ScreenRecordingSidePanel = () => {
|
||||
const { data } = useConfig()
|
||||
@@ -39,7 +38,6 @@ export const ScreenRecordingSidePanel = () => {
|
||||
|
||||
const [includeTranscript, setIncludeTranscript] = useState(false)
|
||||
|
||||
const canRecord = useCanRecord()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
|
||||
const hasScreenRecordingAccess = useHasRecordingAccess(
|
||||
@@ -112,7 +110,7 @@ export const ScreenRecordingSidePanel = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!canRecord) {
|
||||
if (!isAdminOrOwner) {
|
||||
return (
|
||||
<NoAccessView
|
||||
i18nKeyPrefix={keyPrefix}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useRoomContext } from '@livekit/components-react'
|
||||
import {
|
||||
RecordingMode,
|
||||
useHasRecordingAccess,
|
||||
useHasFeatureWithoutRecordingRights,
|
||||
useHasFeatureWithoutAdminRights,
|
||||
useRecordingStatuses,
|
||||
} from '../index'
|
||||
import { useState } from 'react'
|
||||
@@ -53,7 +53,7 @@ export const TranscriptSidePanel = () => {
|
||||
FeatureFlags.Transcript
|
||||
)
|
||||
|
||||
const hasFeatureWithoutAdminRights = useHasFeatureWithoutRecordingRights(
|
||||
const hasFeatureWithoutAdminRights = useHasFeatureWithoutAdminRights(
|
||||
RecordingMode.Transcript,
|
||||
FeatureFlags.Transcript
|
||||
)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||
import { useUser } from '@/features/auth/api/useUser'
|
||||
|
||||
export const useCanRecord = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
const { isLoggedIn } = useUser()
|
||||
|
||||
return (
|
||||
isAdminOrOwner ||
|
||||
(!!isLoggedIn &&
|
||||
apiRoomData?.configuration?.authenticated_can_record !== false)
|
||||
)
|
||||
}
|
||||
+4
-4
@@ -2,21 +2,21 @@ import { useFeatureFlagEnabled } from 'posthog-js/react'
|
||||
import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled'
|
||||
import type { RecordingMode } from '../types'
|
||||
import { useIsRecordingModeEnabled } from './useIsRecordingModeEnabled'
|
||||
import { useCanRecord } from './useCanRecord'
|
||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||
import type { FeatureFlags } from '@/features/analytics/enums'
|
||||
|
||||
export const useHasFeatureWithoutRecordingRights = (
|
||||
export const useHasFeatureWithoutAdminRights = (
|
||||
mode: RecordingMode,
|
||||
featureFlag: FeatureFlags
|
||||
) => {
|
||||
const featureEnabled = useFeatureFlagEnabled(featureFlag)
|
||||
const isAnalyticsEnabled = useIsAnalyticsEnabled()
|
||||
const isRecordingModeEnabled = useIsRecordingModeEnabled(mode)
|
||||
const canRecord = useCanRecord()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
|
||||
return (
|
||||
(featureEnabled || !isAnalyticsEnabled) &&
|
||||
isRecordingModeEnabled &&
|
||||
!canRecord
|
||||
!isAdminOrOwner
|
||||
)
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import { useFeatureFlagEnabled } from 'posthog-js/react'
|
||||
import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled'
|
||||
import type { RecordingMode } from '../types'
|
||||
import { useIsRecordingModeEnabled } from './useIsRecordingModeEnabled'
|
||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||
import type { FeatureFlags } from '@/features/analytics/enums'
|
||||
import { useCanRecord } from './useCanRecord'
|
||||
|
||||
export const useHasRecordingAccess = (
|
||||
mode: RecordingMode,
|
||||
@@ -12,11 +12,11 @@ export const useHasRecordingAccess = (
|
||||
const featureEnabled = useFeatureFlagEnabled(featureFlag)
|
||||
const isAnalyticsEnabled = useIsAnalyticsEnabled()
|
||||
const isRecordingModeEnabled = useIsRecordingModeEnabled(mode)
|
||||
const canRecord = useCanRecord()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
|
||||
return (
|
||||
(featureEnabled || !isAnalyticsEnabled) &&
|
||||
canRecord &&
|
||||
isAdminOrOwner &&
|
||||
isRecordingModeEnabled
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// hooks
|
||||
export { useIsRecordingModeEnabled } from './hooks/useIsRecordingModeEnabled'
|
||||
export { useHasRecordingAccess } from './hooks/useHasRecordingAccess'
|
||||
export { useHasFeatureWithoutRecordingRights } from './hooks/useHasFeatureWithoutRecordingRights.ts'
|
||||
export { useHasFeatureWithoutAdminRights } from './hooks/useHasFeatureWithoutAdminRights'
|
||||
export { useRecordingStatuses } from './hooks/useRecordingStatuses'
|
||||
|
||||
// api
|
||||
|
||||
@@ -16,7 +16,6 @@ export enum ApiAccessLevel {
|
||||
export type RoomConfiguration = {
|
||||
can_publish_sources?: Source[] | null
|
||||
everyone_can_mute?: boolean | null
|
||||
authenticated_can_record?: boolean | null
|
||||
}
|
||||
|
||||
export type ApiRoom = {
|
||||
|
||||
@@ -50,12 +50,7 @@ export const Admin = () => {
|
||||
isScreenShareEnabled,
|
||||
} = usePublishSourcesManager()
|
||||
|
||||
const {
|
||||
toggleMuting,
|
||||
isMutingEnabled,
|
||||
isAuthenticatedCanRecordEnabled,
|
||||
toggleAuthenticatedCanRecord,
|
||||
} = usePermissionsManager()
|
||||
const { toggleMuting, isMutingEnabled } = usePermissionsManager()
|
||||
|
||||
return (
|
||||
<Div
|
||||
@@ -160,17 +155,6 @@ export const Admin = () => {
|
||||
fullWidth: true,
|
||||
}}
|
||||
/>
|
||||
<Field
|
||||
type="switch"
|
||||
label={'Authenticated can record'}
|
||||
description={'Authenticated can record'}
|
||||
isSelected={isAuthenticatedCanRecordEnabled}
|
||||
onChange={toggleAuthenticatedCanRecord}
|
||||
wrapperProps={{
|
||||
noMargin: true,
|
||||
fullWidth: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -12,8 +12,6 @@ export const usePermissionsManager = () => {
|
||||
const roomId = data?.slug
|
||||
|
||||
const isMutingEnabled = configuration?.everyone_can_mute ?? true
|
||||
const isAuthenticatedCanRecordEnabled =
|
||||
configuration?.authenticated_can_record ?? true
|
||||
|
||||
const toggleMuting = useCallback(
|
||||
async (enabled: boolean) => {
|
||||
@@ -41,36 +39,8 @@ export const usePermissionsManager = () => {
|
||||
[configuration, roomId, patchRoom]
|
||||
)
|
||||
|
||||
const toggleAuthenticatedCanRecord = useCallback(
|
||||
async (enabled: boolean) => {
|
||||
if (!roomId) return
|
||||
|
||||
try {
|
||||
const newConfiguration = {
|
||||
...configuration,
|
||||
authenticated_can_record: enabled,
|
||||
}
|
||||
|
||||
const room = await patchRoom({
|
||||
roomId,
|
||||
room: { configuration: newConfiguration },
|
||||
})
|
||||
|
||||
queryClient.setQueryData([keys.room, roomId], room)
|
||||
|
||||
return { configuration: newConfiguration }
|
||||
} catch (error) {
|
||||
console.error('Failed to update recording permission:', error)
|
||||
return { success: false, error }
|
||||
}
|
||||
},
|
||||
[configuration, roomId, patchRoom]
|
||||
)
|
||||
|
||||
return {
|
||||
toggleMuting,
|
||||
isMutingEnabled,
|
||||
isAuthenticatedCanRecordEnabled,
|
||||
toggleAuthenticatedCanRecord,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user