bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/user-list/service.js

793 lines
22 KiB
JavaScript
Raw Normal View History

import React from 'react';
import Users from '/imports/api/users';
import VoiceUsers from '/imports/api/voice-users';
import GroupChat from '/imports/api/group-chat';
import Breakouts from '/imports/api/breakouts';
import Meetings from '/imports/api/meetings';
2016-07-07 20:50:32 +08:00
import Auth from '/imports/ui/services/auth';
2017-03-01 06:40:16 +08:00
import Storage from '/imports/ui/services/storage/session';
import { EMOJI_STATUSES } from '/imports/utils/statuses';
import { makeCall } from '/imports/ui/services/api';
import KEY_CODES from '/imports/utils/keyCodes';
import AudioService from '/imports/ui/components/audio/service';
import VideoService from '/imports/ui/components/video-provider/service';
import logger from '/imports/startup/client/logger';
import WhiteboardService from '/imports/ui/components/whiteboard/service';
2021-05-21 20:17:24 +08:00
import { Session } from 'meteor/session';
import Settings from '/imports/ui/services/settings';
import { notify } from '/imports/ui/services/notification';
import { FormattedMessage } from 'react-intl';
import { getDateString } from '/imports/utils/string-utils';
2023-02-23 20:45:30 +08:00
import { indexOf, without } from '/imports/utils/array-utils';
2023-03-01 21:39:04 +08:00
import { isEmpty, throttle } from 'radash';
2016-06-07 00:45:30 +08:00
const CHAT_CONFIG = Meteor.settings.public.chat;
2021-05-18 04:25:07 +08:00
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
const ROLE_VIEWER = Meteor.settings.public.user.role_viewer;
2016-06-07 00:45:30 +08:00
const DIAL_IN_CLIENT_TYPE = 'dial-in-user';
// session for closed chat list
const CLOSED_CHAT_LIST_KEY = 'closedChatList';
// session for chats the current user started
const STARTED_CHAT_LIST_KEY = 'startedChatList';
2018-03-21 03:35:28 +08:00
const CUSTOM_LOGO_URL_KEY = 'CustomLogoUrl';
2021-12-08 00:22:11 +08:00
export const setCustomLogoUrl = (path) => Storage.setItem(CUSTOM_LOGO_URL_KEY, path);
2018-03-21 03:35:28 +08:00
2021-12-08 00:22:11 +08:00
export const setModeratorOnlyMessage = (msg) => Storage.setItem('ModeratorOnlyMessage', msg);
2018-03-21 03:35:28 +08:00
const getCustomLogoUrl = () => Storage.getItem(CUSTOM_LOGO_URL_KEY);
const sortByWhiteboardAccess = (a, b) => {
const _a = a.whiteboardAccess;
const _b = b.whiteboardAccess;
if (!_b && _a) return -1;
if (!_a && _b) return 1;
return 0;
};
const sortUsersByUserId = (a, b) => {
if (a.userId > b.userId) {
2016-06-07 00:45:30 +08:00
return -1;
} if (a.userId < b.userId) {
2016-06-07 00:45:30 +08:00
return 1;
2016-06-07 21:58:51 +08:00
}
return 0;
};
const sortUsersByName = (a, b) => {
2022-12-14 02:00:13 +08:00
const aName = a.sortName || '';
const bName = b.sortName || '';
// Extending for sorting strings with non-ASCII characters
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#sorting_non-ascii_characters
return aName.localeCompare(bName);
};
2016-06-07 21:58:51 +08:00
const sortUsersByEmoji = (a, b) => {
if (a.emoji && b.emoji && (a.emoji !== 'none' && b.emoji !== 'none')) {
if (a.emojiTime < b.emojiTime) {
return -1;
} if (a.emojiTime > b.emojiTime) {
return 1;
}
} if (a.emoji && a.emoji !== 'none') {
2016-06-07 00:45:30 +08:00
return -1;
} if (b.emoji && b.emoji !== 'none') {
2016-06-07 00:45:30 +08:00
return 1;
}
2016-06-07 21:58:51 +08:00
return 0;
};
const sortUsersByModerator = (a, b) => {
if (a.role === ROLE_MODERATOR && b.role === ROLE_MODERATOR) {
return 0;
} if (a.role === ROLE_MODERATOR) {
2016-06-07 00:45:30 +08:00
return -1;
} if (b.role === ROLE_MODERATOR) {
2016-06-07 00:45:30 +08:00
return 1;
2016-06-07 21:58:51 +08:00
}
return 0;
};
const sortUsersByPhoneUser = (a, b) => {
if (!a.clientType === DIAL_IN_CLIENT_TYPE && !b.clientType === DIAL_IN_CLIENT_TYPE) {
2017-12-12 23:03:33 +08:00
return 0;
} if (!a.clientType === DIAL_IN_CLIENT_TYPE) {
2016-06-07 00:45:30 +08:00
return -1;
} if (!b.clientType === DIAL_IN_CLIENT_TYPE) {
2016-06-07 00:45:30 +08:00
return 1;
}
return 0;
};
// current user's name is always on top
const sortUsersByCurrent = (a, b) => {
if (a.userId === Auth.userID) {
return -1;
} if (b.userId === Auth.userID) {
2018-07-05 01:51:59 +08:00
return 1;
}
return 0;
};
2016-06-07 21:58:51 +08:00
const sortUsers = (a, b) => {
let sort = sortUsersByCurrent(a, b);
if (sort === 0) {
sort = sortUsersByModerator(a, b);
}
2016-06-07 21:58:51 +08:00
if (sort === 0) {
sort = sortUsersByEmoji(a, b);
2016-06-07 21:58:51 +08:00
}
if (sort === 0) {
sort = sortUsersByPhoneUser(a, b);
}
if (sort === 0) {
sort = sortByWhiteboardAccess(a, b);
}
2016-06-07 21:58:51 +08:00
if (sort === 0) {
sort = sortUsersByName(a, b);
}
if (sort === 0) {
sort = sortUsersByUserId(a, b);
}
2016-06-07 21:58:51 +08:00
return sort;
};
2021-05-18 04:25:07 +08:00
const isPublicChat = (chat) => (
chat.userId === PUBLIC_CHAT_ID
);
2016-06-28 21:10:20 +08:00
const userFindSorting = {
2017-07-26 22:09:07 +08:00
emojiTime: 1,
role: 1,
phoneUser: 1,
name: 1,
2017-07-26 22:09:07 +08:00
userId: 1,
2016-06-28 21:10:20 +08:00
};
const addWhiteboardAccess = (users) => {
const whiteboardId = WhiteboardService.getCurrentWhiteboardId();
if (whiteboardId) {
const multiUserWhiteboard = WhiteboardService.getMultiUser(whiteboardId);
2021-05-18 04:25:07 +08:00
return users.map((user) => {
const whiteboardAccess = multiUserWhiteboard.includes(user.userId);
return {
...user,
whiteboardAccess,
};
});
}
2021-05-18 04:25:07 +08:00
return users.map((user) => {
const whiteboardAccess = false;
return {
...user,
whiteboardAccess,
};
});
};
const addIsSharingWebcam = (users) => {
const usersId = VideoService.getUsersIdFromVideoStreams();
return users.map((user) => {
const isSharingWebcam = usersId.includes(user.userId);
return {
...user,
isSharingWebcam,
};
});
};
2022-02-03 22:42:24 +08:00
const getUsers = () => {
let users = Users
.find({
meetingId: Auth.meetingID,
}, userFindSorting)
.fetch();
2016-06-07 00:45:30 +08:00
const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { role: 1, locked: 1 } });
if (currentUser && currentUser.role === ROLE_VIEWER && currentUser.locked) {
const meeting = Meetings.findOne({ meetingId: Auth.meetingID },
{ fields: { 'lockSettingsProps.hideUserList': 1 } });
if (meeting && meeting.lockSettingsProps && meeting.lockSettingsProps.hideUserList) {
2021-05-18 04:25:07 +08:00
const moderatorOrCurrentUser = (u) => u.role === ROLE_MODERATOR || u.userId === Auth.userID;
users = users.filter(moderatorOrCurrentUser);
}
}
return addIsSharingWebcam(addWhiteboardAccess(users)).sort(sortUsers);
2016-05-31 19:29:38 +08:00
};
2016-05-20 02:22:56 +08:00
2022-02-03 22:42:24 +08:00
const formatUsers = (contextUsers, videoUsers, whiteboardUsers) => {
2022-04-27 01:07:21 +08:00
let users = contextUsers.filter((user) => user.loggedOut === false && user.left === false);
2022-02-03 22:42:24 +08:00
const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { role: 1, locked: 1 } });
if (currentUser && currentUser.role === ROLE_VIEWER && currentUser.locked) {
const meeting = Meetings.findOne({ meetingId: Auth.meetingID },
{ fields: { 'lockSettingsProps.hideUserList': 1 } });
if (meeting && meeting.lockSettingsProps && meeting.lockSettingsProps.hideUserList) {
const moderatorOrCurrentUser = (u) => u.role === ROLE_MODERATOR || u.userId === Auth.userID;
users = users.filter(moderatorOrCurrentUser);
}
}
return users.map((user) => {
const isSharingWebcam = videoUsers?.includes(user.userId);
const whiteboardAccess = whiteboardUsers?.includes(user.userId);
return {
...user,
isSharingWebcam,
whiteboardAccess,
};
}).sort(sortUsers);
};
2021-05-18 04:25:07 +08:00
const getUserCount = () => Users.find({ meetingId: Auth.meetingID }).count();
2016-05-20 02:22:56 +08:00
const hasBreakoutRoom = () => Breakouts.find({ parentMeetingId: Auth.meetingID },
{ fields: {} }).count() > 0;
2018-10-02 21:48:12 +08:00
2021-05-18 04:25:07 +08:00
const isMe = (userId) => userId === Auth.userID;
const getActiveChats = ({ groupChatsMessages, groupChats, users }) => {
2023-02-23 21:27:16 +08:00
if (isEmpty(groupChats) && isEmpty(users)) return [];
2021-05-18 04:25:07 +08:00
const chatIds = Object.keys(groupChats);
const lastTimeWindows = chatIds.reduce((acc, chatId) => {
const chat = groupChatsMessages[chatId];
const lastTimewindowKey = chat?.lastTimewindow;
const lastTimeWindow = lastTimewindowKey?.split('-')[1];
return {
...acc,
chatId: lastTimeWindow,
2021-05-18 04:25:07 +08:00
};
}, {});
2017-03-01 06:40:16 +08:00
2021-05-18 04:25:07 +08:00
chatIds.sort((a, b) => {
if (a === PUBLIC_GROUP_CHAT_ID) {
return -1;
}
2021-05-18 04:25:07 +08:00
if (lastTimeWindows[a] === lastTimeWindows[b]) {
return 0;
2017-03-01 06:40:16 +08:00
}
2021-05-18 04:25:07 +08:00
return 1;
2017-03-03 04:33:49 +08:00
});
2021-05-18 04:25:07 +08:00
const chatInfo = chatIds.map((chatId) => {
const contextChat = groupChatsMessages[chatId];
const isPublicChatId = chatId === PUBLIC_GROUP_CHAT_ID;
let unreadMessagesCount = 0;
if (contextChat) {
const unreadTimewindows = contextChat.unreadTimeWindows;
2021-05-18 04:25:07 +08:00
// eslint-disable-next-line
for (const unreadTimeWindowId of unreadTimewindows) {
const timeWindow = (isPublicChatId
2021-05-18 04:25:07 +08:00
? contextChat?.preJoinMessages[unreadTimeWindowId]
|| contextChat?.posJoinMessages[unreadTimeWindowId]
2021-03-18 01:49:44 +08:00
: contextChat?.messageGroups[unreadTimeWindowId]);
unreadMessagesCount += timeWindow.content.length;
}
}
2017-03-03 04:33:49 +08:00
if (chatId !== PUBLIC_GROUP_CHAT_ID) {
const groupChatsParticipants = groupChats[chatId].participants;
const otherParticipant = groupChatsParticipants.filter((user) => user.id !== Auth.userID)[0];
2021-05-13 03:33:20 +08:00
const user = users[otherParticipant.id];
2021-05-21 20:17:24 +08:00
const startedChats = Session.get(STARTED_CHAT_LIST_KEY) || [];
2021-05-13 03:33:20 +08:00
return {
color: user?.color || '#7b1fa2',
isModerator: user?.role === ROLE_MODERATOR,
name: user?.name || otherParticipant.name,
avatar: user?.avatar,
chatId,
unreadCounter: unreadMessagesCount,
userId: user?.userId || otherParticipant.id,
shouldDisplayInChatList: groupChats[chatId].createdBy === Auth.userID
|| startedChats.includes(chatId)
|| !!contextChat,
2021-05-13 03:33:20 +08:00
};
2017-03-03 04:33:49 +08:00
}
2016-06-28 21:10:20 +08:00
return {
2021-05-18 04:25:07 +08:00
userId: PUBLIC_CHAT_ID,
name: 'Public Chat',
icon: 'group_chat',
2021-05-18 04:25:07 +08:00
chatId: PUBLIC_CHAT_ID,
unreadCounter: unreadMessagesCount,
shouldDisplayInChatList: true,
};
2016-06-28 21:10:20 +08:00
});
2021-05-18 04:25:07 +08:00
const currentClosedChats = Storage.getItem(CLOSED_CHAT_LIST_KEY) || [];
const removeClosedChats = chatInfo.filter((chat) => !currentClosedChats.includes(chat.chatId)
&& chat.shouldDisplayInChatList);
const sortByChatIdAndUnread = removeClosedChats.sort((a, b) => {
if (a.chatId === PUBLIC_GROUP_CHAT_ID) {
return -1;
}
if (b.chatId === PUBLIC_CHAT_ID) {
return 0;
}
if (a.unreadCounter > b.unreadCounter) {
return -1;
} else if (b.unreadCounter > a.unreadCounter) {
return 1;
} else {
if (a.name.toLowerCase() < b.name.toLowerCase()) {
return -1;
}
if (a.name.toLowerCase() > b.name.toLowerCase()) {
return 1;
}
return 0;
}
});
return sortByChatIdAndUnread;
2021-05-18 04:25:07 +08:00
};
2016-06-28 21:10:20 +08:00
2021-05-18 04:25:07 +08:00
const isVoiceOnlyUser = (userId) => userId.toString().startsWith('v_');
2017-12-09 00:40:52 +08:00
const isMeetingLocked = (id) => {
const meeting = Meetings.findOne({ meetingId: id },
{ fields: { lockSettingsProps: 1, usersProp: 1 } });
let isLocked = false;
if (meeting.lockSettingsProps !== undefined) {
2021-12-08 00:22:11 +08:00
const { lockSettingsProps: lockSettings, usersProp } = meeting;
if (lockSettings.disableCam
|| lockSettings.disableMic
2019-04-10 21:44:34 +08:00
|| lockSettings.disablePrivateChat
|| lockSettings.disablePublicChat
|| lockSettings.disableNotes
|| lockSettings.hideUserList
2022-03-24 03:11:41 +08:00
|| lockSettings.hideViewersCursor
|| usersProp.webcamsOnlyForModerator) {
isLocked = true;
}
}
return isLocked;
};
const getUsersProp = () => {
const meeting = Meetings.findOne(
{ meetingId: Auth.meetingID },
{
fields: {
'usersProp.allowModsToUnmuteUsers': 1,
'usersProp.allowModsToEjectCameras': 1,
'usersProp.authenticatedGuest': 1,
},
2021-05-18 04:25:07 +08:00
},
);
if (meeting.usersProp) return meeting.usersProp;
return {
allowModsToUnmuteUsers: false,
allowModsToEjectCameras: false,
authenticatedGuest: false,
2021-05-18 04:25:07 +08:00
};
};
2019-04-11 04:55:24 +08:00
const curatedVoiceUser = (intId) => {
const voiceUser = VoiceUsers.findOne({ intId });
return {
isVoiceUser: voiceUser ? voiceUser.joined : false,
isMuted: voiceUser ? voiceUser.muted && !voiceUser.listenOnly : false,
isTalking: voiceUser ? voiceUser.talking && !voiceUser.muted : false,
isListenOnly: voiceUser ? voiceUser.listenOnly : false,
};
};
2021-05-18 04:25:07 +08:00
const getAvailableActions = (
amIModerator, isBreakoutRoom, subjectUser, subjectVoiceUser, usersProp, amIPresenter,
) => {
const isDialInUser = isVoiceOnlyUser(subjectUser.userId) || subjectUser.phone_user;
2019-09-05 02:32:58 +08:00
const amISubjectUser = isMe(subjectUser.userId);
const isSubjectUserModerator = subjectUser.role === ROLE_MODERATOR;
const isSubjectUserGuest = subjectUser.guest;
2019-09-05 02:32:58 +08:00
const hasAuthority = amIModerator || amISubjectUser;
const allowedToChatPrivately = !amISubjectUser && !isDialInUser;
const allowedToMuteAudio = hasAuthority
&& subjectVoiceUser.isVoiceUser
&& !subjectVoiceUser.isMuted
&& !subjectVoiceUser.isListenOnly;
const allowedToUnmuteAudio = hasAuthority
&& subjectVoiceUser.isVoiceUser
&& !subjectVoiceUser.isListenOnly
&& subjectVoiceUser.isMuted
&& (amISubjectUser || usersProp.allowModsToUnmuteUsers);
const allowedToResetStatus = hasAuthority
&& subjectUser.emoji !== EMOJI_STATUSES.none
2019-01-14 21:23:35 +08:00
&& !isDialInUser;
2017-08-16 22:56:31 +08:00
// if currentUser is a moderator, allow removing other users
2019-09-05 02:32:58 +08:00
const allowedToRemove = amIModerator
&& !amISubjectUser
&& !isBreakoutRoom;
2017-08-16 22:56:31 +08:00
2019-09-05 02:32:58 +08:00
const allowedToSetPresenter = amIModerator
&& !subjectUser.presenter
2019-01-14 21:23:35 +08:00
&& !isDialInUser;
2019-09-05 02:32:58 +08:00
const allowedToPromote = amIModerator
&& !amISubjectUser
&& !isSubjectUserModerator
&& !isDialInUser
&& !isBreakoutRoom
&& !(isSubjectUserGuest && usersProp.authenticatedGuest);
2017-08-16 22:56:31 +08:00
2019-09-05 02:32:58 +08:00
const allowedToDemote = amIModerator
&& !amISubjectUser
&& isSubjectUserModerator
&& !isDialInUser
&& !isBreakoutRoom
&& !(isSubjectUserGuest && usersProp.authenticatedGuest);
2019-09-05 02:32:58 +08:00
const allowedToChangeStatus = amISubjectUser;
2019-09-05 02:32:58 +08:00
const allowedToChangeUserLockStatus = amIModerator
&& !isSubjectUserModerator
&& isMeetingLocked(Auth.meetingID);
const allowedToChangeWhiteboardAccess = amIPresenter
&& !amISubjectUser;
const allowedToEjectCameras = amIModerator
&& !amISubjectUser
&& usersProp.allowModsToEjectCameras;
2017-08-16 22:56:31 +08:00
return {
allowedToChatPrivately,
allowedToMuteAudio,
allowedToUnmuteAudio,
allowedToResetStatus,
allowedToRemove,
2017-08-16 22:56:31 +08:00
allowedToSetPresenter,
allowedToPromote,
allowedToDemote,
allowedToChangeStatus,
allowedToChangeUserLockStatus,
allowedToChangeWhiteboardAccess,
allowedToEjectCameras,
2017-08-16 22:56:31 +08:00
};
};
2021-05-18 04:25:07 +08:00
const normalizeEmojiName = (emoji) => (
emoji in EMOJI_STATUSES ? EMOJI_STATUSES[emoji] : emoji
);
2017-08-16 22:56:31 +08:00
2023-03-01 21:39:04 +08:00
const setEmojiStatus = throttle({ interval: 1000 }, (userId, emoji) => {
const statusAvailable = (Object.keys(EMOJI_STATUSES).includes(emoji));
return statusAvailable
? makeCall('setEmojiStatus', Auth.userID, emoji)
: makeCall('setEmojiStatus', userId, 'none');
2023-03-01 21:39:04 +08:00
});
const clearAllEmojiStatus = (users) => {
2021-05-18 04:25:07 +08:00
users.forEach((user) => makeCall('setEmojiStatus', user.userId, 'none'));
};
const assignPresenter = (userId) => { makeCall('assignPresenter', userId); };
const removeUser = (userId, banUser) => {
2017-12-09 00:40:52 +08:00
if (isVoiceOnlyUser(userId)) {
2022-01-14 02:43:16 +08:00
makeCall('ejectUserFromVoice', userId, banUser);
2017-12-09 00:40:52 +08:00
} else {
makeCall('removeUser', userId, banUser);
2017-12-09 00:40:52 +08:00
}
};
2019-01-14 21:23:35 +08:00
const toggleVoice = (userId) => {
if (userId === Auth.userID) {
AudioService.toggleMuteMicrophone();
2019-01-14 21:23:35 +08:00
} else {
makeCall('toggleVoice', userId);
logger.info({
logCode: 'usermenu_option_mute_toggle_audio',
extraInfo: { logType: 'moderator_action', userId },
}, 'moderator muted user microphone');
2019-01-14 21:23:35 +08:00
}
};
const ejectUserCameras = (userId) => {
makeCall('ejectUserCameras', userId);
};
const getEmoji = () => {
const currentUser = Users.findOne({ userId: Auth.userID },
{ fields: { emoji: 1 } });
if (!currentUser) {
return false;
}
return currentUser.emoji;
};
2018-09-29 05:32:52 +08:00
const muteAllUsers = (userId) => { makeCall('muteAllUsers', userId); };
const muteAllExceptPresenter = (userId) => { makeCall('muteAllExceptPresenter', userId); };
const changeRole = (userId, role) => { makeCall('changeRole', userId, role); };
const focusFirstDropDownItem = () => {
const dropdownContent = document.querySelector('div[data-test="dropdownContent"][style="visibility: visible;"]');
if (!dropdownContent) return;
const list = dropdownContent.getElementsByTagName('li');
list[0].focus();
};
const roving = (...args) => {
const [
event,
changeState,
elementsList,
element,
] = args;
this.selectedElement = element;
const numberOfChilds = elementsList.childElementCount;
const menuOpen = Session.get('dropdownOpen') || false;
if (menuOpen) {
const menuChildren = document.activeElement.getElementsByTagName('li');
if ([KEY_CODES.ESCAPE, KEY_CODES.ARROW_LEFT].includes(event.keyCode)) {
Session.set('dropdownOpen', false);
document.activeElement.click();
}
if ([KEY_CODES.ARROW_UP].includes(event.keyCode)) {
menuChildren[menuChildren.length - 1].focus();
}
if ([KEY_CODES.ARROW_DOWN].includes(event.keyCode)) {
for (let i = 0; i < menuChildren.length; i += 1) {
if (menuChildren[i].hasAttribute('tabIndex')) {
menuChildren[i].focus();
break;
}
}
}
return;
}
if ([KEY_CODES.ESCAPE, KEY_CODES.TAB].includes(event.keyCode)) {
Session.set('dropdownOpen', false);
changeState(null);
}
if (event.keyCode === KEY_CODES.ARROW_DOWN) {
const firstElement = elementsList.firstChild;
let elRef = element && numberOfChilds > 1 ? element.nextSibling : firstElement;
elRef = elRef || firstElement;
changeState(elRef);
}
if (event.keyCode === KEY_CODES.ARROW_UP) {
const lastElement = elementsList.lastChild;
let elRef = element ? element.previousSibling : lastElement;
elRef = elRef || lastElement;
changeState(elRef);
}
if ([KEY_CODES.ARROW_RIGHT, KEY_CODES.SPACE, KEY_CODES.ENTER].includes(event.keyCode)) {
const tether = document.activeElement.firstChild;
const dropdownTrigger = tether.firstChild;
dropdownTrigger?.click();
focusFirstDropDownItem();
}
};
2019-07-31 19:53:53 +08:00
const hasPrivateChatBetweenUsers = (senderId, receiverId) => GroupChat
.findOne({ users: { $all: [receiverId, senderId] } });
const getGroupChatPrivate = (senderUserId, receiver) => {
2021-02-12 22:07:53 +08:00
const chat = hasPrivateChatBetweenUsers(senderUserId, receiver.userId);
if (!chat) {
makeCall('createGroupChat', receiver);
2021-02-12 22:07:53 +08:00
} else {
2021-05-21 20:17:24 +08:00
const startedChats = Session.get(STARTED_CHAT_LIST_KEY) || [];
2023-02-23 20:45:30 +08:00
if (indexOf(startedChats, chat.chatId) < 0) {
startedChats.push(chat.chatId);
2021-05-21 20:17:24 +08:00
Session.set(STARTED_CHAT_LIST_KEY, startedChats);
}
2021-02-12 22:07:53 +08:00
const currentClosedChats = Storage.getItem(CLOSED_CHAT_LIST_KEY);
2023-02-23 20:45:30 +08:00
if (indexOf(currentClosedChats, chat.chatId) > -1) {
Storage.setItem(CLOSED_CHAT_LIST_KEY, without(currentClosedChats, chat.chatId));
2021-02-12 22:07:53 +08:00
}
}
};
const toggleUserLock = (userId, lockStatus) => {
makeCall('toggleUserLock', userId, lockStatus);
};
const requestUserInformation = (userId) => {
makeCall('requestUserInformation', userId);
};
const sortUsersByFirstName = (a, b) => {
const aUser = { sortName: a.firstName ? a.firstName : '' };
const bUser = { sortName: b.firstName ? b.firstName : '' };
return sortUsersByName(aUser, bUser);
};
const sortUsersByLastName = (a, b) => {
const aUser = { sortName: a.lastName ? a.lastName : '' };
const bUser = { sortName: b.lastName ? b.lastName : '' };
return sortUsersByName(aUser, bUser);
};
2022-06-23 21:05:11 +08:00
const isUserPresenter = (userId = Auth.userID) => {
const user = Users.findOne({ userId },
{ fields: { presenter: 1 } });
return user ? user.presenter : false;
};
export const getUserNamesLink = (docTitle, fnSortedLabel, lnSortedLabel) => {
const mimeType = 'text/plain';
const userNamesObj = getUsers()
.map((u) => {
const name = u.name.split(' ');
return ({
firstName: name[0],
middleNames: name.length > 2 ? name.slice(1, name.length - 1) : null,
lastName: name.length > 1 ? name[name.length - 1] : null,
});
});
const getUsernameString = (user) => {
const { firstName, middleNames, lastName } = user;
return `${firstName || ''} ${middleNames && middleNames.length > 0 ? middleNames.join(' ') : ''} ${lastName || ''}`;
};
const namesByFirstName = userNamesObj.sort(sortUsersByFirstName)
2021-05-18 04:25:07 +08:00
.map((u) => getUsernameString(u)).join('\r\n');
const namesByLastName = userNamesObj.sort(sortUsersByLastName)
2021-05-18 04:25:07 +08:00
.map((u) => getUsernameString(u)).join('\r\n');
2020-08-30 00:39:29 +08:00
const namesListsString = `${docTitle}\r\n\r\n${fnSortedLabel}\r\n${namesByFirstName}
\r\n\r\n${lnSortedLabel}\r\n${namesByLastName}`.replace(/ {2}/g, ' ');
const link = document.createElement('a');
const meeting = Meetings.findOne({ meetingId: Auth.meetingID },
{ fields: { 'meetingProp.name': 1 } });
link.setAttribute('download', `bbb-${meeting.meetingProp.name}[users-list]_${getDateString()}.txt`);
link.setAttribute(
'href',
`data: ${mimeType};charset=utf-16,${encodeURIComponent(namesListsString)}`,
);
return link;
};
const UserJoinedMeetingAlert = (obj) => {
const {
userJoinAudioAlerts,
userJoinPushAlerts,
} = Settings.application;
if (!userJoinAudioAlerts && !userJoinPushAlerts) return;
if (userJoinAudioAlerts) {
AudioService.playAlertSound(`${Meteor.settings.public.app.cdn
+ Meteor.settings.public.app.basename
+ Meteor.settings.public.app.instanceId}`
+ '/resources/sounds/userJoin.mp3');
}
if (userJoinPushAlerts) {
notify(
<FormattedMessage
id={obj.messageId}
values={obj.messageValues}
description={obj.messageDescription}
/>,
obj.notificationType,
obj.icon,
);
}
}
const UserLeftMeetingAlert = (obj) => {
const {
userLeaveAudioAlerts,
userLeavePushAlerts,
} = Settings.application;
if (!userLeaveAudioAlerts && !userLeavePushAlerts) return;
if (userLeaveAudioAlerts) {
AudioService.playAlertSound(`${Meteor.settings.public.app.cdn
+ Meteor.settings.public.app.basename
+ Meteor.settings.public.app.instanceId}`
+ '/resources/sounds/notify.mp3');
}
if (userLeavePushAlerts) {
notify(
<FormattedMessage
id={obj.messageId}
values={obj.messageValues}
description={obj.messageDescription}
/>,
obj.notificationType,
obj.icon,
);
}
}
export default {
sortUsersByName,
sortUsers,
setEmojiStatus,
clearAllEmojiStatus,
assignPresenter,
removeUser,
toggleVoice,
2018-09-29 05:32:52 +08:00
muteAllUsers,
muteAllExceptPresenter,
changeRole,
2016-06-07 00:45:30 +08:00
getUsers,
2022-02-03 22:42:24 +08:00
formatUsers,
2019-01-14 21:23:35 +08:00
getActiveChats,
2017-08-16 22:56:31 +08:00
getAvailableActions,
curatedVoiceUser,
2017-08-16 22:56:31 +08:00
normalizeEmojiName,
isMeetingLocked,
isPublicChat,
roving,
2018-03-21 03:35:28 +08:00
getCustomLogoUrl,
getGroupChatPrivate,
2018-10-02 21:48:12 +08:00
hasBreakoutRoom,
getEmojiList: () => EMOJI_STATUSES,
getEmoji,
hasPrivateChatBetweenUsers,
toggleUserLock,
requestUserInformation,
focusFirstDropDownItem,
isUserPresenter,
getUsersProp,
getUserCount,
sortUsersByCurrent,
ejectUserCameras,
UserJoinedMeetingAlert,
UserLeftMeetingAlert,
};