User information lookup feature in HTML5 client.
This commit is contained in:
parent
2d5d23f75f
commit
3fa22c6908
@ -11,6 +11,7 @@ import clearPolls from '/imports/api/polls/server/modifiers/clearPolls';
|
||||
import clearCaptions from '/imports/api/captions/server/modifiers/clearCaptions';
|
||||
import clearPresentationPods from '/imports/api/presentation-pods/server/modifiers/clearPresentationPods';
|
||||
import clearVoiceUsers from '/imports/api/voice-users/server/modifiers/clearVoiceUsers';
|
||||
import clearUserInfo from '/imports/api/users-infos/server/modifiers/clearUserInfo';
|
||||
|
||||
|
||||
export default function removeMeeting(meetingId) {
|
||||
@ -25,6 +26,7 @@ export default function removeMeeting(meetingId) {
|
||||
clearUsers(meetingId);
|
||||
clearUsersSettings(meetingId);
|
||||
clearVoiceUsers(meetingId);
|
||||
clearUserInfo(meetingId);
|
||||
|
||||
return Logger.info(`Cleared Meetings with id ${meetingId}`);
|
||||
});
|
||||
|
9
bigbluebutton-html5/imports/api/users-infos/index.js
Normal file
9
bigbluebutton-html5/imports/api/users-infos/index.js
Normal file
@ -0,0 +1,9 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
const UserInfos = new Mongo.Collection('users-infos');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
UserInfos._ensureIndex({ meetingId: 1, userId: 1 });
|
||||
}
|
||||
|
||||
export default UserInfos;
|
@ -0,0 +1,4 @@
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import handleUserInformation from './handlers/userInformation';
|
||||
|
||||
RedisPubSub.on('LookUpUserRespMsg', handleUserInformation);
|
@ -0,0 +1,8 @@
|
||||
import { check } from 'meteor/check';
|
||||
import addUserInfo from '../modifiers/addUserInfo';
|
||||
|
||||
export default function handleUserInformation({ header, body }, meetingId) {
|
||||
check(body, Object);
|
||||
|
||||
return addUserInfo(body.userInfo, header.userId, header.meetingId);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import './eventHandlers';
|
||||
import './methods';
|
||||
import './publishers';
|
@ -0,0 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import requestUserInformation from './methods/requestUserInformation';
|
||||
import removeUserInformation from './methods/removeUserInformation';
|
||||
|
||||
Meteor.methods({
|
||||
requestUserInformation,
|
||||
removeUserInformation,
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function removeUserInformation(credentials, meetingId, requesterUserId) {
|
||||
const selector = {
|
||||
meetingId,
|
||||
requesterUserId,
|
||||
};
|
||||
const cb = (err, numChanged) => {
|
||||
if (err) {
|
||||
return Logger.error(`Removing user information from collection: ${err}`);
|
||||
}
|
||||
return Logger.info(`Removed user information: requester id=${requesterUserId} meeting=${meetingId}`);
|
||||
};
|
||||
return UserInfos.remove(selector, cb);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import Users from '/imports/api/users';
|
||||
|
||||
export default function getUserInformation(credentials, externalUserId) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toThirdParty;
|
||||
const EVENT_NAME = 'LookUpUserReqMsg';
|
||||
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
check(externalUserId, String);
|
||||
|
||||
const payload = {
|
||||
externalUserId,
|
||||
};
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function addUserInfo(userInfo, requesterUserId, meetingId) {
|
||||
const info = {
|
||||
meetingId,
|
||||
requesterUserId,
|
||||
userInfo,
|
||||
};
|
||||
const cb = (err, numChanged) => {
|
||||
if (err) {
|
||||
return Logger.error(`Adding user information to collection: ${err}`);
|
||||
}
|
||||
return Logger.info(`Added user information: requester id=${requesterUserId} meeting=${meetingId}`);
|
||||
};
|
||||
|
||||
return UserInfos.insert(info, cb);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function clearUsersInfo(meetingId) {
|
||||
return UserInfos.remove({ meetingId }, () => {
|
||||
Logger.info(`Cleared User Infos (${meetingId})`);
|
||||
});
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function clearUsersInfoForRequester(meetingId, requesterUserId) {
|
||||
return UserInfos.remove({ meetingId }, () => {
|
||||
Logger.info(`Cleared User Infos requested by user=${requesterUserId}`);
|
||||
});
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
function userInfos(credentials) {
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
|
||||
Logger.debug(`Publishing user infos requested by user=${requesterUserId}`);
|
||||
|
||||
return UserInfos.find({ meetingId, requesterUserId });
|
||||
}
|
||||
|
||||
function publish(...args) {
|
||||
const boundUserInfos = userInfos.bind(this);
|
||||
return boundUserInfos(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('users-infos', publish);
|
@ -2,6 +2,7 @@ import { check } from 'meteor/check';
|
||||
import Users from '/imports/api/users';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import stopWatchingExternalVideo from '/imports/api/external-videos/server/methods/stopWatchingExternalVideo';
|
||||
import clearUserInfoForRequester from '/imports/api/users-infos/server/modifiers/clearUserInfoForRequester';
|
||||
|
||||
const clearAllSessions = (sessionUserId) => {
|
||||
const serverSessions = Meteor.server.sessions;
|
||||
@ -46,6 +47,8 @@ export default function removeUser(meetingId, userId) {
|
||||
const sessionUserId = `${meetingId}-${userId}`;
|
||||
clearAllSessions(sessionUserId);
|
||||
|
||||
clearUserInfoForRequester(meetingId, userId);
|
||||
|
||||
return Logger.info(`Removed user id=${userId} meeting=${meetingId}`);
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import Users from '/imports/api/users';
|
||||
import clearUserInfoForRequester from '/imports/api/users-infos/server/modifiers/clearUserInfoForRequester';
|
||||
|
||||
export default function userEjected(meetingId, userId) {
|
||||
check(meetingId, String);
|
||||
@ -23,6 +24,7 @@ export default function userEjected(meetingId, userId) {
|
||||
}
|
||||
|
||||
if (numChanged) {
|
||||
clearUserInfoForRequester(meetingId, userId);
|
||||
return Logger.info(`Ejected user id=${userId} meeting=${meetingId}`);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import Settings from '/imports/ui/services/settings';
|
||||
import AudioManager from '/imports/ui/services/audio-manager';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import Users from '/imports/api/users';
|
||||
import UserInfos from '/imports/api/users-infos';
|
||||
import Annotations from '/imports/api/annotations';
|
||||
import AnnotationsLocal from '/imports/ui/components/whiteboard/service';
|
||||
import GroupChat from '/imports/api/group-chat';
|
||||
@ -159,7 +160,7 @@ Base.defaultProps = defaultProps;
|
||||
const SUBSCRIPTIONS_NAME = [
|
||||
'users', 'meetings', 'polls', 'presentations',
|
||||
'slides', 'captions', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
|
||||
'group-chat', 'presentation-pods', 'users-settings', 'guestUser',
|
||||
'group-chat', 'presentation-pods', 'users-settings', 'guestUser', 'users-infos',
|
||||
];
|
||||
|
||||
const BaseContainer = withTracker(() => {
|
||||
@ -168,6 +169,7 @@ const BaseContainer = withTracker(() => {
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
let breakoutRoomSubscriptionHandler;
|
||||
let userSubscriptionHandler;
|
||||
let userInfoSubscriptionHandler;
|
||||
|
||||
const subscriptionErrorHandler = {
|
||||
onError: (error) => {
|
||||
@ -204,8 +206,12 @@ const BaseContainer = withTracker(() => {
|
||||
// override meteor subscription to verify if is moderator
|
||||
userSubscriptionHandler = Meteor.subscribe('users', credentials, mappedUser.isModerator, subscriptionErrorHandler);
|
||||
breakoutRoomSubscriptionHandler = Meteor.subscribe('breakouts', credentials, mappedUser.isModerator, subscriptionErrorHandler);
|
||||
|
||||
userInfoSubscriptionhandler = Meteor.subscribe('users-infos', credentials, subscriptionErrorHandler);
|
||||
}
|
||||
|
||||
const UserInfo = UserInfos.find({ meetingId, requesterUserId }).fetch();
|
||||
|
||||
const annotationsHandler = Meteor.subscribe('annotations', credentials, {
|
||||
onReady: () => {
|
||||
AnnotationsLocal.remove({});
|
||||
@ -230,10 +236,12 @@ const BaseContainer = withTracker(() => {
|
||||
annotationsHandler,
|
||||
groupChatMessageHandler,
|
||||
userSubscriptionHandler,
|
||||
userInfoSubscriptionHandler,
|
||||
breakoutRoomSubscriptionHandler,
|
||||
animations,
|
||||
meetingExist: !!Meetings.find({ meetingId }).count(),
|
||||
User,
|
||||
UserInfo,
|
||||
meteorIsConnected: Meteor.status().connected,
|
||||
};
|
||||
})(Base);
|
||||
|
@ -8,11 +8,11 @@ import Logger from './logger';
|
||||
// Fake meetingId used for messages that have no meetingId
|
||||
const NO_MEETING_ID = '_';
|
||||
|
||||
const makeEnvelope = (channel, eventName, header, body) => {
|
||||
const makeEnvelope = (channel, eventName, header, body, routing) => {
|
||||
const envelope = {
|
||||
envelope: {
|
||||
name: eventName,
|
||||
routing: {
|
||||
routing: routing || {
|
||||
sender: 'bbb-apps-akka',
|
||||
// sender: 'html5-server', // TODO
|
||||
},
|
||||
@ -227,7 +227,7 @@ class RedisPubSub {
|
||||
userId,
|
||||
};
|
||||
|
||||
const envelope = makeEnvelope(channel, eventName, header, payload);
|
||||
const envelope = makeEnvelope(channel, eventName, header, payload, { meetingId, userId });
|
||||
|
||||
return this.pub.publish(channel, envelope, RedisPubSub.handlePublishError);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import PanelManager from '/imports/ui/components/panel-manager/component';
|
||||
import PollingContainer from '/imports/ui/components/polling/container';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import ActivityCheckContainer from '/imports/ui/components/activity-check/container';
|
||||
import UserInfoContainer from '/imports/ui/components/user-info/container';
|
||||
import ToastContainer from '../toast/container';
|
||||
import ModalContainer from '../modal/container';
|
||||
import NotificationsBarContainer from '../notifications-bar/container';
|
||||
@ -206,6 +207,17 @@ class App extends Component {
|
||||
/>) : null);
|
||||
}
|
||||
|
||||
renderUserInformation() {
|
||||
const { UserInfo, User } = this.props;
|
||||
|
||||
return (UserInfo.length > 0 ? (
|
||||
<UserInfoContainer
|
||||
UserInfo={UserInfo}
|
||||
requesterUserId={User.userId}
|
||||
meetingId={User.meetingId}
|
||||
/>) : null);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
customStyle, customStyleUrl, openPanel,
|
||||
@ -214,6 +226,7 @@ class App extends Component {
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
{this.renderActivityCheck()}
|
||||
{this.renderUserInformation()}
|
||||
<NotificationsBarContainer />
|
||||
<section className={styles.wrapper}>
|
||||
<div className={openPanel ? styles.content : styles.noPanelContent}>
|
||||
|
@ -0,0 +1,75 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, intlShape } from 'react-intl';
|
||||
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Modal from '/imports/ui/components/modal/simple/component';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
|
||||
import { styles } from './styles';
|
||||
|
||||
const propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
title: {
|
||||
id: 'app.user-info.title',
|
||||
description: 'User info title label',
|
||||
},
|
||||
});
|
||||
|
||||
class UserInfo extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleCloseUserInfo = this.handleCloseUserInfo.bind(this);
|
||||
}
|
||||
|
||||
handleCloseUserInfo() {
|
||||
const { mountModal, requesterUserId, meetingId } = this.props;
|
||||
makeCall('removeUserInformation', meetingId, requesterUserId);
|
||||
}
|
||||
|
||||
renderUserInfo(UserInfo) {
|
||||
const userInfoList = UserInfo.map((user, index, array) => {
|
||||
const infoList = user.userInfo.map((info) => {
|
||||
const key = Object.keys(info)[0];
|
||||
return (
|
||||
<tr key={key}>
|
||||
<td className={styles.keyCell}>{key}</td>
|
||||
<td className={styles.valueCell}>{info[key]}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
if (array.length > 1) {
|
||||
infoList.unshift(<tr key={infoList.length}>
|
||||
<th className={styles.titleCell}>{`User ${index + 1}`}</th>
|
||||
</tr>);
|
||||
}
|
||||
return infoList;
|
||||
});
|
||||
return (
|
||||
<table className={styles.userInfoTable}>
|
||||
<tbody>
|
||||
{userInfoList}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, UserInfo } = this.props;
|
||||
return (
|
||||
<Modal
|
||||
title={intl.formatMessage(intlMessages.title)}
|
||||
onRequestClose={this.handleCloseUserInfo}
|
||||
>
|
||||
{this.renderUserInfo(UserInfo)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserInfo.propTypes = propTypes;
|
||||
|
||||
export default UserInfo;
|
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import UserInfo from './component';
|
||||
|
||||
const UserInfoContainer = props => <UserInfo {...props} />;
|
||||
|
||||
export default injectIntl(UserInfoContainer);
|
@ -0,0 +1,24 @@
|
||||
@import "/imports/ui/stylesheets/variables/_all";
|
||||
|
||||
.keyCell, .valueCell, .userInfoTable {
|
||||
border: var(--border-size) solid var(--color-gray-lighter);
|
||||
}
|
||||
|
||||
.userInfoTable {
|
||||
border-collapse: collapse;
|
||||
border: none;
|
||||
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
|
||||
table-layout: fixed;
|
||||
|
||||
td {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.keyCell, .valueCell {
|
||||
padding: var(--md-padding-x);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ const propTypes = {
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
showBranding: PropTypes.bool.isRequired,
|
||||
toggleUserLock: PropTypes.func.isRequired,
|
||||
requestUserInformation: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -69,6 +70,7 @@ class UserList extends PureComponent {
|
||||
getUsersId,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -106,6 +108,7 @@ class UserList extends PureComponent {
|
||||
getUsersId,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
}
|
||||
}
|
||||
/>}
|
||||
|
@ -25,6 +25,7 @@ const propTypes = {
|
||||
roving: PropTypes.func.isRequired,
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
toggleUserLock: PropTypes.func.isRequired,
|
||||
requestUserInformation: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const UserListContainer = props => <UserList {...props} />;
|
||||
@ -58,4 +59,5 @@ export default withTracker(({ chatID, compact }) => ({
|
||||
showBranding: getFromUserSettings('displayBrandingArea', Meteor.settings.public.app.branding.displayBrandingArea),
|
||||
hasPrivateChatBetweenUsers: Service.hasPrivateChatBetweenUsers,
|
||||
toggleUserLock: Service.toggleUserLock,
|
||||
requestUserInformation: Service.requestUserInformation,
|
||||
}))(UserListContainer);
|
||||
|
@ -461,6 +461,10 @@ const toggleUserLock = (userId, lockStatus) => {
|
||||
makeCall('toggleUserLock', userId, lockStatus);
|
||||
};
|
||||
|
||||
const requestUserInformation = (userId) => {
|
||||
makeCall('requestUserInformation', userId);
|
||||
};
|
||||
|
||||
export default {
|
||||
setEmojiStatus,
|
||||
assignPresenter,
|
||||
@ -487,4 +491,5 @@ export default {
|
||||
getEmoji: () => Users.findOne({ userId: Auth.userID }).emoji,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
};
|
||||
|
@ -34,6 +34,7 @@ const propTypes = {
|
||||
pollIsOpen: PropTypes.bool.isRequired,
|
||||
forcePollOpen: PropTypes.bool.isRequired,
|
||||
toggleUserLock: PropTypes.func.isRequired,
|
||||
requestUserInformation: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -72,6 +73,7 @@ class UserContent extends PureComponent {
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
pendingUsers,
|
||||
requestUserInformation,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -136,6 +138,7 @@ class UserContent extends PureComponent {
|
||||
getUsersId,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -32,6 +32,7 @@ const propTypes = {
|
||||
isMeetingLocked: PropTypes.func.isRequired,
|
||||
roving: PropTypes.func.isRequired,
|
||||
toggleUserLock: PropTypes.func.isRequired,
|
||||
requestUserInformation: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -128,6 +129,7 @@ class UserParticipants extends Component {
|
||||
users,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
} = this.props;
|
||||
|
||||
let index = -1;
|
||||
@ -164,6 +166,7 @@ class UserParticipants extends Component {
|
||||
getGroupChatPrivate,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
}}
|
||||
userId={u}
|
||||
getScrollContainerRef={this.getScrollContainerRef}
|
||||
|
@ -49,6 +49,7 @@ class UserListItem extends PureComponent {
|
||||
toggleVoice,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
} = this.props;
|
||||
|
||||
const { meetingId, lockSettingsProp } = meeting;
|
||||
@ -78,6 +79,7 @@ class UserListItem extends PureComponent {
|
||||
user,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -89,6 +89,10 @@ const messages = defineMessages({
|
||||
id: 'app.userList.menu.lockUser.label',
|
||||
description: 'Lock a unlocked user',
|
||||
},
|
||||
DirectoryLookupLabel: {
|
||||
id: 'app.userList.menu.directoryLookup.label',
|
||||
description: 'Directory lookup',
|
||||
},
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
@ -201,6 +205,7 @@ class UserDropdown extends PureComponent {
|
||||
lockSettingsProp,
|
||||
hasPrivateChatBetweenUsers,
|
||||
toggleUserLock,
|
||||
requestUserInformation,
|
||||
} = this.props;
|
||||
|
||||
const { showNestedOptions } = this.state;
|
||||
@ -230,6 +235,8 @@ class UserDropdown extends PureComponent {
|
||||
|| hasPrivateChatBetweenUsers(currentUser, user)
|
||||
|| user.isModerator);
|
||||
|
||||
const allowUserLookup = Meteor.settings.public.app.allowUserLookup;
|
||||
|
||||
if (showNestedOptions) {
|
||||
if (allowedToChangeStatus) {
|
||||
actions.push(this.makeDropdownItem(
|
||||
@ -349,6 +356,15 @@ class UserDropdown extends PureComponent {
|
||||
));
|
||||
}
|
||||
|
||||
if (allowUserLookup) {
|
||||
actions.push(this.makeDropdownItem(
|
||||
'directoryLookup',
|
||||
intl.formatMessage(messages.DirectoryLookupLabel),
|
||||
() => this.onActionsHide(requestUserInformation(user.externalUserId)),
|
||||
'user',
|
||||
));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ const mapUser = (user) => {
|
||||
isOnline: user.connectionStatus === 'online',
|
||||
clientType: user.clientType,
|
||||
loginTime: user.loginTime,
|
||||
externalUserId: user.extId,
|
||||
};
|
||||
|
||||
mappedUser.isLocked = user.locked && !(mappedUser.isPresenter || mappedUser.isModerator);
|
||||
|
@ -17,6 +17,7 @@ public:
|
||||
lockOnJoin: true
|
||||
basename: "/html5client"
|
||||
askForFeedbackOnLogout: false
|
||||
allowUserLookup: false
|
||||
defaultSettings:
|
||||
application:
|
||||
animations: true
|
||||
@ -265,9 +266,11 @@ private:
|
||||
debug: false
|
||||
channels:
|
||||
toAkkaApps: to-akka-apps-redis-channel
|
||||
toThirdParty: to-third-party-redis-channel
|
||||
subscribeTo:
|
||||
- to-html5-redis-channel
|
||||
- from-akka-apps-*
|
||||
- from-third-party-redis-channel
|
||||
async:
|
||||
- from-akka-apps-wb-redis-channel
|
||||
ignored:
|
||||
|
@ -49,6 +49,7 @@
|
||||
"app.userList.menu.demoteUser.label": "Demote to viewer",
|
||||
"app.userList.menu.unlockUser.label": "Unlock {0}",
|
||||
"app.userList.menu.lockUser.label": "Lock {0}",
|
||||
"app.userList.menu.directoryLookup.label": "Directory Lookup",
|
||||
"app.userList.userOptions.manageUsersLabel": "Manage users",
|
||||
"app.userList.userOptions.muteAllLabel": "Mute all users",
|
||||
"app.userList.userOptions.muteAllDesc": "Mutes all users in the meeting",
|
||||
@ -392,6 +393,7 @@
|
||||
"app.userList.guest.pendingUsers": "{0} Pending Users",
|
||||
"app.userList.guest.pendingGuestUsers": "{0} Pending Guest Users",
|
||||
"app.userList.guest.pendingGuestAlert": "Has joined the session and is waiting for your approval.",
|
||||
"app.user-info.title": "Directory Lookup",
|
||||
"app.toast.breakoutRoomEnded": "The breakout room ended. Please rejoin in the audio.",
|
||||
"app.toast.chat.public": "New Public Chat message",
|
||||
"app.toast.chat.private": "New Private Chat message",
|
||||
|
@ -19,6 +19,7 @@ import '/imports/api/users-settings/server';
|
||||
import '/imports/api/voice-users/server';
|
||||
import '/imports/api/whiteboard-multi-user/server';
|
||||
import '/imports/api/video/server';
|
||||
import '/imports/api/users-infos/server';
|
||||
|
||||
import '/imports/api/external-videos/server';
|
||||
import '/imports/api/guest-users/server';
|
||||
|
Loading…
Reference in New Issue
Block a user