diff --git a/README.md b/README.md
index de7fb96..cf13290 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,12 @@ To integrate with an LMS (e.g. Moodle), have a look at [LTI](LTI/LTI.md).
* You need an additional [TURN](https://github.com/coturn/coturn)-server for clients located behind restrictive firewalls! Add your server and credentials to `app/config.js`
+## Community-driven support
+
+* Open mailing list: community@lists.edumeet.org
+* Subscribe: lists.edumeet.org/sympa/subscribe/community/
+* Open archive: lists.edumeet.org/sympa/arc/community/
+
## Authors
* Håvar Aambø Fosstveit
diff --git a/app/package.json b/app/package.json
index fc6c575..1dab672 100644
--- a/app/package.json
+++ b/app/package.json
@@ -11,6 +11,7 @@
"@material-ui/core": "^4.5.1",
"@material-ui/icons": "^4.5.1",
"bowser": "^2.7.0",
+ "classnames": "^2.2.6",
"create-torrent": "^4.4.1",
"dompurify": "^2.0.7",
"domready": "^1.0.8",
diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js
index 8d0e01f..0151e2b 100644
--- a/app/src/RoomClient.js
+++ b/app/src/RoomClient.js
@@ -1295,6 +1295,28 @@ export default class RoomClient
lobbyPeerActions.setLobbyPeerPromotionInProgress(peerId, false));
}
+ async clearChat()
+ {
+ logger.debug('clearChat()');
+
+ store.dispatch(
+ roomActions.setClearChatInProgress(true));
+
+ try
+ {
+ await this.sendRequest('moderator:clearChat');
+
+ store.dispatch(chatActions.clearChat());
+ }
+ catch (error)
+ {
+ logger.error('clearChat() failed: %o', error);
+ }
+
+ store.dispatch(
+ roomActions.setClearChatInProgress(false));
+ }
+
async kickPeer(peerId)
{
logger.debug('kickPeer() [peerId:"%s"]', peerId);
@@ -2152,6 +2174,21 @@ export default class RoomClient
break;
}
+ case 'moderator:clearChat':
+ {
+ store.dispatch(chatActions.clearChat());
+
+ store.dispatch(requestActions.notify(
+ {
+ text : intl.formatMessage({
+ id : 'moderator.clearChat',
+ defaultMessage : 'Moderator cleared the chat'
+ })
+ }));
+
+ break;
+ }
+
case 'sendFile':
{
const { peerId, magnetUri } = notification.data;
@@ -2306,8 +2343,8 @@ export default class RoomClient
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
- id : 'moderator.mute',
- defaultMessage : 'Moderator muted your microphone'
+ id : 'moderator.muteAudio',
+ defaultMessage : 'Moderator muted your audio'
})
}));
}
@@ -2325,7 +2362,7 @@ export default class RoomClient
store.dispatch(requestActions.notify(
{
text : intl.formatMessage({
- id : 'moderator.mute',
+ id : 'moderator.muteVideo',
defaultMessage : 'Moderator stopped your video'
})
}));
diff --git a/app/src/actions/chatActions.js b/app/src/actions/chatActions.js
index c38d92d..f7b0cf3 100644
--- a/app/src/actions/chatActions.js
+++ b/app/src/actions/chatActions.js
@@ -14,4 +14,9 @@ export const addChatHistory = (chatHistory) =>
({
type : 'ADD_CHAT_HISTORY',
payload : { chatHistory }
+ });
+
+export const clearChat = () =>
+ ({
+ type : 'CLEAR_CHAT'
});
\ No newline at end of file
diff --git a/app/src/actions/roomActions.js b/app/src/actions/roomActions.js
index 1e93453..227969c 100644
--- a/app/src/actions/roomActions.js
+++ b/app/src/actions/roomActions.js
@@ -129,6 +129,12 @@ export const setCloseMeetingInProgress = (flag) =>
payload : { flag }
});
+export const setClearChatInProgress = (flag) =>
+ ({
+ type : 'CLEAR_CHAT_IN_PROGRESS',
+ payload : { flag }
+ });
+
export const setUserRoles = (userRoles) =>
({
type : 'SET_USER_ROLES',
@@ -139,4 +145,4 @@ export const setPermissionsFromRoles = (permissionsFromRoles) =>
({
type : 'SET_PERMISSIONS_FROM_ROLES',
payload : { permissionsFromRoles }
- });
\ No newline at end of file
+ });
diff --git a/app/src/components/MeetingDrawer/Chat/Chat.js b/app/src/components/MeetingDrawer/Chat/Chat.js
index 2bf88ad..d1c8c9e 100644
--- a/app/src/components/MeetingDrawer/Chat/Chat.js
+++ b/app/src/components/MeetingDrawer/Chat/Chat.js
@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
+import ChatModerator from './ChatModerator';
import MessageList from './MessageList';
import ChatInput from './ChatInput';
@@ -25,6 +26,7 @@ const Chat = (props) =>
return (
+
diff --git a/app/src/components/MeetingDrawer/Chat/ChatModerator.js b/app/src/components/MeetingDrawer/Chat/ChatModerator.js
new file mode 100644
index 0000000..86f4dd7
--- /dev/null
+++ b/app/src/components/MeetingDrawer/Chat/ChatModerator.js
@@ -0,0 +1,104 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { withRoomContext } from '../../../RoomContext';
+import { withStyles } from '@material-ui/core/styles';
+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',
+ listStyleType : 'none',
+ boxShadow : '0 2px 5px 2px rgba(0, 0, 0, 0.2)',
+ backgroundColor : 'rgba(255, 255, 255, 1)'
+ },
+ listheader :
+ {
+ padding : theme.spacing(1),
+ fontWeight : 'bolder'
+ },
+ actionButton :
+ {
+ marginLeft : 'auto'
+ }
+ });
+
+const ChatModerator = (props) =>
+{
+ const intl = useIntl();
+
+ const {
+ roomClient,
+ isChatModerator,
+ room,
+ classes
+ } = props;
+
+ if (!isChatModerator)
+ return;
+
+ return (
+
+ -
+
+
+
+
+ );
+};
+
+ChatModerator.propTypes =
+{
+ roomClient : PropTypes.any.isRequired,
+ isChatModerator : PropTypes.bool,
+ room : PropTypes.object,
+ classes : PropTypes.object.isRequired
+};
+
+const mapStateToProps = (state) =>
+ ({
+ isChatModerator :
+ state.me.roles.some((role) =>
+ state.room.permissionsFromRoles.MODERATE_CHAT.includes(role)),
+ room : state.room
+ });
+
+export default withRoomContext(connect(
+ mapStateToProps,
+ null,
+ null,
+ {
+ areStatesEqual : (next, prev) =>
+ {
+ return (
+ prev.room === next.room &&
+ prev.me === next.me
+ );
+ }
+ }
+)(withStyles(styles)(ChatModerator)));
\ No newline at end of file
diff --git a/app/src/components/VideoContainers/VideoView.js b/app/src/components/VideoContainers/VideoView.js
index 85506bf..c978433 100644
--- a/app/src/components/VideoContainers/VideoView.js
+++ b/app/src/components/VideoContainers/VideoView.js
@@ -9,7 +9,7 @@ import SignalCellular0BarIcon from '@material-ui/icons/SignalCellular0Bar';
import SignalCellular1BarIcon from '@material-ui/icons/SignalCellular1Bar';
import SignalCellular2BarIcon from '@material-ui/icons/SignalCellular2Bar';
import SignalCellular3BarIcon from '@material-ui/icons/SignalCellular3Bar';
-import SignalCellular4BarIcon from '@material-ui/icons/SignalCellular4Bar';
+import SignalCellularAltIcon from '@material-ui/icons/SignalCellularAlt';
const styles = (theme) =>
({
@@ -217,7 +217,7 @@ class VideoView extends React.PureComponent
case 9:
case 10:
{
- quality = ;
+ quality = ;
break;
}
diff --git a/app/src/reducers/chat.js b/app/src/reducers/chat.js
index e273ee7..001f1a9 100644
--- a/app/src/reducers/chat.js
+++ b/app/src/reducers/chat.js
@@ -30,6 +30,11 @@ const chat = (state = [], action) =>
return [ ...state, ...chatHistory ];
}
+ case 'CLEAR_CHAT':
+ {
+ return [];
+ }
+
default:
return state;
}
diff --git a/app/src/reducers/room.js b/app/src/reducers/room.js
index 0f735d0..cd702f2 100644
--- a/app/src/reducers/room.js
+++ b/app/src/reducers/room.js
@@ -22,11 +22,13 @@ const initialState =
muteAllInProgress : false,
stopAllVideoInProgress : false,
closeMeetingInProgress : false,
+ clearChatInProgress : false,
userRoles : { NORMAL: 'normal' }, // Default role
permissionsFromRoles : {
CHANGE_ROOM_LOCK : [],
PROMOTE_PEER : [],
SEND_CHAT : [],
+ MODERATE_CHAT : [],
SHARE_SCREEN : [],
SHARE_FILE : [],
MODERATE_ROOM : []
@@ -184,6 +186,9 @@ const room = (state = initialState, action) =>
case 'CLOSE_MEETING_IN_PROGRESS':
return { ...state, closeMeetingInProgress: action.payload.flag };
+ case 'CLEAR_CHAT_IN_PROGRESS':
+ return { ...state, clearChatInProgress: action.payload.flag };
+
case 'SET_USER_ROLES':
{
const { userRoles } = action.payload;
diff --git a/app/src/translations/cn.json b/app/src/translations/cn.json
index 572d84e..6f24a6a 100644
--- a/app/src/translations/cn.json
+++ b/app/src/translations/cn.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "访问屏幕时发生错误",
"devices.cameraDisconnected": "相机已断开连接",
- "devices.cameraError": "访问相机时发生错误"
+ "devices.cameraError": "访问相机时发生错误",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
\ No newline at end of file
diff --git a/app/src/translations/cs.json b/app/src/translations/cs.json
index 1be5e7b..401eb2d 100644
--- a/app/src/translations/cs.json
+++ b/app/src/translations/cs.json
@@ -51,6 +51,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -138,5 +139,9 @@
"devices.screenSharingError": "Při přístupu k vaší obrazovce se vyskytla chyba",
"devices.cameraDisconnected": "Kamera odpojena",
- "devices.cameraError": "Při přístupu k vaší kameře se vyskytla chyba"
+ "devices.cameraError": "Při přístupu k vaší kameře se vyskytla chyba",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/de.json b/app/src/translations/de.json
index d2fe938..ca61408 100644
--- a/app/src/translations/de.json
+++ b/app/src/translations/de.json
@@ -52,6 +52,7 @@
"room.muteAll": "Alle stummschalten",
"room.stopAllVideo": "Alle Videos stoppen",
"room.closeMeeting": "Meeting schließen",
+ "room.clearChat": null,
"room.speechUnsupported": "Dein Browser unterstützt keine Spracherkennung",
"me.mutedPTT": "Du bist stummgeschalted, Halte die SPACE-Taste um zu sprechen",
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Fehler bei der Bildschirmfreigabe",
"devices.cameraDisconnected": "Kamera getrennt",
- "devices.cameraError": "Fehler mit deiner Kamera"
+ "devices.cameraError": "Fehler mit deiner Kamera",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/dk.json b/app/src/translations/dk.json
index 1eccd1f..839c94c 100644
--- a/app/src/translations/dk.json
+++ b/app/src/translations/dk.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Der opstod en fejl ved adgang til skærmdeling",
"device.cameraDisconnected": "Kamera frakoblet",
- "device.cameraError": "Der opstod en fejl ved tilkobling af dit kamera"
+ "device.cameraError": "Der opstod en fejl ved tilkobling af dit kamera",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/el.json b/app/src/translations/el.json
index 9125308..054853c 100644
--- a/app/src/translations/el.json
+++ b/app/src/translations/el.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Παρουσιάστηκε σφάλμα κατά την πρόσβαση στην οθόνη σας",
"devices.cameraDisconnected": "Η κάμερα αποσυνδέθηκε",
- "devices.cameraError": "Παρουσιάστηκε σφάλμα κατά την πρόσβαση στην κάμερά σας"
+ "devices.cameraError": "Παρουσιάστηκε σφάλμα κατά την πρόσβαση στην κάμερά σας",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
\ No newline at end of file
diff --git a/app/src/translations/en.json b/app/src/translations/en.json
index 55a80dd..463a1d0 100644
--- a/app/src/translations/en.json
+++ b/app/src/translations/en.json
@@ -52,6 +52,7 @@
"room.muteAll": "Mute all",
"room.stopAllVideo": "Stop all video",
"room.closeMeeting": "Close meeting",
+ "room.clearChat": "Clear chat",
"room.speechUnsupported": "Your browser does not support speech recognition",
"me.mutedPTT": "You are muted, hold down SPACE-BAR to talk",
@@ -143,5 +144,9 @@
"devices.screenSharingError": "An error occured while accessing your screen",
"devices.cameraDisconnected": "Camera disconnected",
- "devices.cameraError": "An error occured while accessing your camera"
+ "devices.cameraError": "An error occured while accessing your camera",
+
+ "moderator.clearChat": "Moderator cleared the chat",
+ "moderator.muteAudio": "Moderator muted your audio",
+ "moderator.muteVideo": "Moderator muted your video"
}
\ No newline at end of file
diff --git a/app/src/translations/es.json b/app/src/translations/es.json
index ef27cdc..3170d3b 100644
--- a/app/src/translations/es.json
+++ b/app/src/translations/es.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Hubo un error al acceder a su pantalla",
"devices.cameraDisconnected": "Cámara desconectada",
- "devices.cameraError": "Hubo un error al acceder a su cámara"
+ "devices.cameraError": "Hubo un error al acceder a su cámara",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/fr.json b/app/src/translations/fr.json
index d057178..10e9566 100644
--- a/app/src/translations/fr.json
+++ b/app/src/translations/fr.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -142,5 +143,9 @@
"devices.screenSharingError": "Une erreur est apparue lors de l'accès à votre partage d'écran",
"devices.cameraDisconnected": "Caméra déconnectée",
- "devices.cameraError": "Une erreur est apparue lors de l'accès à votre caméra"
+ "devices.cameraError": "Une erreur est apparue lors de l'accès à votre caméra",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/hr.json b/app/src/translations/hr.json
index 120b1a5..efc47f6 100644
--- a/app/src/translations/hr.json
+++ b/app/src/translations/hr.json
@@ -52,6 +52,7 @@
"room.muteAll": "Utišaj sve",
"room.stopAllVideo": "Ugasi sve kamere",
"room.closeMeeting": "Završi sastanak",
+ "room.clearChat": null,
"room.speechUnsupported": "Vaš preglednik ne podržava prepoznavanje govora",
"me.mutedPTT": "Utišani ste, pritisnite i držite SPACE tipku za razgovor",
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Greška prilikom pristupa ekranu",
"devices.cameraDisconnected": "Kamera odspojena",
- "devices.cameraError": "Greška prilikom pristupa kameri"
+ "devices.cameraError": "Greška prilikom pristupa kameri",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/hu.json b/app/src/translations/hu.json
index c7dedf1..7f7f334 100644
--- a/app/src/translations/hu.json
+++ b/app/src/translations/hu.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Hiba történt a képernyőd megosztása során",
"devices.cameraDisconnected": "A kamera kapcsolata lebomlott",
- "devices.cameraError": "Hiba történt a kamera elérése során"
+ "devices.cameraError": "Hiba történt a kamera elérése során",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/it.json b/app/src/translations/it.json
index 4529279..7cb7d99 100644
--- a/app/src/translations/it.json
+++ b/app/src/translations/it.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -142,5 +143,9 @@
"devices.screenSharingError": "Errore con l'accesso al tuo schermo",
"devices.cameraDisconnected": "Videocamera scollegata",
- "devices.cameraError": "Errore con l'accesso alla videocamera"
+ "devices.cameraError": "Errore con l'accesso alla videocamera",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/nb.json b/app/src/translations/nb.json
index 1841857..49398aa 100644
--- a/app/src/translations/nb.json
+++ b/app/src/translations/nb.json
@@ -52,6 +52,7 @@
"room.muteAll": "Demp alle",
"room.stopAllVideo": "Stopp all video",
"room.closeMeeting": "Avslutt møte",
+ "room.clearChat": "Tøm chat",
"room.speechUnsupported": "Din nettleser støtter ikke stemmegjenkjenning",
"me.mutedPTT": "Du er dempet, hold nede SPACE for å snakke",
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Det skjedde noe feil med skjermdelingen din",
"devices.cameraDisconnected": "Kamera koblet fra",
- "devices.cameraError": "Det skjedde noe feil med kameraet ditt"
+ "devices.cameraError": "Det skjedde noe feil med kameraet ditt",
+
+ "moderator.clearChat": "Moderator tømte chatten",
+ "moderator.muteAudio": "Moderator mutet lyden din",
+ "moderator.muteVideo": "Moderator mutet videoen din"
}
\ No newline at end of file
diff --git a/app/src/translations/pl.json b/app/src/translations/pl.json
index 3172ab8..7cb17f2 100644
--- a/app/src/translations/pl.json
+++ b/app/src/translations/pl.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Wystąpił błąd podczas uzyskiwania dostępu do ekranu",
"devices.cameraDisconnected": "Kamera odłączona",
- "devices.cameraError": "Wystąpił błąd podczas uzyskiwania dostępu do kamery"
+ "devices.cameraError": "Wystąpił błąd podczas uzyskiwania dostępu do kamery",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
\ No newline at end of file
diff --git a/app/src/translations/pt.json b/app/src/translations/pt.json
index 4c30812..8d3848d 100644
--- a/app/src/translations/pt.json
+++ b/app/src/translations/pt.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "Ocorreu um erro no acesso ao seu ecrã",
"devices.cameraDisconnected": "Câmara desconectada",
- "devices.cameraError": "Ocorreu um erro no acesso à sua câmara"
+ "devices.cameraError": "Ocorreu um erro no acesso à sua câmara",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/ro.json b/app/src/translations/ro.json
index 0fae5de..0439cdf 100644
--- a/app/src/translations/ro.json
+++ b/app/src/translations/ro.json
@@ -52,6 +52,7 @@
"room.muteAll": null,
"room.stopAllVideo": null,
"room.closeMeeting": null,
+ "room.clearChat": null,
"room.speechUnsupported": null,
"me.mutedPTT": null,
@@ -143,5 +144,9 @@
"devices.screenSharingError": "A apărut o eroare la accesarea ecranului",
"devices.cameraDisconnected": "Camera video e disconectată",
- "devices.cameraError": "A apărut o eroare la accesarea camerei video"
+ "devices.cameraError": "A apărut o eroare la accesarea camerei video",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
diff --git a/app/src/translations/uk.json b/app/src/translations/uk.json
index 4c051ed..961aef5 100644
--- a/app/src/translations/uk.json
+++ b/app/src/translations/uk.json
@@ -1,140 +1,149 @@
{
-"socket.disconnected": "Ви відключені",
-"socket.reconnecting": "Ви від'єдналися, намагаєтесь знову підключитися",
-"socket.reconnected": "Ви знову підключилися",
-"socket.requestError": "Помилка при запиті сервера",
+ "socket.disconnected": "Ви відключені",
+ "socket.reconnecting": "Ви від'єдналися, намагаєтесь знову підключитися",
+ "socket.reconnected": "Ви знову підключилися",
+ "socket.requestError": "Помилка при запиті сервера",
-"room.chooseRoom": "Виберіть назву кімнати, до якої хочете приєднатися",
-"room.cookieConsent": "Цей веб-сайт використовує файли cookie для поліпшення роботи користувачів",
-"room.consentUnderstand": "Я розумію",
-"room.joined": "Ви приєдналися до кімнати",
-"room.cantJoin": "Неможливо приєднатися до кімнати",
-"room.youLocked": "Ви заблокували кімнату",
-"room.cantLock": "Не вдається заблокувати кімнату",
-"room.youUnLocked": "Ви розблокували кімнату",
-"room.cantUnLock": "Не вдається розблокувати кімнату",
-"room.locked": "Кімната зараз заблокована",
-"room.unlocked": "Кімната зараз розблокована",
-"room.newLobbyPeer": "Новий учасник увійшов у зал очікування",
-"room.lobbyPeerLeft": "Учасник вийшов із зала очікування",
-"room.lobbyPeerChangedDisplayName": "Учасник у залі очікування змінив ім'я на {displayName}",
-"room.lobbyPeerChangedPicture": "Учасник залу очікування змінив зображення",
-"room.setAccessCode": "Код доступу до кімнати оновлений",
-"room.accessCodeOn": "Код доступу до кімнати зараз активований",
-"room.accessCodeOff": "Код доступу до кімнати зараз відключений",
-"room.peerChangedDisplayName": "{oldDisplayName} змінив ім'я на {displayName}",
-"room.newPeer": "{displayName} приєднався до кімнати",
-"room.newFile": "Новий файл є у доступі",
-"room.toggleAdvancedMode": "Увімкнено розширений режим",
-"room.setDemocratView": "Змінено макет на демократичний вигляд",
-"room.setFilmStripView": "Змінено макет на вид фільму",
-"room.loggedIn": "Ви ввійшли в систему",
-"room.loggedOut": "Ви вийшли з системи",
-"room.changedDisplayName": "Відображуване ім’я змінено на {displayName}",
-"room.changeDisplayNameError": "Сталася помилка під час зміни вашого відображуваного імені",
-"room.chatError": "Не вдається надіслати повідомлення в чаті",
-"room.aboutToJoin": "Ви збираєтесь приєднатися до зустрічі",
-"room.roomId": "Ідентифікатор кімнати: {roomName}",
-"room.setYourName": "Встановіть своє ім'я для участі та виберіть, як ви хочете приєднатися:",
-"room.audioOnly": "Тільки аудіо",
-"room.audioVideo": "Аудіо та відео",
-"room.youAreReady": "Добре, ви готові",
-"room.emptyRequireLogin": "Кімната порожня! Ви можете увійти, щоб розпочати зустріч або чекати, поки хост приєднається",
-"room.locketWait": "Кімната заблокована - дочекайтеся, поки хтось не впустить вас у ...",
-"room.lobbyAdministration": "Адміністрація залу очікування",
-"room.peersInLobby": "Учасники залу очікувань",
-"room.lobbyEmpty": "Наразі у залі очікувань немає нікого",
-"room.hiddenPeers": "{hiddenPeersCount, множина, один {учасник} інший {учасників}}",
-"room.me": "Я",
-"room.spotlights": "Учасники у центрі уваги",
-"room.passive": "Пасивні учасники",
-"room.videoPaused": "Це відео призупинено",
+ "room.chooseRoom": "Виберіть назву кімнати, до якої хочете приєднатися",
+ "room.cookieConsent": "Цей веб-сайт використовує файли cookie для поліпшення роботи користувачів",
+ "room.consentUnderstand": "Я розумію",
+ "room.joined": "Ви приєдналися до кімнати",
+ "room.cantJoin": "Неможливо приєднатися до кімнати",
+ "room.youLocked": "Ви заблокували кімнату",
+ "room.cantLock": "Не вдається заблокувати кімнату",
+ "room.youUnLocked": "Ви розблокували кімнату",
+ "room.cantUnLock": "Не вдається розблокувати кімнату",
+ "room.locked": "Кімната зараз заблокована",
+ "room.unlocked": "Кімната зараз розблокована",
+ "room.newLobbyPeer": "Новий учасник увійшов у зал очікування",
+ "room.lobbyPeerLeft": "Учасник вийшов із зала очікування",
+ "room.lobbyPeerChangedDisplayName": "Учасник у залі очікування змінив ім'я на {displayName}",
+ "room.lobbyPeerChangedPicture": "Учасник залу очікування змінив зображення",
+ "room.setAccessCode": "Код доступу до кімнати оновлений",
+ "room.accessCodeOn": "Код доступу до кімнати зараз активований",
+ "room.accessCodeOff": "Код доступу до кімнати зараз відключений",
+ "room.peerChangedDisplayName": "{oldDisplayName} змінив ім'я на {displayName}",
+ "room.newPeer": "{displayName} приєднався до кімнати",
+ "room.newFile": "Новий файл є у доступі",
+ "room.toggleAdvancedMode": "Увімкнено розширений режим",
+ "room.setDemocratView": "Змінено макет на демократичний вигляд",
+ "room.setFilmStripView": "Змінено макет на вид фільму",
+ "room.loggedIn": "Ви ввійшли в систему",
+ "room.loggedOut": "Ви вийшли з системи",
+ "room.changedDisplayName": "Відображуване ім’я змінено на {displayName}",
+ "room.changeDisplayNameError": "Сталася помилка під час зміни вашого відображуваного імені",
+ "room.chatError": "Не вдається надіслати повідомлення в чаті",
+ "room.aboutToJoin": "Ви збираєтесь приєднатися до зустрічі",
+ "room.roomId": "Ідентифікатор кімнати: {roomName}",
+ "room.setYourName": "Встановіть своє ім'я для участі та виберіть, як ви хочете приєднатися:",
+ "room.audioOnly": "Тільки аудіо",
+ "room.audioVideo": "Аудіо та відео",
+ "room.youAreReady": "Добре, ви готові",
+ "room.emptyRequireLogin": "Кімната порожня! Ви можете увійти, щоб розпочати зустріч або чекати, поки хост приєднається",
+ "room.locketWait": "Кімната заблокована - дочекайтеся, поки хтось не впустить вас у ...",
+ "room.lobbyAdministration": "Адміністрація залу очікування",
+ "room.peersInLobby": "Учасники залу очікувань",
+ "room.lobbyEmpty": "Наразі у залі очікувань немає нікого",
+ "room.hiddenPeers": "{hiddenPeersCount, множина, один {учасник} інший {учасників}}",
+ "room.me": "Я",
+ "room.spotlights": "Учасники у центрі уваги",
+ "room.passive": "Пасивні учасники",
+ "room.videoPaused": "Це відео призупинено",
+ "room.muteAll": null,
+ "room.stopAllVideo": null,
+ "room.closeMeeting": null,
+ "room.clearChat": null,
+ "room.speechUnsupported": null,
-"tooltip.login": "Увійти",
-"tooltip.logout": "Вихід",
-"tooltip.admitFromLobby": "Вхід із залу очікувань",
-"tooltip.lockRoom": "Заблокувати кімнату",
-"tooltip.unLockRoom": "Розблокувати кімнату",
-"tooltip.enterFullscreen": "Вивести повний екран",
-"tooltip.leaveFullscreen": "Залишити повноекранний екран",
-"tooltip.lobby": "Показати зал очікувань",
-"tooltip.settings": "Показати налаштування",
-"tooltip.participants": "Показати учасників",
+ "tooltip.login": "Увійти",
+ "tooltip.logout": "Вихід",
+ "tooltip.admitFromLobby": "Вхід із залу очікувань",
+ "tooltip.lockRoom": "Заблокувати кімнату",
+ "tooltip.unLockRoom": "Розблокувати кімнату",
+ "tooltip.enterFullscreen": "Вивести повний екран",
+ "tooltip.leaveFullscreen": "Залишити повноекранний екран",
+ "tooltip.lobby": "Показати зал очікувань",
+ "tooltip.settings": "Показати налаштування",
+ "tooltip.participants": "Показати учасників",
-"label.roomName": "Назва кімнати",
-"label.chooseRoomButton": "Продовжити",
-"label.yourName": "Ваше ім'я",
-"label.newWindow": "Нове вікно",
-"label.fullscreen": "Повний екран",
-"label.openDrawer": "Відкрити ящик",
-"label.leave": "Залишити",
-"label.chatInput": "Введіть повідомлення чату ...",
-"label.chat": "Чат",
-"label.filesharing": "Обмін файлами",
-"label.participants": "Учасники",
-"label.shareFile": "Надіслати файл",
-"label.fileSharingUnsupported": "Обмін файлами не підтримується",
-"label.unknown": "Невідомо",
-"label.democrat": "Демократичний вигляд",
-"label.filmstrip": "У вигляді кінострічки",
-"label.low": "Низький",
-"label.medium": "Середній",
-"label.high": "Високий (HD)",
-"label.veryHigh": "Дуже високий (FHD)",
-"label.ultra": "Ультра (UHD)",
-"label.close": "Закрити",
+ "label.roomName": "Назва кімнати",
+ "label.chooseRoomButton": "Продовжити",
+ "label.yourName": "Ваше ім'я",
+ "label.newWindow": "Нове вікно",
+ "label.fullscreen": "Повний екран",
+ "label.openDrawer": "Відкрити ящик",
+ "label.leave": "Залишити",
+ "label.chatInput": "Введіть повідомлення чату ...",
+ "label.chat": "Чат",
+ "label.filesharing": "Обмін файлами",
+ "label.participants": "Учасники",
+ "label.shareFile": "Надіслати файл",
+ "label.fileSharingUnsupported": "Обмін файлами не підтримується",
+ "label.unknown": "Невідомо",
+ "label.democrat": "Демократичний вигляд",
+ "label.filmstrip": "У вигляді кінострічки",
+ "label.low": "Низький",
+ "label.medium": "Середній",
+ "label.high": "Високий (HD)",
+ "label.veryHigh": "Дуже високий (FHD)",
+ "label.ultra": "Ультра (UHD)",
+ "label.close": "Закрити",
-"settings.settings": "Налаштування",
-"settings.camera": "Камера",
-"settings.selectCamera": "Вибрати відеопристрій",
-"settings.cantSelectCamera": "Неможливо вибрати відеопристрій",
-"settings.audio": "Аудіопристрій",
-"settings.selectAudio": "Вибрати аудіопристрій",
-"settings.cantSelectAudio": "Неможливо вибрати аудіопристрій",
-"settings.resolution": "Виберіть роздільну здатність відео",
-"settings.layout": "Розміщення кімнати",
-"settings.selectRoomLayout": "Вибір розташування кімнати",
-"settings.advancedMode": "Розширений режим",
-"settings.permanentTopBar": "Постійний верхній рядок",
-"settings.lastn": "Кількість видимих відео",
+ "settings.settings": "Налаштування",
+ "settings.camera": "Камера",
+ "settings.selectCamera": "Вибрати відеопристрій",
+ "settings.cantSelectCamera": "Неможливо вибрати відеопристрій",
+ "settings.audio": "Аудіопристрій",
+ "settings.selectAudio": "Вибрати аудіопристрій",
+ "settings.cantSelectAudio": "Неможливо вибрати аудіопристрій",
+ "settings.resolution": "Виберіть роздільну здатність відео",
+ "settings.layout": "Розміщення кімнати",
+ "settings.selectRoomLayout": "Вибір розташування кімнати",
+ "settings.advancedMode": "Розширений режим",
+ "settings.permanentTopBar": "Постійний верхній рядок",
+ "settings.lastn": "Кількість видимих відео",
-"filesharing.saveFileError": "Неможливо зберегти файл",
-"filesharing.startingFileShare": "Спроба поділитися файлом",
-"filesharing.successfulFileShare": "Файл готовий для обміну",
-"filesharing.unableToShare": "Неможливо поділитися файлом",
-"filesharing.error": "Виникла помилка обміну файлами",
-"filesharing.finished": "Завантаження файлу закінчено",
-"filesharing.save": "Зберегти",
-"filesharing.sharedFile": "{displayName} поділився файлом",
-"filesharing.download": "Завантажити",
-"filesharing.missingSeeds": "Якщо цей процес триває тривалий час, може не з’явиться хтось, хто роздає цей торрент. Спробуйте попросити когось перезавантажити потрібний файл.",
+ "filesharing.saveFileError": "Неможливо зберегти файл",
+ "filesharing.startingFileShare": "Спроба поділитися файлом",
+ "filesharing.successfulFileShare": "Файл готовий для обміну",
+ "filesharing.unableToShare": "Неможливо поділитися файлом",
+ "filesharing.error": "Виникла помилка обміну файлами",
+ "filesharing.finished": "Завантаження файлу закінчено",
+ "filesharing.save": "Зберегти",
+ "filesharing.sharedFile": "{displayName} поділився файлом",
+ "filesharing.download": "Завантажити",
+ "filesharing.missingSeeds": "Якщо цей процес триває тривалий час, може не з’явиться хтось, хто роздає цей торрент. Спробуйте попросити когось перезавантажити потрібний файл.",
-"devices.devicesChanged": "Ваші пристрої змінилися, налаштуйте ваші пристрої в діалоговому вікні налаштувань",
+ "devices.devicesChanged": "Ваші пристрої змінилися, налаштуйте ваші пристрої в діалоговому вікні налаштувань",
-"device.audioUnsupported": "Аудіо не підтримується",
-"device.activateAudio": "Активувати звук",
-"device.muteAudio": "Вимкнути звук",
-"device.unMuteAudio": "Увімкнути звук",
+ "device.audioUnsupported": "Аудіо не підтримується",
+ "device.activateAudio": "Активувати звук",
+ "device.muteAudio": "Вимкнути звук",
+ "device.unMuteAudio": "Увімкнути звук",
-"device.videoUnsupported": "Відео не підтримується",
-"device.startVideo": "Запустити відео",
-"device.stopVideo": "Зупинити відео",
+ "device.videoUnsupported": "Відео не підтримується",
+ "device.startVideo": "Запустити відео",
+ "device.stopVideo": "Зупинити відео",
-"device.screenSharingUnsupported": "Обмін екраном не підтримується",
-"device.startScreenSharing": "Початок спільного використання екрана",
-"device.stopScreenSharing": "Зупинити спільний доступ до екрана",
+ "device.screenSharingUnsupported": "Обмін екраном не підтримується",
+ "device.startScreenSharing": "Початок спільного використання екрана",
+ "device.stopScreenSharing": "Зупинити спільний доступ до екрана",
-"devices.microphoneDisconnected": "Мікрофон відключений",
-"devices.microphoneError": "Сталася помилка під час доступу до мікрофона",
-"devices.microPhoneMute": "Вимкнено ваш мікрофон",
-"devices.micophoneUnMute": "Не ввімкнено ваш мікрофон",
-"devices.microphoneEnable": "Увімкнено мікрофон",
-"devices.microphoneMuteError": "Не вдається вимкнути мікрофон",
-"devices.microphoneUnMuteError": "Неможливо ввімкнути мікрофон",
+ "devices.microphoneDisconnected": "Мікрофон відключений",
+ "devices.microphoneError": "Сталася помилка під час доступу до мікрофона",
+ "devices.microPhoneMute": "Вимкнено ваш мікрофон",
+ "devices.micophoneUnMute": "Не ввімкнено ваш мікрофон",
+ "devices.microphoneEnable": "Увімкнено мікрофон",
+ "devices.microphoneMuteError": "Не вдається вимкнути мікрофон",
+ "devices.microphoneUnMuteError": "Неможливо ввімкнути мікрофон",
-"devices.screenSharingDisconnected": "Спільний доступ до екрана відключений",
-"devices.screenSharingError": "Сталася помилка під час доступу до екрану",
+ "devices.screenSharingDisconnected": "Спільний доступ до екрана відключений",
+ "devices.screenSharingError": "Сталася помилка під час доступу до екрану",
-"devices.cameraDisconnected": "Камера відключена",
-"devices.cameraError": "Під час доступу до камери сталася помилка"
+ "devices.cameraDisconnected": "Камера відключена",
+ "devices.cameraError": "Під час доступу до камери сталася помилка",
+
+ "moderator.clearChat": null,
+ "moderator.muteAudio": null,
+ "moderator.muteVideo": null
}
\ No newline at end of file
diff --git a/server/config/config.example.js b/server/config/config.example.js
index 32ca836..6b030e1 100644
--- a/server/config/config.example.js
+++ b/server/config/config.example.js
@@ -229,6 +229,8 @@ module.exports =
PROMOTE_PEER : [ userRoles.NORMAL ],
// The role(s) have permission to send chat messages
SEND_CHAT : [ userRoles.NORMAL ],
+ // The role(s) have permission to moderate chat
+ MODERATE_CHAT : [ userRoles.MODERATOR ],
// The role(s) have permission to share screen
SHARE_SCREEN : [ userRoles.NORMAL ],
// The role(s) have permission to share files
diff --git a/server/lib/Room.js b/server/lib/Room.js
index b436671..8bbedf1 100644
--- a/server/lib/Room.js
+++ b/server/lib/Room.js
@@ -1005,6 +1005,24 @@ class Room extends EventEmitter
break;
}
+ case 'moderator:clearChat':
+ {
+ if (
+ !peer.roles.some((role) => config.permissionsFromRoles.MODERATE_CHAT.includes(role))
+ )
+ throw new Error('peer not authorized');
+
+ this._chatHistory = [];
+
+ // Spread to others
+ this._notification(peer.socket, 'moderator:clearChat', null, true);
+
+ // Return no error
+ cb();
+
+ break;
+ }
+
case 'serverHistory':
{
// Return to sender
@@ -1186,9 +1204,7 @@ class Room extends EventEmitter
throw new Error('peer not authorized');
// Spread to others
- this._notification(peer.socket, 'moderator:mute', {
- peerId : peer.id
- }, true);
+ this._notification(peer.socket, 'moderator:mute', null, true);
cb();
@@ -1203,9 +1219,7 @@ class Room extends EventEmitter
throw new Error('peer not authorized');
// Spread to others
- this._notification(peer.socket, 'moderator:stopVideo', {
- peerId : peer.id
- }, true);
+ this._notification(peer.socket, 'moderator:stopVideo', null, true);
cb();
@@ -1219,12 +1233,7 @@ class Room extends EventEmitter
)
throw new Error('peer not authorized');
- this._notification(
- peer.socket,
- 'moderator:kick',
- null,
- true
- );
+ this._notification(peer.socket, 'moderator:kick', null, true);
cb();
@@ -1248,10 +1257,7 @@ class Room extends EventEmitter
if (!kickPeer)
throw new Error(`peer with id "${peerId}" not found`);
- this._notification(
- kickPeer.socket,
- 'moderator:kick'
- );
+ this._notification(kickPeer.socket, 'moderator:kick');
kickPeer.close();
diff --git a/server/server.js b/server/server.js
index e2eeb5b..c28eda8 100755
--- a/server/server.js
+++ b/server/server.js
@@ -38,8 +38,8 @@ const promExporter = require('./lib/promExporter');
/* eslint-disable no-console */
console.log('- process.env.DEBUG:', process.env.DEBUG);
-console.log('- config.mediasoup.logLevel:', config.mediasoup.logLevel);
-console.log('- config.mediasoup.logTags:', config.mediasoup.logTags);
+console.log('- config.mediasoup.worker.logLevel:', config.mediasoup.worker.logLevel);
+console.log('- config.mediasoup.worker.logTags:', config.mediasoup.worker.logTags);
/* eslint-enable no-console */
const logger = new Logger();