diff --git a/HAproxy.md b/HAproxy.md index b738097..485e11e 100644 --- a/HAproxy.md +++ b/HAproxy.md @@ -62,14 +62,6 @@ OR ## Configure multiparty-meeting servers -### App config - -mm/configs/app/config.js - -``` js -multipartyServer : 'meet.example.com', -``` - ### Server config mm/configs/server/config.js diff --git a/app/package.json b/app/package.json index 1dab672..9392a4a 100644 --- a/app/package.json +++ b/app/package.json @@ -60,6 +60,7 @@ ], "devDependencies": { "electron": "^7.1.1", + "eslint-plugin-react": "^7.19.0", "foreman": "^3.0.1", "redux-mock-store": "^1.5.3" } diff --git a/app/public/config/config.example.js b/app/public/config/config.example.js index 9e16360..cf2703d 100644 --- a/app/public/config/config.example.js +++ b/app/public/config/config.example.js @@ -1,9 +1,9 @@ // eslint-disable-next-line var config = { - loginEnabled : false, - developmentPort : 3443, - productionPort : 443, + loginEnabled : false, + developmentPort : 3443, + productionPort : 443, /** * If defaultResolution is set, it will override user settings when joining: @@ -25,6 +25,7 @@ var config = { scaleResolutionDownBy: 2 }, { scaleResolutionDownBy: 1 } ], + /** * White listing browsers that support audio output device selection. * It is not yet fully implemented in Firefox. @@ -41,13 +42,18 @@ var config = { tcp : true }, - lastN : 4, - mobileLastN : 1, - background : 'images/background.jpg', + defaultLayout : 'democratic', // democratic, filmstrip + lastN : 4, + mobileLastN : 1, + // Highest number of speakers user can select + maxLastN : 5, + // If truthy, users can NOT change number of speakers visible + lockLastN : false, + background : 'images/background.jpg', // Add file and uncomment for adding logo to appbar // logo : 'images/logo.svg', - title : 'Multiparty meeting', - theme : + title : 'Multiparty meeting', + theme : { palette : { diff --git a/app/public/privacy/privacy.html b/app/public/privacy/privacy.html new file mode 100644 index 0000000..89b4959 --- /dev/null +++ b/app/public/privacy/privacy.html @@ -0,0 +1,13 @@ + + + + + + Pleaceholder for Privacy Statetment/Policy, AUP + + +

Privacy Statement

+

Privacy Policy

+

Acceptable use policy (AUP)

