diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py
index 77a9b278..bd40c632 100644
--- a/src/backend/core/api/serializers.py
+++ b/src/backend/core/api/serializers.py
@@ -329,6 +329,7 @@ class RoomConfiguration(BaseModel):
"""
can_publish_sources: list[RoomConfigurationTrackSource] | None = None
+ everyone_can_mute: bool | None = None
model_config = {"extra": "forbid"}
diff --git a/src/backend/core/tests/rooms/test_api_rooms_update.py b/src/backend/core/tests/rooms/test_api_rooms_update.py
index 258be673..f9f86eec 100644
--- a/src/backend/core/tests/rooms/test_api_rooms_update.py
+++ b/src/backend/core/tests/rooms/test_api_rooms_update.py
@@ -122,6 +122,10 @@ def test_api_rooms_update_administrators():
},
{"can_publish_sources": []},
{"can_publish_sources": None},
+ {"can_publish_sources": None, "everyone_can_mute": True},
+ {"can_publish_sources": None, "everyone_can_mute": False},
+ {"can_publish_sources": None, "everyone_can_mute": "yes"},
+ {"can_publish_sources": None, "everyone_can_mute": "1"},
],
)
def test_api_rooms_update_configuration_valid(configuration):
@@ -198,6 +202,24 @@ def test_api_rooms_update_configuration_wrong_type():
assert room.configuration == {}
+@pytest.mark.parametrize("invalid_value", ["test", [], {}])
+def test_api_rooms_update_configuration_everyone_can_mute_wrong_type(invalid_value):
+ """everyone_can_mute values with wrong types should be rejected."""
+ user = UserFactory()
+ room = RoomFactory(users=[(user, "owner")])
+ client = APIClient()
+ client.force_login(user)
+
+ response = client.patch(
+ f"/api/v1.0/rooms/{room.id!s}/",
+ {"configuration": {"everyone_can_mute": invalid_value}},
+ format="json",
+ )
+ assert response.status_code == 400
+ room.refresh_from_db()
+ assert room.configuration == {}
+
+
def test_api_rooms_update_administrators_of_another():
"""
Being administrator or owner of a room should not grant authorization to update
diff --git a/src/frontend/src/features/rooms/livekit/components/Admin.tsx b/src/frontend/src/features/rooms/livekit/components/Admin.tsx
index efe1090a..1ebbacda 100644
--- a/src/frontend/src/features/rooms/livekit/components/Admin.tsx
+++ b/src/frontend/src/features/rooms/livekit/components/Admin.tsx
@@ -9,7 +9,8 @@ import { queryClient } from '@/api/queryClient'
import { keys } from '@/api/queryKeys'
import { useQuery } from '@tanstack/react-query'
import { useParams } from 'wouter'
-import { usePublishSourcesManager } from '@/features/rooms/livekit/hooks/usePublishSourcesManager'
+import { usePublishSourcesManager } from '../hooks/usePublishSourcesManager'
+import { usePermissionsManager } from '../hooks/usePermissionsManager'
export const Admin = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'admin' })
@@ -38,6 +39,8 @@ export const Admin = () => {
isScreenShareEnabled,
} = usePublishSourcesManager()
+ const { toggleMuting, isMutingEnabled } = usePermissionsManager()
+
return (
{
fullWidth: true,
}}
/>
+
{
+ const { mutateAsync: patchRoom } = usePatchRoom()
+
+ const data = useRoomData()
+ const configuration = data?.configuration
+ const roomId = data?.slug
+
+ const isMutingEnabled = configuration?.everyone_can_mute ?? true
+
+ const toggleMuting = useCallback(
+ async (enabled: boolean) => {
+ if (!roomId) return
+
+ try {
+ const newConfiguration = {
+ ...configuration,
+ everyone_can_mute: 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 muting permission:', error)
+ return { success: false, error }
+ }
+ },
+ [configuration, roomId, patchRoom]
+ )
+
+ return {
+ toggleMuting,
+ isMutingEnabled,
+ }
+}
diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json
index 2582c353..f9c81637 100644
--- a/src/frontend/src/locales/de/rooms.json
+++ b/src/frontend/src/locales/de/rooms.json
@@ -528,6 +528,10 @@
"screenshare": {
"label": "Bildschirm teilen",
"description": "Wenn du diese Option deaktivierst, können Teilnehmende ihren Bildschirm nicht mehr teilen. Laufende Bildschirmfreigaben werden sofort beendet."
+ },
+ "mute": {
+ "label": "Andere stummschalten",
+ "description": "Wenn deaktiviert, können Teilnehmer andere Teilnehmer nicht mehr stummschalten."
}
}
},
diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json
index c09beded..af3b1947 100644
--- a/src/frontend/src/locales/en/rooms.json
+++ b/src/frontend/src/locales/en/rooms.json
@@ -527,6 +527,10 @@
"screenshare": {
"label": "Share their screen",
"description": "Disabling this option will prevent participants from sharing their screen, and any ongoing screen sharing will be stopped immediately."
+ },
+ "mute": {
+ "label": "Mute others",
+ "description": "When disabled, participants will no longer be able to mute other participants."
}
}
},
diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json
index d0a64e42..5421a207 100644
--- a/src/frontend/src/locales/fr/rooms.json
+++ b/src/frontend/src/locales/fr/rooms.json
@@ -527,6 +527,10 @@
"screenshare": {
"label": "Partager leur écran",
"description": "En désactivant cette option, les participants ne pourront plus partager leur écran et tout partage en cours sera immédiatement interrompu."
+ },
+ "mute": {
+ "label": "Muter les autres",
+ "description": "En désactivant cette option, les participants ne pourront plus muter d'autres participants."
}
}
},
diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json
index 57896e25..3579b2ab 100644
--- a/src/frontend/src/locales/nl/rooms.json
+++ b/src/frontend/src/locales/nl/rooms.json
@@ -527,6 +527,10 @@
"screenshare": {
"label": "Hun scherm delen",
"description": "Als u deze optie uitschakelt, kunnen deelnemers hun scherm niet meer delen en wordt elke lopende schermdeling onmiddellijk gestopt."
+ },
+ "mute": {
+ "label": "Anderen dempen",
+ "description": "Wanneer uitgeschakeld, kunnen deelnemers andere deelnemers niet meer dempen."
}
}
},