diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js
index 1efcab2..4edc5c3 100644
--- a/app/src/RoomClient.js
+++ b/app/src/RoomClient.js
@@ -1126,6 +1126,66 @@ export default class RoomClient
lobbyPeerActions.setLobbyPeerPromotionInProgress(peerId, false));
}
+ async kickPeer(peerId)
+ {
+ logger.debug('kickPeer() [peerId:"%s"]', peerId);
+
+ store.dispatch(
+ peerActions.setPeerKickInProgress(peerId, true));
+
+ try
+ {
+ await this.sendRequest('moderator:kickPeer', { peerId });
+ }
+ catch (error)
+ {
+ logger.error('kickPeer() failed: %o', error);
+ }
+
+ store.dispatch(
+ peerActions.setPeerKickInProgress(peerId, false));
+ }
+
+ async muteAllPeers()
+ {
+ logger.debug('muteAllPeers()');
+
+ store.dispatch(
+ roomActions.setMuteAllInProgress(true));
+
+ try
+ {
+ await this.sendRequest('moderator:muteAll');
+ }
+ catch (error)
+ {
+ logger.error('muteAllPeers() failed: %o', error);
+ }
+
+ store.dispatch(
+ roomActions.setMuteAllInProgress(false));
+ }
+
+ async stopAllPeerVideo()
+ {
+ logger.debug('stopAllPeerVideo()');
+
+ store.dispatch(
+ roomActions.setStopAllVideoInProgress(true));
+
+ try
+ {
+ await this.sendRequest('moderator:stopAllVideo');
+ }
+ catch (error)
+ {
+ logger.error('stopAllPeerVideo() failed: %o', error);
+ }
+
+ store.dispatch(
+ roomActions.setStopAllVideoInProgress(false));
+ }
+
// type: mic/webcam/screen
// mute: true/false
async modifyPeerConsumer(peerId, type, mute)
@@ -1902,10 +1962,10 @@ export default class RoomClient
case 'newPeer':
{
- const { id, displayName, picture } = notification.data;
+ const { id, displayName, picture, roles } = notification.data;
store.dispatch(
- peerActions.addPeer({ id, displayName, picture, consumers: [] }));
+ peerActions.addPeer({ id, displayName, picture, roles, consumers: [] }));
store.dispatch(requestActions.notify(
{
@@ -2004,6 +2064,96 @@ export default class RoomClient
break;
}
+
+ case 'moderator:mute':
+ {
+ // const { peerId } = notification.data;
+
+ if (this._micProducer && !this._micProducer.paused)
+ {
+ this.muteMic();
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'moderator.mute',
+ defaultMessage : 'Moderator muted your microphone'
+ })
+ }));
+ }
+
+ break;
+ }
+
+ case 'moderator:stopVideo':
+ {
+ // const { peerId } = notification.data;
+
+ this.disableWebcam();
+ this.disableScreenSharing();
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'moderator.mute',
+ defaultMessage : 'Moderator stopped your video'
+ })
+ }));
+
+ break;
+ }
+
+ case 'moderator:kick':
+ {
+ // Need some feedback
+ this.close();
+
+ break;
+ }
+
+ case 'gotRole':
+ {
+ const { peerId, role } = notification.data;
+
+ if (peerId === this._peerId)
+ {
+ store.dispatch(meActions.addRole({ role }));
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'roles.gotRole',
+ defaultMessage : `You got the role: ${role}`
+ })
+ }));
+ }
+ else
+ store.dispatch(peerActions.addPeerRole({ peerId, role }));
+
+ break;
+ }
+
+ case 'lostRole':
+ {
+ const { peerId, role } = notification.data;
+
+ if (peerId === this._peerId)
+ {
+ store.dispatch(meActions.removeRole({ role }));
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'roles.lostRole',
+ defaultMessage : `You lost the role: ${role}`
+ })
+ }));
+ }
+ else
+ store.dispatch(peerActions.removePeerRole({ peerId, role }));
+
+ break;
+ }
default:
{
@@ -2158,7 +2308,7 @@ export default class RoomClient
canShareFiles : this._torrentSupport
}));
- const { peers } = await this.sendRequest(
+ const { roles, peers } = await this.sendRequest(
'join',
{
displayName : displayName,
@@ -2166,7 +2316,25 @@ export default class RoomClient
rtpCapabilities : this._mediasoupDevice.rtpCapabilities
});
- logger.debug('_joinRoom() joined, got peers [peers:"%o"]', peers);
+ logger.debug('_joinRoom() joined [peers:"%o", roles:"%o"]', peers, roles);
+
+ const myRoles = store.getState().me.roles;
+
+ for (const role of roles)
+ {
+ if (!myRoles.includes(role))
+ {
+ store.dispatch(meActions.addRole({ role }));
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'roles.gotRole',
+ defaultMessage : `You got the role: ${role}`
+ })
+ }));
+ }
+ }
for (const peer of peers)
{
diff --git a/app/src/actions/meActions.js b/app/src/actions/meActions.js
index b704880..bdff144 100644
--- a/app/src/actions/meActions.js
+++ b/app/src/actions/meActions.js
@@ -10,6 +10,18 @@ export const loggedIn = (flag) =>
payload : { flag }
});
+export const addRole = ({ role }) =>
+ ({
+ type : 'ADD_ROLE',
+ payload : { role }
+ });
+
+export const removeRole = (role) =>
+ ({
+ type : 'REMOVE_ROLE',
+ payload : { role }
+ });
+
export const setPicture = (picture) =>
({
type : 'SET_PICTURE',
diff --git a/app/src/actions/peerActions.js b/app/src/actions/peerActions.js
index 4caca32..1a87151 100644
--- a/app/src/actions/peerActions.js
+++ b/app/src/actions/peerActions.js
@@ -45,3 +45,22 @@ export const setPeerPicture = (peerId, picture) =>
type : 'SET_PEER_PICTURE',
payload : { peerId, picture }
});
+
+
+export const addPeerRole = (peerId, role) =>
+ ({
+ type : 'ADD_PEER_ROLE',
+ payload : { peerId, role }
+ });
+
+export const removePeerRole = (peerId, role) =>
+ ({
+ type : 'REMOVE_PEER_ROLE',
+ payload : { peerId, role }
+ });
+
+export const setPeerKickInProgress = (peerId, flag) =>
+ ({
+ type : 'SET_PEER_KICK_IN_PROGRESS',
+ payload : { peerId, flag }
+ });
diff --git a/app/src/actions/roomActions.js b/app/src/actions/roomActions.js
index 560c77d..9ad1e08 100644
--- a/app/src/actions/roomActions.js
+++ b/app/src/actions/roomActions.js
@@ -109,4 +109,16 @@ export const toggleConsumerFullscreen = (consumerId) =>
({
type : 'TOGGLE_FULLSCREEN_CONSUMER',
payload : { consumerId }
+ });
+
+export const setMuteAllInProgress = (flag) =>
+ ({
+ type : 'MUTE_ALL_IN_PROGRESS',
+ payload : { flag }
+ });
+
+export const setStopAllVideoInProgress = (flag) =>
+ ({
+ type : 'STOP_ALL_VIDEO_IN_PROGRESS',
+ payload : { flag }
});
\ No newline at end of file
diff --git a/app/src/components/MeetingDrawer/ParticipantList/ListModerator.js b/app/src/components/MeetingDrawer/ParticipantList/ListModerator.js
new file mode 100644
index 0000000..66f64bd
--- /dev/null
+++ b/app/src/components/MeetingDrawer/ParticipantList/ListModerator.js
@@ -0,0 +1,101 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { withStyles } from '@material-ui/core/styles';
+import PropTypes from 'prop-types';
+import { withRoomContext } from '../../../RoomContext';
+import { useIntl, FormattedMessage } from 'react-intl';
+import Button from '@material-ui/core/Button';
+
+const styles = (theme) =>
+ ({
+ root :
+ {
+ padding : theme.spacing(1),
+ width : '100%',
+ overflow : 'hidden',
+ cursor : 'auto',
+ display : 'flex'
+ },
+ actionButtons :
+ {
+ display : 'flex'
+ },
+ divider :
+ {
+ marginLeft : theme.spacing(2)
+ }
+ });
+
+const ListModerator = (props) =>
+{
+ const intl = useIntl();
+
+ const {
+ roomClient,
+ room,
+ classes
+ } = props;
+
+ return (
+
+
+
+
+
+ );
+};
+
+ListModerator.propTypes =
+{
+ roomClient : PropTypes.any.isRequired,
+ room : PropTypes.object.isRequired,
+ classes : PropTypes.object.isRequired
+};
+
+const mapStateToProps = (state) => ({
+ room : state.room
+});
+
+export default withRoomContext(connect(
+ mapStateToProps,
+ null,
+ null,
+ {
+ areStatesEqual : (next, prev) =>
+ {
+ return (
+ prev.room === next.room
+ );
+ }
+ }
+)(withStyles(styles)(ListModerator)));
\ No newline at end of file
diff --git a/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js b/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
index 9f74e65..26a8ab3 100644
--- a/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
+++ b/app/src/components/MeetingDrawer/ParticipantList/ListPeer.js
@@ -12,6 +12,7 @@ import MicIcon from '@material-ui/icons/Mic';
import MicOffIcon from '@material-ui/icons/MicOff';
import ScreenIcon from '@material-ui/icons/ScreenShare';
import ScreenOffIcon from '@material-ui/icons/StopScreenShare';
+import ExitIcon from '@material-ui/icons/ExitToApp';
import EmptyAvatar from '../../../images/avatar-empty.jpeg';
import HandIcon from '../../../images/icon-hand-white.svg';
@@ -91,40 +92,6 @@ const styles = (theme) =>
flexDirection : 'row',
justifyContent : 'flex-start',
alignItems : 'center'
- },
- button :
- {
- flex : '0 0 auto',
- margin : '0.3rem',
- borderRadius : 2,
- backgroundColor : 'rgba(0, 0, 0, 0.5)',
- cursor : 'pointer',
- transitionProperty : 'opacity, background-color',
- transitionDuration : '0.15s',
- width : 'var(--media-control-button-size)',
- height : 'var(--media-control-button-size)',
- opacity : 0.85,
- '&:hover' :
- {
- opacity : 1
- },
- '&.unsupported' :
- {
- pointerEvents : 'none'
- },
- '&.disabled' :
- {
- pointerEvents : 'none',
- backgroundColor : 'var(--media-control-botton-disabled)'
- },
- '&.on' :
- {
- backgroundColor : 'var(--media-control-botton-on)'
- },
- '&.off' :
- {
- backgroundColor : 'var(--media-control-botton-off)'
- }
}
});
@@ -134,6 +101,7 @@ const ListPeer = (props) =>
const {
roomClient,
+ isModerator,
peer,
micConsumer,
screenConsumer,
@@ -185,9 +153,8 @@ const ListPeer = (props) =>
})}
color={ screenVisible ? 'primary' : 'secondary'}
disabled={ peer.peerScreenInProgress }
- onClick={(e) =>
+ onClick={() =>
{
- e.stopPropagation();
screenVisible ?
roomClient.modifyPeerConsumer(peer.id, 'screen', true) :
roomClient.modifyPeerConsumer(peer.id, 'screen', false);
@@ -207,9 +174,8 @@ const ListPeer = (props) =>
})}
color={ micEnabled ? 'primary' : 'secondary'}
disabled={ peer.peerAudioInProgress }
- onClick={(e) =>
+ onClick={() =>
{
- e.stopPropagation();
micEnabled ?
roomClient.modifyPeerConsumer(peer.id, 'mic', true) :
roomClient.modifyPeerConsumer(peer.id, 'mic', false);
@@ -221,6 +187,21 @@ const ListPeer = (props) =>
}
+ { isModerator &&
+
+ {
+ roomClient.kickPeer(peer.id);
+ }}
+ >
+
+
+ }
);
@@ -230,6 +211,7 @@ ListPeer.propTypes =
{
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
+ isModerator : PropTypes.bool,
peer : appPropTypes.Peer.isRequired,
micConsumer : appPropTypes.Consumer,
webcamConsumer : appPropTypes.Consumer,
diff --git a/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js b/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
index 3313d2b..01dbf9d 100644
--- a/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
+++ b/app/src/components/MeetingDrawer/ParticipantList/ParticipantList.js
@@ -11,7 +11,9 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import ListPeer from './ListPeer';
import ListMe from './ListMe';
+import ListModerator from './ListModerator';
import Volume from '../../Containers/Volume';
+import * as userRoles from '../../../reducers/userRoles';
const styles = (theme) =>
({
@@ -76,6 +78,7 @@ class ParticipantList extends React.PureComponent
const {
roomClient,
advancedMode,
+ isModerator,
passivePeers,
selectedPeerId,
spotlightPeers,
@@ -84,6 +87,17 @@ class ParticipantList extends React.PureComponent
return (
{ this.node = node; }}>
+ { isModerator &&
+
+ }
-
roomClient.setSelectedPeer(peerId)}
>
-
+
@@ -129,7 +143,7 @@ class ParticipantList extends React.PureComponent
})}
onClick={() => roomClient.setSelectedPeer(peerId)}
>
-
+
))}
@@ -142,6 +156,7 @@ ParticipantList.propTypes =
{
roomClient : PropTypes.any.isRequired,
advancedMode : PropTypes.bool,
+ isModerator : PropTypes.bool,
passivePeers : PropTypes.array,
selectedPeerId : PropTypes.string,
spotlightPeers : PropTypes.array,
@@ -150,7 +165,12 @@ ParticipantList.propTypes =
const mapStateToProps = (state) =>
{
+ const isModerator =
+ state.me.roles.includes(userRoles.MODERATOR) ||
+ state.me.roles.includes(userRoles.ADMIN);
+
return {
+ isModerator,
passivePeers : passivePeersSelector(state),
selectedPeerId : state.room.selectedPeerId,
spotlightPeers : spotlightPeersSelector(state)
@@ -165,6 +185,7 @@ const ParticipantListContainer = withRoomContext(connect(
areStatesEqual : (next, prev) =>
{
return (
+ prev.me.roles === next.me.roles &&
prev.peers === next.peers &&
prev.room.spotlights === next.room.spotlights &&
prev.room.selectedPeerId === next.room.selectedPeerId
diff --git a/app/src/reducers/me.js b/app/src/reducers/me.js
index e80375a..4bad22f 100644
--- a/app/src/reducers/me.js
+++ b/app/src/reducers/me.js
@@ -1,7 +1,10 @@
+import * as userRoles from './userRoles';
+
const initialState =
{
id : null,
picture : null,
+ roles : [ userRoles.ALL ],
canSendMic : false,
canSendWebcam : false,
canShareScreen : false,
@@ -43,6 +46,21 @@ const me = (state = initialState, action) =>
return { ...state, loggedIn: flag };
}
+ case 'ADD_ROLE':
+ {
+ const roles = [ ...state.roles, action.payload.role ];
+
+ return { ...state, roles };
+ }
+
+ case 'REMOVE_ROLE':
+ {
+ const roles = state.roles.filter((role) =>
+ role !== action.payload.role);
+
+ return { ...state, roles };
+ }
+
case 'SET_PICTURE':
return { ...state, picture: action.payload.picture };
diff --git a/app/src/reducers/peers.js b/app/src/reducers/peers.js
index ddd104f..e3d207d 100644
--- a/app/src/reducers/peers.js
+++ b/app/src/reducers/peers.js
@@ -16,6 +16,9 @@ const peer = (state = {}, action) =>
case 'SET_PEER_SCREEN_IN_PROGRESS':
return { ...state, peerScreenInProgress: action.payload.flag };
+
+ case 'SET_PEER_KICK_IN_PROGRESS':
+ return { ...state, peerKickInProgress: action.payload.flag };
case 'SET_PEER_RAISE_HAND_STATE':
return { ...state, raiseHandState: action.payload.raiseHandState };
@@ -40,6 +43,21 @@ const peer = (state = {}, action) =>
return { ...state, picture: action.payload.picture };
}
+ case 'ADD_PEER_ROLE':
+ {
+ const roles = [ ...state.roles, action.payload.role ];
+
+ return { ...state, roles };
+ }
+
+ case 'REMOVE_PEER_ROLE':
+ {
+ const roles = state.roles.filter((role) =>
+ role !== action.payload.role);
+
+ return { ...state, roles };
+ }
+
default:
return state;
}
@@ -71,6 +89,8 @@ const peers = (state = {}, action) =>
case 'SET_PEER_RAISE_HAND_STATE':
case 'SET_PEER_PICTURE':
case 'ADD_CONSUMER':
+ case 'ADD_PEER_ROLE':
+ case 'REMOVE_PEER_ROLE':
{
const oldPeer = state[action.payload.peerId];
@@ -82,6 +102,7 @@ const peers = (state = {}, action) =>
return { ...state, [oldPeer.id]: peer(oldPeer, action) };
}
+ case 'SET_PEER_KICK_IN_PROGRESS':
case 'REMOVE_CONSUMER':
{
const oldPeer = state[action.payload.peerId];
diff --git a/app/src/reducers/room.js b/app/src/reducers/room.js
index c4b29fb..9d483b8 100644
--- a/app/src/reducers/room.js
+++ b/app/src/reducers/room.js
@@ -163,6 +163,12 @@ const room = (state = initialState, action) =>
return { ...state, spotlights };
}
+ case 'MUTE_ALL_IN_PROGRESS':
+ return { ...state, muteAllInProgress: action.payload.flag };
+
+ case 'STOP_ALL_VIDEO_IN_PROGRESS':
+ return { ...state, stopAllVideoInProgress: action.payload.flag };
+
default:
return state;
}
diff --git a/app/src/reducers/userRoles.js b/app/src/reducers/userRoles.js
new file mode 100644
index 0000000..217a760
--- /dev/null
+++ b/app/src/reducers/userRoles.js
@@ -0,0 +1,4 @@
+export const ADMIN = 'admin';
+export const MODERATOR = 'moderator';
+export const AUTHENTICATED = 'authenticated';
+export const ALL = 'normal';
\ No newline at end of file
diff --git a/server/lib/Lobby.js b/server/lib/Lobby.js
index 7372455..b5d9fb6 100644
--- a/server/lib/Lobby.js
+++ b/server/lib/Lobby.js
@@ -75,13 +75,13 @@ class Lobby extends EventEmitter
if (peer)
{
peer.socket.removeListener('request', peer.socketRequestHandler);
- peer.removeListener('rolesChange', peer.roleChangeHandler);
+ peer.removeListener('gotRole', peer.gotRoleHandler);
peer.removeListener('displayNameChanged', peer.displayNameChangeHandler);
peer.removeListener('pictureChanged', peer.pictureChangeHandler);
peer.removeListener('close', peer.closeHandler);
peer.socketRequestHandler = null;
- peer.roleChangeHandler = null;
+ peer.gotRoleHandler = null;
peer.displayNameChangeHandler = null;
peer.pictureChangeHandler = null;
peer.closeHandler = null;
@@ -116,7 +116,7 @@ class Lobby extends EventEmitter
});
};
- peer.roleChangeHandler = () =>
+ peer.gotRoleHandler = () =>
{
logger.info('parkPeer() | rolesChange [peer:"%s"]', peer.id);
@@ -156,7 +156,7 @@ class Lobby extends EventEmitter
this._peers.set(peer.id, peer);
- peer.on('rolesChange', peer.roleChangeHandler);
+ peer.on('gotRole', peer.gotRoleHandler);
peer.on('displayNameChanged', peer.displayNameChangeHandler);
peer.on('pictureChanged', peer.pictureChangeHandler);
diff --git a/server/lib/Peer.js b/server/lib/Peer.js
index 93ee9b8..2b63c87 100644
--- a/server/lib/Peer.js
+++ b/server/lib/Peer.js
@@ -224,7 +224,7 @@ class Peer extends EventEmitter
logger.info('addRole() | [newRole:"%s]"', newRole);
- this.emit('rolesChange', { newRole });
+ this.emit('gotRole', { newRole });
}
}
@@ -236,7 +236,7 @@ class Peer extends EventEmitter
logger.info('removeRole() | [oldRole:"%s]"', oldRole);
- this.emit('rolesChange', { oldRole });
+ this.emit('lostRole', { oldRole });
}
}
@@ -302,7 +302,8 @@ class Peer extends EventEmitter
{
id : this.id,
displayName : this.displayName,
- picture : this.picture
+ picture : this.picture,
+ roles : this.roles
};
return peerInfo;
diff --git a/server/lib/Room.js b/server/lib/Room.js
index 140d4ee..b397ae1 100644
--- a/server/lib/Room.js
+++ b/server/lib/Room.js
@@ -420,6 +420,32 @@ class Room extends EventEmitter
picture : peer.picture
}, true);
});
+
+ peer.on('gotRole', ({ newRole }) =>
+ {
+ // Ensure the Peer is joined.
+ if (!peer.joined)
+ return;
+
+ // Spread to others
+ this._notification(peer.socket, 'gotRole', {
+ peerId : peer.id,
+ role : newRole
+ }, true);
+ });
+
+ peer.on('lostRole', ({ oldRole }) =>
+ {
+ // Ensure the Peer is joined.
+ if (!peer.joined)
+ return;
+
+ // Spread to others
+ this._notification(peer.socket, 'lostRole', {
+ peerId : peer.id,
+ role : oldRole
+ }, true);
+ });
}
async _handleSocketRequest(peer, request, cb)
@@ -483,7 +509,10 @@ class Room extends EventEmitter
.filter((joinedPeer) => joinedPeer.id !== peer.id)
.map((joinedPeer) => (joinedPeer.peerInfo));
- cb(null, { peers: peerInfos });
+ cb(null, {
+ roles : peer.roles,
+ peers : peerInfos
+ });
// Mark the new Peer as joined.
peer.joined = true;
@@ -511,7 +540,8 @@ class Room extends EventEmitter
{
id : peer.id,
displayName : displayName,
- picture : picture
+ picture : picture,
+ roles : peer.roles
}
);
}
@@ -1077,6 +1107,69 @@ class Room extends EventEmitter
break;
}
+ case 'moderator:muteAll':
+ {
+ if (
+ !peer.hasRole(userRoles.MODERATOR) &&
+ !peer.hasRole(userRoles.ADMIN)
+ )
+ throw new Error('peer does not have moderator priveleges');
+
+ // Spread to others
+ this._notification(peer.socket, 'moderator:mute', {
+ peerId : peer.id
+ }, true);
+
+ cb();
+
+ break;
+ }
+
+ case 'moderator:stopAllVideo':
+ {
+ if (
+ !peer.hasRole(userRoles.MODERATOR) &&
+ !peer.hasRole(userRoles.ADMIN)
+ )
+ throw new Error('peer does not have moderator priveleges');
+
+ // Spread to others
+ this._notification(peer.socket, 'moderator:stopVideo', {
+ peerId : peer.id
+ }, true);
+
+ cb();
+
+ break;
+ }
+
+ case 'moderator:kickPeer':
+ {
+ if (
+ !peer.hasRole(userRoles.MODERATOR) &&
+ !peer.hasRole(userRoles.ADMIN)
+ )
+ throw new Error('peer does not have moderator priveleges');
+
+ const { peerId } = request.data;
+
+ const kickPeer = this._peers[peerId];
+
+ if (!kickPeer)
+ throw new Error(`peer with id "${peerId}" not found`);
+
+ this._notification(
+ kickPeer.socket,
+ 'moderator:kick'
+ );
+
+ kickPeer.close();
+
+ cb();
+
+ break;
+ }
+
default:
{
logger.error('unknown request.method "%s"', request.method);
diff --git a/server/userRoles.js b/server/userRoles.js
index ba5fd59..c8cf886 100644
--- a/server/userRoles.js
+++ b/server/userRoles.js
@@ -1,12 +1,12 @@
module.exports = {
// Allowed to enter locked rooms + all other priveleges
- ADMIN : 0,
+ ADMIN : 'admin',
// Allowed to enter restricted rooms if configured.
// Allowed to moderate users in a room (mute all,
// spotlight video, kick users)
- MODERATOR : 1,
+ MODERATOR : 'moderator',
// Same as MODERATOR, but can't moderate users
- AUTHENTICATED : 2,
+ AUTHENTICATED : 'authenticated',
// No priveleges
- ALL : 3
+ ALL : 'normal'
};
\ No newline at end of file