+ + \ No newline at end of file diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index 630851a..d2ab9bc 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -31,8 +31,7 @@ let Spotlights; let requestTimeout, transportOptions, lastN, - mobileLastN, - defaultResolution; + mobileLastN; if (process.env.NODE_ENV !== 'test') { @@ -40,8 +39,7 @@ if (process.env.NODE_ENV !== 'test') requestTimeout, transportOptions, lastN, - mobileLastN, - defaultResolution + mobileLastN } = window.config); } @@ -205,9 +203,6 @@ export default class RoomClient // Our WebTorrent client this._webTorrent = null; - if (defaultResolution) - store.dispatch(settingsActions.setVideoResolution(defaultResolution)); - // Max spotlights if (device.platform === 'desktop') this._maxSpotlights = lastN; @@ -470,9 +465,9 @@ export default class RoomClient }); } - login() + login(roomId = this._roomId) { - const url = `/auth/login?peerId=${this._peerId}&roomId=${this._roomId}`; + const url = `/auth/login?peerId=${this._peerId}&roomId=${roomId}`; window.open(url, 'loginWindow'); } @@ -534,11 +529,6 @@ export default class RoomClient } } - notify(text) - { - store.dispatch(requestActions.notify({ text: text })); - } - timeoutCallback(callback) { let called = false; @@ -684,7 +674,7 @@ export default class RoomClient { if (err) { - return store.dispatch(requestActions.notify( + store.dispatch(requestActions.notify( { type : 'error', text : intl.formatMessage({ @@ -692,6 +682,8 @@ export default class RoomClient defaultMessage : 'Unable to save file' }) })); + + return; } saveAs(blob, file.name); @@ -708,7 +700,9 @@ export default class RoomClient if (existingTorrent) { // Never add duplicate torrents, use the existing one instead. - return this._handleTorrent(existingTorrent); + this._handleTorrent(existingTorrent); + + return; } this._webTorrent.add(magnetUri, this._handleTorrent); @@ -720,11 +714,13 @@ export default class RoomClient // same file was sent multiple times. if (torrent.progress === 1) { - return store.dispatch( + store.dispatch( fileActions.setFileDone( torrent.magnetURI, torrent.files )); + + return; } let lastMove = 0; @@ -767,7 +763,7 @@ export default class RoomClient { if (err) { - return store.dispatch(requestActions.notify( + store.dispatch(requestActions.notify( { type : 'error', text : intl.formatMessage({ @@ -775,13 +771,30 @@ export default class RoomClient defaultMessage : 'Unable to share file' }) })); + + return; } const existingTorrent = this._webTorrent.get(torrent); if (existingTorrent) { - return this._sendFile(existingTorrent.magnetURI); + store.dispatch(requestActions.notify( + { + text : intl.formatMessage({ + id : 'filesharing.successfulFileShare', + defaultMessage : 'File successfully shared' + }) + })); + + store.dispatch(fileActions.addFile( + this._peerId, + existingTorrent.magnetURI + )); + + this._sendFile(existingTorrent.magnetURI); + + return; } this._webTorrent.seed( @@ -873,7 +886,7 @@ export default class RoomClient store.dispatch( lobbyPeerActions.addLobbyPeer(peer.peerId)); store.dispatch( - lobbyPeerActions.setLobbyPeerDisplayName(peer.displayName)); + lobbyPeerActions.setLobbyPeerDisplayName(peer.displayName, peer.peerId)); store.dispatch( lobbyPeerActions.setLobbyPeerPicture(peer.picture)); }); diff --git a/app/src/components/ChooseRoom.js b/app/src/components/ChooseRoom.js index b81ff47..3d549b3 100644 --- a/app/src/components/ChooseRoom.js +++ b/app/src/components/ChooseRoom.js @@ -86,7 +86,7 @@ const DialogTitle = withStyles(styles)((props) => return ( - { window.config && window.config.logo && Logo } + { window.config.logo && Logo } {children} ); @@ -125,7 +125,7 @@ const ChooseRoom = ({ }} > - { window.config && window.config.title ? window.config.title : 'Multiparty meeting' } + { window.config.title ? window.config.title : 'Multiparty meeting' }
diff --git a/app/src/components/Containers/Peer.js b/app/src/components/Containers/Peer.js index 559d625..827550b 100644 --- a/app/src/components/Containers/Peer.js +++ b/app/src/components/Containers/Peer.js @@ -12,8 +12,8 @@ import { useIntl, FormattedMessage } from 'react-intl'; import VideoView from '../VideoContainers/VideoView'; import Tooltip from '@material-ui/core/Tooltip'; import Fab from '@material-ui/core/Fab'; -import MicIcon from '@material-ui/icons/Mic'; -import MicOffIcon from '@material-ui/icons/MicOff'; +import VolumeUpIcon from '@material-ui/icons/VolumeUp'; +import VolumeOffIcon from '@material-ui/icons/VolumeOff'; import NewWindowIcon from '@material-ui/icons/OpenInNew'; import FullScreenIcon from '@material-ui/icons/Fullscreen'; import Volume from './Volume'; @@ -252,9 +252,9 @@ const Peer = (props) => }} > { micEnabled ? - + : - + } @@ -340,6 +340,7 @@ const Peer = (props) => videoMultiLayer={webcamConsumer && webcamConsumer.type !== 'simple'} videoTrack={webcamConsumer && webcamConsumer.track} videoVisible={videoVisible} + audioTrack={micConsumer && micConsumer.track} audioCodec={micConsumer && micConsumer.codec} videoCodec={webcamConsumer && webcamConsumer.codec} audioScore={micConsumer ? micConsumer.score : null} diff --git a/app/src/components/Controls/TopBar.js b/app/src/components/Controls/TopBar.js index 2cc380a..277507b 100644 --- a/app/src/components/Controls/TopBar.js +++ b/app/src/components/Controls/TopBar.js @@ -80,6 +80,10 @@ const styles = (theme) => { margin : theme.spacing(1, 0), padding : theme.spacing(0, 1) + }, + green : + { + color : 'rgba(0, 153, 0, 1)' } }); @@ -136,6 +140,7 @@ const TopBar = (props) => openUsersTab, unread, canLock, + canPromote, classes } = props; @@ -194,14 +199,14 @@ const TopBar = (props) => - { window.config && window.config.logo && Logo } + { window.config.logo && Logo } - { window.config && window.config.title ? window.config.title : 'Multiparty meeting' } + { window.config.title ? window.config.title : 'Multiparty meeting' }
@@ -305,6 +310,7 @@ const TopBar = (props) => defaultMessage : 'Show lobby' })} color='inherit' + disabled={!canPromote} onClick={() => setLockDialogOpen(!room.lockDialogOpen)} > { myPicture ? : - + } @@ -380,6 +386,7 @@ TopBar.propTypes = openUsersTab : PropTypes.func.isRequired, unread : PropTypes.number.isRequired, canLock : PropTypes.bool.isRequired, + canPromote : PropTypes.bool.isRequired, classes : PropTypes.object.isRequired, theme : PropTypes.object.isRequired }; @@ -397,7 +404,10 @@ const mapStateToProps = (state) => state.toolarea.unreadFiles, canLock : state.me.roles.some((role) => - state.room.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role)) + state.room.permissionsFromRoles.CHANGE_ROOM_LOCK.includes(role)), + canPromote : + state.me.roles.some((role) => + state.room.permissionsFromRoles.PROMOTE_PEER.includes(role)) }); const mapDispatchToProps = (dispatch) => diff --git a/app/src/components/JoinDialog.js b/app/src/components/JoinDialog.js index 85262b1..1f270c6 100644 --- a/app/src/components/JoinDialog.js +++ b/app/src/components/JoinDialog.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { withStyles } from '@material-ui/core/styles'; import { withRoomContext } from '../RoomContext'; +import classnames from 'classnames'; import isElectron from 'is-electron'; import * as settingsActions from '../actions/settingsActions'; import PropTypes from 'prop-types'; @@ -128,9 +129,9 @@ const DialogTitle = withStyles(styles)((props) => return ( - { window.config && window.config.logo && Logo } + { window.config.logo && Logo } {children} - { window.config && window.config.loginEnabled && + { window.config.loginEnabled && { myPicture ? : - + } @@ -217,11 +220,11 @@ const JoinDialog = ({ myPicture={myPicture} onLogin={() => { - loggedIn ? roomClient.logout() : roomClient.login(); + loggedIn ? roomClient.logout() : roomClient.login(roomId); }} loggedIn={loggedIn} > - { window.config && window.config.title ? window.config.title : 'Multiparty meeting' } + { window.config.title ? window.config.title : 'Multiparty meeting' }
@@ -316,6 +319,7 @@ const JoinDialog = ({ className={classes.green} gutterBottom variant='h6' + style={{ fontWeight: '600' }} align='center' > { room.signInRequired ? - + : - + { if (event.target.files.length > 0) { - props.roomClient.shareFiles(event.target.files); + await props.roomClient.shareFiles(event.target.files); } }; @@ -65,6 +65,8 @@ const FileSharing = (props) => type='file' disabled={!canShare} onChange={handleFileChange} + // Need to reset to be able to share same file twice + onClick={(e) => (e.target.value = null)} id='share-files-button' />