Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b29e04d635 | |||
| 9ff6177004 |
@@ -136,3 +136,35 @@ class FilePermission(IsAuthenticated):
|
||||
raise Http404
|
||||
|
||||
return obj.get_abilities(request.user).get(view.action, False)
|
||||
|
||||
|
||||
class CanMuteParticipant(permissions.BasePermission):
|
||||
"""
|
||||
Grant muting rights based on role or room configuration.
|
||||
|
||||
Allows muting unconditionally for admins/owners. For other users, requires
|
||||
both the room's ``everyone_can_mute`` option to be enabled and a valid
|
||||
authentication (session/JWT or a LiveKit token matching the room ID).
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""Check if the requesting user is allowed to mute a participant in the given room."""
|
||||
|
||||
# Always allow admins/owners
|
||||
if obj.is_administrator_or_owner(request.user):
|
||||
return True
|
||||
|
||||
everyone_can_mute = obj.configuration.get("everyone_can_mute", True)
|
||||
|
||||
if not everyone_can_mute:
|
||||
return False
|
||||
|
||||
# Standard backend auth (e.g. session/JWT) — no LiveKit token needed
|
||||
if request.user and request.user.is_authenticated:
|
||||
return True
|
||||
|
||||
# LiveKit token auth
|
||||
if request.auth and hasattr(request.auth, "video"):
|
||||
return request.auth.video.room == str(obj.id)
|
||||
|
||||
return False
|
||||
|
||||
@@ -30,6 +30,7 @@ from rest_framework import (
|
||||
from rest_framework import (
|
||||
status as drf_status,
|
||||
)
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
from core import enums, models, utils
|
||||
from core.api.filters import ListFileFilter
|
||||
@@ -583,7 +584,12 @@ class RoomViewSet(
|
||||
methods=["post"],
|
||||
url_path="mute-participant",
|
||||
url_name="mute-participant",
|
||||
permission_classes=[permissions.HasPrivilegesOnRoom],
|
||||
permission_classes=[permissions.CanMuteParticipant],
|
||||
# Accept both session auth (privileged users) and LiveKit token auth (participants)
|
||||
authentication_classes=[
|
||||
*api_settings.DEFAULT_AUTHENTICATION_CLASSES,
|
||||
LiveKitTokenAuthentication,
|
||||
],
|
||||
)
|
||||
def mute_participant(self, request, pk=None): # pylint: disable=unused-argument
|
||||
"""Mute a specific track for a participant in the room."""
|
||||
|
||||
@@ -7,13 +7,13 @@ import {
|
||||
} from '@/features/notifications'
|
||||
import { fetchApi } from '@/api/fetchApi'
|
||||
|
||||
export const useMuteParticipant = () => {
|
||||
const data = useRoomData()
|
||||
|
||||
export const useMuteParticipant = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
const { notifyParticipants } = useNotifyParticipants()
|
||||
|
||||
const muteParticipant = async (participant: Participant) => {
|
||||
if (!data?.id) {
|
||||
if (!apiRoomData?.livekit?.room) {
|
||||
throw new Error('Room id is not available')
|
||||
}
|
||||
const trackSid = participant.getTrackPublication(
|
||||
@@ -25,24 +25,31 @@ export const useMuteParticipant = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetchApi(`rooms/${data.id}/mute-participant/`, {
|
||||
const response = fetchApi(`rooms/${apiRoomData?.livekit?.room}/mute-participant/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
token: apiRoomData?.livekit?.token,
|
||||
participant_identity: participant.identity,
|
||||
track_sid: trackSid,
|
||||
}),
|
||||
})
|
||||
|
||||
await notifyParticipants({
|
||||
type: NotificationType.ParticipantMuted,
|
||||
destinationIdentities: [participant.identity],
|
||||
})
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Failed to mute participant ${participant.identity}: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await notifyParticipants({
|
||||
type: NotificationType.ParticipantMuted,
|
||||
destinationIdentities: [participant.identity],
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to notify muted participant ${participant.identity}: ${e}`
|
||||
)
|
||||
}
|
||||
}
|
||||
return { muteParticipant }
|
||||
|
||||
Reference in New Issue
Block a user