Merge branch 'feat-roles-authorization' into develop
This commit is contained in:
+12
-5
@@ -2371,10 +2371,8 @@ export default class RoomClient
|
||||
{
|
||||
logger.debug('_joinRoom()');
|
||||
|
||||
const {
|
||||
displayName,
|
||||
picture
|
||||
} = store.getState().settings;
|
||||
const { displayName } = store.getState().settings;
|
||||
const { picture } = store.getState().me;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -2524,7 +2522,13 @@ export default class RoomClient
|
||||
canShareFiles : this._torrentSupport
|
||||
}));
|
||||
|
||||
const { authenticated, roles, peers } = await this.sendRequest(
|
||||
const {
|
||||
authenticated,
|
||||
roles,
|
||||
peers,
|
||||
permissionsFromRoles,
|
||||
userRoles
|
||||
} = await this.sendRequest(
|
||||
'join',
|
||||
{
|
||||
displayName : displayName,
|
||||
@@ -2541,6 +2545,9 @@ export default class RoomClient
|
||||
|
||||
store.dispatch(meActions.loggedIn(authenticated));
|
||||
|
||||
store.dispatch(roomActions.setUserRoles(userRoles));
|
||||
store.dispatch(roomActions.setPermissionsFromRoles(permissionsFromRoles));
|
||||
|
||||
const myRoles = store.getState().me.roles;
|
||||
|
||||
for (const role of roles)
|
||||
|
||||
@@ -127,4 +127,16 @@ export const setCloseMeetingInProgress = (flag) =>
|
||||
({
|
||||
type : 'CLOSE_MEETING_IN_PROGRESS',
|
||||
payload : { flag }
|
||||
});
|
||||
|
||||
export const setUserRoles = (userRoles) =>
|
||||
({
|
||||
type : 'SET_USER_ROLES',
|
||||
payload : { userRoles }
|
||||
});
|
||||
|
||||
export const setPermissionsFromRoles = (permissionsFromRoles) =>
|
||||
({
|
||||
type : 'SET_PERMISSIONS_FROM_ROLES',
|
||||
payload : { permissionsFromRoles }
|
||||
});
|
||||
@@ -7,72 +7,16 @@ import { withRoomContext } from '../../../RoomContext';
|
||||
import { useIntl } from 'react-intl';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import EmptyAvatar from '../../../images/avatar-empty.jpeg';
|
||||
import PromoteIcon from '@material-ui/icons/OpenInBrowser';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
|
||||
const styles = (theme) =>
|
||||
const styles = () =>
|
||||
({
|
||||
root :
|
||||
{
|
||||
padding : theme.spacing(1),
|
||||
width : '100%',
|
||||
overflow : 'hidden',
|
||||
cursor : 'auto',
|
||||
display : 'flex'
|
||||
},
|
||||
avatar :
|
||||
{
|
||||
borderRadius : '50%',
|
||||
height : '2rem'
|
||||
},
|
||||
peerInfo :
|
||||
{
|
||||
fontSize : '1rem',
|
||||
border : 'none',
|
||||
display : 'flex',
|
||||
paddingLeft : theme.spacing(1),
|
||||
flexGrow : 1,
|
||||
alignItems : 'center'
|
||||
},
|
||||
controls :
|
||||
{
|
||||
float : 'right',
|
||||
display : 'flex',
|
||||
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
|
||||
},
|
||||
'&.disabled' :
|
||||
{
|
||||
pointerEvents : 'none',
|
||||
backgroundColor : 'var(--media-control-botton-disabled)'
|
||||
},
|
||||
'&.promote' :
|
||||
{
|
||||
backgroundColor : 'var(--media-control-botton-on)'
|
||||
}
|
||||
},
|
||||
ListItem :
|
||||
{
|
||||
alignItems : 'center'
|
||||
}
|
||||
@@ -83,6 +27,7 @@ const ListLobbyPeer = (props) =>
|
||||
const {
|
||||
roomClient,
|
||||
peer,
|
||||
canPromote,
|
||||
classes
|
||||
} = props;
|
||||
|
||||
@@ -92,7 +37,7 @@ const ListLobbyPeer = (props) =>
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
className={classnames(classes.ListItem)}
|
||||
className={classnames(classes.root)}
|
||||
key={peer.peerId}
|
||||
button
|
||||
alignItems='flex-start'
|
||||
@@ -109,10 +54,8 @@ const ListLobbyPeer = (props) =>
|
||||
defaultMessage : 'Click to let them in'
|
||||
})}
|
||||
>
|
||||
<ListItemIcon
|
||||
className={classnames(classes.button, 'promote', {
|
||||
disabled : peer.promotionInProgress
|
||||
})}
|
||||
<IconButton
|
||||
disabled={!canPromote || peer.promotionInProgress}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
@@ -120,7 +63,7 @@ const ListLobbyPeer = (props) =>
|
||||
}}
|
||||
>
|
||||
<PromoteIcon />
|
||||
</ListItemIcon>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</ListItem>
|
||||
);
|
||||
@@ -131,13 +74,17 @@ ListLobbyPeer.propTypes =
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
advancedMode : PropTypes.bool,
|
||||
peer : PropTypes.object.isRequired,
|
||||
canPromote : PropTypes.bool.isRequired,
|
||||
classes : PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, { id }) =>
|
||||
{
|
||||
return {
|
||||
peer : state.lobbyPeers[id]
|
||||
peer : state.lobbyPeers[id],
|
||||
canPromote :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.PROMOTE_PEER.includes(role))
|
||||
};
|
||||
};
|
||||
|
||||
@@ -149,6 +96,8 @@ export default withRoomContext(connect(
|
||||
areStatesEqual : (next, prev) =>
|
||||
{
|
||||
return (
|
||||
prev.room.permissionsFromRoles === next.room.permissionsFromRoles &&
|
||||
prev.me.roles === next.me.roles &&
|
||||
prev.lobbyPeers === next.lobbyPeers
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ const Me = (props) =>
|
||||
micProducer,
|
||||
webcamProducer,
|
||||
screenProducer,
|
||||
canShareScreen,
|
||||
classes,
|
||||
theme
|
||||
} = props;
|
||||
@@ -396,7 +397,11 @@ const Me = (props) =>
|
||||
defaultMessage : 'Start screen sharing'
|
||||
})}
|
||||
className={classes.fab}
|
||||
disabled={!me.canShareScreen || me.screenShareInProgress}
|
||||
disabled={
|
||||
!canShareScreen ||
|
||||
!me.canShareScreen ||
|
||||
me.screenShareInProgress
|
||||
}
|
||||
color={screenState === 'on' ? 'primary' : 'default'}
|
||||
size={smallButtons ? 'small' : 'large'}
|
||||
onClick={() =>
|
||||
@@ -537,6 +542,7 @@ Me.propTypes =
|
||||
spacing : PropTypes.number,
|
||||
style : PropTypes.object,
|
||||
smallButtons : PropTypes.bool,
|
||||
canShareScreen : PropTypes.bool.isRequired,
|
||||
classes : PropTypes.object.isRequired,
|
||||
theme : PropTypes.object.isRequired
|
||||
};
|
||||
@@ -544,10 +550,13 @@ Me.propTypes =
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
me : state.me,
|
||||
me : state.me,
|
||||
...meProducersSelector(state),
|
||||
settings : state.settings,
|
||||
activeSpeaker : state.me.id === state.room.activeSpeakerId
|
||||
settings : state.settings,
|
||||
activeSpeaker : state.me.id === state.room.activeSpeakerId,
|
||||
canShareScreen :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.SHARE_SCREEN.includes(role))
|
||||
};
|
||||
};
|
||||
|
||||
@@ -559,6 +568,7 @@ export default withRoomContext(connect(
|
||||
areStatesEqual : (next, prev) =>
|
||||
{
|
||||
return (
|
||||
prev.room.permissionsFromRoles === next.room.permissionsFromRoles &&
|
||||
prev.me === next.me &&
|
||||
prev.producers === next.producers &&
|
||||
prev.settings === next.settings &&
|
||||
|
||||
@@ -135,6 +135,7 @@ const TopBar = (props) =>
|
||||
toggleToolArea,
|
||||
openUsersTab,
|
||||
unread,
|
||||
canLock,
|
||||
classes
|
||||
} = props;
|
||||
|
||||
@@ -271,6 +272,7 @@ const TopBar = (props) =>
|
||||
})}
|
||||
className={classes.actionButton}
|
||||
color='inherit'
|
||||
disabled={!canLock}
|
||||
onClick={() =>
|
||||
{
|
||||
if (room.locked)
|
||||
@@ -377,6 +379,7 @@ TopBar.propTypes =
|
||||
toggleToolArea : PropTypes.func.isRequired,
|
||||
openUsersTab : PropTypes.func.isRequired,
|
||||
unread : PropTypes.number.isRequired,
|
||||
canLock : PropTypes.bool.isRequired,
|
||||
classes : PropTypes.object.isRequired,
|
||||
theme : PropTypes.object.isRequired
|
||||
};
|
||||
@@ -391,7 +394,10 @@ const mapStateToProps = (state) =>
|
||||
loginEnabled : state.me.loginEnabled,
|
||||
myPicture : state.me.picture,
|
||||
unread : state.toolarea.unreadMessages +
|
||||
state.toolarea.unreadFiles
|
||||
state.toolarea.unreadFiles,
|
||||
canLock :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role))
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
@@ -434,6 +440,7 @@ export default withRoomContext(connect(
|
||||
prev.me.loggedIn === next.me.loggedIn &&
|
||||
prev.me.loginEnabled === next.me.loginEnabled &&
|
||||
prev.me.picture === next.me.picture &&
|
||||
prev.me.roles === next.me.roles &&
|
||||
prev.toolarea.unreadMessages === next.toolarea.unreadMessages &&
|
||||
prev.toolarea.unreadFiles === next.toolarea.unreadFiles
|
||||
);
|
||||
|
||||
@@ -54,6 +54,7 @@ const ChatInput = (props) =>
|
||||
roomClient,
|
||||
displayName,
|
||||
picture,
|
||||
canChat,
|
||||
classes
|
||||
} = props;
|
||||
|
||||
@@ -66,6 +67,7 @@ const ChatInput = (props) =>
|
||||
defaultMessage : 'Enter chat message...'
|
||||
})}
|
||||
value={message || ''}
|
||||
disabled={!canChat}
|
||||
onChange={handleChange}
|
||||
onKeyPress={(ev) =>
|
||||
{
|
||||
@@ -89,6 +91,7 @@ const ChatInput = (props) =>
|
||||
color='primary'
|
||||
className={classes.iconButton}
|
||||
aria-label='Send'
|
||||
disabled={!canChat}
|
||||
onClick={() =>
|
||||
{
|
||||
if (message && message !== '')
|
||||
@@ -112,13 +115,17 @@ ChatInput.propTypes =
|
||||
roomClient : PropTypes.object.isRequired,
|
||||
displayName : PropTypes.string,
|
||||
picture : PropTypes.string,
|
||||
canChat : PropTypes.bool.isRequired,
|
||||
classes : PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
({
|
||||
displayName : state.settings.displayName,
|
||||
picture : state.me.picture
|
||||
picture : state.me.picture,
|
||||
canChat :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.SEND_CHAT.includes(role))
|
||||
});
|
||||
|
||||
export default withRoomContext(
|
||||
@@ -130,6 +137,8 @@ export default withRoomContext(
|
||||
areStatesEqual : (next, prev) =>
|
||||
{
|
||||
return (
|
||||
prev.room.permissionsFromRoles === next.room.permissionsFromRoles &&
|
||||
prev.me.roles === next.me.roles &&
|
||||
prev.settings.displayName === next.settings.displayName &&
|
||||
prev.me.picture === next.me.picture
|
||||
);
|
||||
|
||||
@@ -41,6 +41,7 @@ const FileSharing = (props) =>
|
||||
|
||||
const {
|
||||
canShareFiles,
|
||||
canShare,
|
||||
classes
|
||||
} = props;
|
||||
|
||||
@@ -60,6 +61,7 @@ const FileSharing = (props) =>
|
||||
<input
|
||||
className={classes.input}
|
||||
type='file'
|
||||
disabled={!canShare}
|
||||
onChange={handleFileChange}
|
||||
id='share-files-button'
|
||||
/>
|
||||
@@ -68,7 +70,7 @@ const FileSharing = (props) =>
|
||||
variant='contained'
|
||||
component='span'
|
||||
className={classes.button}
|
||||
disabled={!canShareFiles}
|
||||
disabled={!canShareFiles || !canShare}
|
||||
>
|
||||
{buttonDescription}
|
||||
</Button>
|
||||
@@ -83,6 +85,7 @@ FileSharing.propTypes = {
|
||||
roomClient : PropTypes.any.isRequired,
|
||||
canShareFiles : PropTypes.bool.isRequired,
|
||||
tabOpen : PropTypes.bool.isRequired,
|
||||
canShare : PropTypes.bool.isRequired,
|
||||
classes : PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -90,10 +93,26 @@ const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
canShareFiles : state.me.canShareFiles,
|
||||
tabOpen : state.toolarea.currentToolTab === 'files'
|
||||
tabOpen : state.toolarea.currentToolTab === 'files',
|
||||
canShare :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.SHARE_FILE.includes(role))
|
||||
};
|
||||
};
|
||||
|
||||
export default withRoomContext(connect(
|
||||
mapStateToProps
|
||||
mapStateToProps,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
areStatesEqual : (next, prev) =>
|
||||
{
|
||||
return (
|
||||
prev.room.permissionsFromRoles === next.room.permissionsFromRoles &&
|
||||
prev.me.roles === next.me.roles &&
|
||||
prev.me.canShareFiles === next.me.canShareFiles &&
|
||||
prev.toolarea.currentToolTab === next.toolarea.currentToolTab
|
||||
);
|
||||
}
|
||||
}
|
||||
)(withStyles(styles)(FileSharing)));
|
||||
|
||||
@@ -13,7 +13,6 @@ 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) =>
|
||||
({
|
||||
@@ -174,8 +173,9 @@ ParticipantList.propTypes =
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
isModerator : state.me.roles.includes(userRoles.MODERATOR) ||
|
||||
state.me.roles.includes(userRoles.ADMIN),
|
||||
isModerator :
|
||||
state.me.roles.some((role) =>
|
||||
state.room.permissionsFromRoles.MODERATE_ROOM.includes(role)),
|
||||
passivePeers : passivePeersSelector(state),
|
||||
selectedPeerId : state.room.selectedPeerId,
|
||||
spotlightPeers : spotlightSortedPeersSelector(state)
|
||||
@@ -190,6 +190,7 @@ const ParticipantListContainer = withRoomContext(connect(
|
||||
areStatesEqual : (next, prev) =>
|
||||
{
|
||||
return (
|
||||
prev.room.permissionsFromRoles === next.room.permissionsFromRoles &&
|
||||
prev.me.roles === next.me.roles &&
|
||||
prev.peers === next.peers &&
|
||||
prev.room.spotlights === next.room.spotlights &&
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import * as userRoles from './userRoles';
|
||||
|
||||
const initialState =
|
||||
{
|
||||
id : null,
|
||||
picture : null,
|
||||
isMobile : false,
|
||||
roles : [ userRoles.ALL ],
|
||||
roles : [ 'normal' ], // Default role
|
||||
canSendMic : false,
|
||||
canSendWebcam : false,
|
||||
canShareScreen : false,
|
||||
|
||||
@@ -21,7 +21,16 @@ const initialState =
|
||||
joined : false,
|
||||
muteAllInProgress : false,
|
||||
stopAllVideoInProgress : false,
|
||||
closeMeetingInProgress : false
|
||||
closeMeetingInProgress : false,
|
||||
userRoles : { NORMAL: 'normal' }, // Default role
|
||||
permissionsFromRoles : {
|
||||
CHANGE_ROOM_LOCK : [],
|
||||
PROMOTE_PEER : [],
|
||||
SEND_CHAT : [],
|
||||
SHARE_SCREEN : [],
|
||||
SHARE_FILE : [],
|
||||
MODERATE_ROOM : []
|
||||
}
|
||||
};
|
||||
|
||||
const room = (state = initialState, action) =>
|
||||
@@ -175,6 +184,20 @@ const room = (state = initialState, action) =>
|
||||
case 'CLOSE_MEETING_IN_PROGRESS':
|
||||
return { ...state, closeMeetingInProgress: action.payload.flag };
|
||||
|
||||
case 'SET_USER_ROLES':
|
||||
{
|
||||
const { userRoles } = action.payload;
|
||||
|
||||
return { ...state, userRoles };
|
||||
}
|
||||
|
||||
case 'SET_PERMISSIONS_FROM_ROLES':
|
||||
{
|
||||
const { permissionsFromRoles } = action.payload;
|
||||
|
||||
return { ...state, permissionsFromRoles };
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export const ADMIN = 'admin';
|
||||
export const MODERATOR = 'moderator';
|
||||
export const AUTHENTICATED = 'authenticated';
|
||||
export const ALL = 'normal';
|
||||
Reference in New Issue
Block a user