2017-10-12 10:00:28 +08:00
|
|
|
import Users from '/imports/api/users';
|
2019-08-22 23:19:54 +08:00
|
|
|
import VoiceUsers from '/imports/api/voice-users';
|
2018-07-26 22:56:26 +08:00
|
|
|
import GroupChat from '/imports/api/group-chat';
|
2019-08-03 02:18:33 +08:00
|
|
|
import { GroupChatMsg } from '/imports/api/group-chat-msg';
|
2018-10-02 21:48:12 +08:00
|
|
|
import Breakouts from '/imports/api/breakouts/';
|
2017-10-12 10:00:28 +08:00
|
|
|
import Meetings from '/imports/api/meetings';
|
2016-07-07 20:50:32 +08:00
|
|
|
import Auth from '/imports/ui/services/auth';
|
2016-07-11 20:34:58 +08:00
|
|
|
import UnreadMessages from '/imports/ui/services/unread-messages';
|
2017-03-01 06:40:16 +08:00
|
|
|
import Storage from '/imports/ui/services/storage/session';
|
2017-11-21 18:50:20 +08:00
|
|
|
import { EMOJI_STATUSES } from '/imports/utils/statuses';
|
2017-09-29 02:19:57 +08:00
|
|
|
import { makeCall } from '/imports/ui/services/api';
|
2017-03-22 05:52:10 +08:00
|
|
|
import _ from 'lodash';
|
2017-12-06 03:13:11 +08:00
|
|
|
import KEY_CODES from '/imports/utils/keyCodes';
|
2019-07-26 02:41:24 +08:00
|
|
|
import AudioService from '/imports/ui/components/audio/service';
|
|
|
|
import logger from '/imports/startup/client/logger';
|
2016-06-07 00:45:30 +08:00
|
|
|
|
2016-08-17 23:48:03 +08:00
|
|
|
const CHAT_CONFIG = Meteor.settings.public.chat;
|
2018-07-27 21:44:21 +08:00
|
|
|
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
|
2019-06-29 04:52:19 +08:00
|
|
|
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
|
2019-08-10 07:45:26 +08:00
|
|
|
const ROLE_VIEWER = Meteor.settings.public.user.role_viewer;
|
2016-06-07 00:45:30 +08:00
|
|
|
|
2019-08-10 06:28:49 +08:00
|
|
|
const DIAL_IN_CLIENT_TYPE = 'dial-in-user';
|
|
|
|
|
2017-03-17 23:27:37 +08:00
|
|
|
// session for closed chat list
|
|
|
|
const CLOSED_CHAT_LIST_KEY = 'closedChatList';
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
const mapActiveChats = (chat) => {
|
2017-06-03 03:25:02 +08:00
|
|
|
const currentUserId = Auth.userID;
|
2018-08-03 22:51:36 +08:00
|
|
|
|
|
|
|
if (chat.sender !== currentUserId) {
|
|
|
|
return chat.sender;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { chatId } = chat;
|
|
|
|
|
|
|
|
const userId = GroupChat.findOne({ chatId }).users.filter(user => user !== currentUserId);
|
|
|
|
|
|
|
|
return userId[0];
|
2016-06-28 21:10:20 +08:00
|
|
|
};
|
|
|
|
|
2018-03-21 03:35:28 +08:00
|
|
|
const CUSTOM_LOGO_URL_KEY = 'CustomLogoUrl';
|
|
|
|
|
|
|
|
export const setCustomLogoUrl = path => Storage.setItem(CUSTOM_LOGO_URL_KEY, path);
|
|
|
|
|
2020-05-21 03:54:08 +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);
|
|
|
|
|
2016-06-07 21:58:51 +08:00
|
|
|
const sortUsersByName = (a, b) => {
|
2019-08-10 06:28:49 +08:00
|
|
|
const aName = a.name.toLowerCase();
|
|
|
|
const bName = b.name.toLowerCase();
|
|
|
|
|
|
|
|
if (aName < bName) {
|
2016-06-07 00:45:30 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (aName > bName) {
|
2016-06-07 00:45:30 +08:00
|
|
|
return 1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (a.userId > b.userId) {
|
2016-06-07 00:45:30 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} 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 sortUsersByEmoji = (a, b) => {
|
2019-08-10 06:28:49 +08:00
|
|
|
if (a.emoji && b.emoji && (a.emoji !== 'none' && b.emoji !== 'none')) {
|
|
|
|
if (a.emojiTime < b.emojiTime) {
|
2016-06-08 00:46:24 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (a.emojiTime > b.emojiTime) {
|
2016-06-08 00:46:24 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (a.emoji && a.emoji !== 'none') {
|
2016-06-07 00:45:30 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} 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) => {
|
2019-08-10 06:28:49 +08:00
|
|
|
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;
|
2019-08-10 06:28:49 +08:00
|
|
|
} 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) => {
|
2019-08-10 06:28:49 +08:00
|
|
|
if (!a.clientType === DIAL_IN_CLIENT_TYPE && !b.clientType === DIAL_IN_CLIENT_TYPE) {
|
2017-12-12 23:03:33 +08:00
|
|
|
return 0;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (!a.clientType === DIAL_IN_CLIENT_TYPE) {
|
2016-06-07 00:45:30 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (!b.clientType === DIAL_IN_CLIENT_TYPE) {
|
2016-06-07 00:45:30 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2018-07-05 01:27:15 +08:00
|
|
|
// current user's name is always on top
|
|
|
|
const sortUsersByCurrent = (a, b) => {
|
2019-08-10 06:28:49 +08:00
|
|
|
if (a.userId === Auth.userID) {
|
2018-07-05 01:48:58 +08:00
|
|
|
return -1;
|
2019-08-10 06:28:49 +08:00
|
|
|
} if (b.userId === Auth.userID) {
|
2018-07-05 01:51:59 +08:00
|
|
|
return 1;
|
2018-07-05 01:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2016-06-07 21:58:51 +08:00
|
|
|
const sortUsers = (a, b) => {
|
2018-07-05 01:27:15 +08:00
|
|
|
let sort = sortUsersByCurrent(a, b);
|
|
|
|
|
|
|
|
if (sort === 0) {
|
|
|
|
sort = sortUsersByModerator(a, b);
|
|
|
|
}
|
2016-06-07 21:58:51 +08:00
|
|
|
|
|
|
|
if (sort === 0) {
|
2016-10-07 04:42:37 +08:00
|
|
|
sort = sortUsersByEmoji(a, b);
|
2016-06-07 21:58:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sort === 0) {
|
|
|
|
sort = sortUsersByPhoneUser(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sort === 0) {
|
|
|
|
sort = sortUsersByName(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sort;
|
|
|
|
};
|
|
|
|
|
2016-06-28 21:10:20 +08:00
|
|
|
const sortChatsByName = (a, b) => {
|
|
|
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
|
|
return -1;
|
2018-12-18 05:01:23 +08:00
|
|
|
} if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
2016-06-28 21:10:20 +08:00
|
|
|
return 1;
|
2019-09-06 02:26:54 +08:00
|
|
|
} if (a.userId.toLowerCase() > b.userId.toLowerCase()) {
|
2016-06-28 21:10:20 +08:00
|
|
|
return -1;
|
2019-09-06 02:26:54 +08:00
|
|
|
} if (a.userId.toLowerCase() < b.userId.toLowerCase()) {
|
2016-06-28 21:10:20 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortChatsByIcon = (a, b) => {
|
|
|
|
if (a.icon && b.icon) {
|
|
|
|
return sortChatsByName(a, b);
|
2018-12-18 05:01:23 +08:00
|
|
|
} if (a.icon) {
|
2016-06-28 21:10:20 +08:00
|
|
|
return -1;
|
2018-12-18 05:01:23 +08:00
|
|
|
} if (b.icon) {
|
2016-06-28 21:10:20 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2017-09-22 22:24:24 +08:00
|
|
|
const isPublicChat = chat => (
|
2019-08-23 01:23:18 +08:00
|
|
|
chat.userId === 'public'
|
2017-09-22 22:24:24 +08:00
|
|
|
);
|
|
|
|
|
2016-06-28 21:10:20 +08:00
|
|
|
const sortChats = (a, b) => {
|
|
|
|
let sort = sortChatsByIcon(a, b);
|
|
|
|
|
|
|
|
if (sort === 0) {
|
|
|
|
sort = sortChatsByName(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sort;
|
|
|
|
};
|
|
|
|
|
|
|
|
const userFindSorting = {
|
2017-07-26 22:09:07 +08:00
|
|
|
emojiTime: 1,
|
|
|
|
role: 1,
|
|
|
|
phoneUser: 1,
|
2020-09-17 21:26:38 +08:00
|
|
|
name: 1,
|
2017-07-26 22:09:07 +08:00
|
|
|
userId: 1,
|
2016-06-28 21:10:20 +08:00
|
|
|
};
|
|
|
|
|
2016-06-07 00:45:30 +08:00
|
|
|
const getUsers = () => {
|
2019-08-10 07:45:26 +08:00
|
|
|
let users = Users
|
2019-02-08 00:42:47 +08:00
|
|
|
.find({
|
|
|
|
meetingId: Auth.meetingID,
|
|
|
|
connectionStatus: 'online',
|
|
|
|
}, userFindSorting)
|
2017-04-13 04:19:39 +08:00
|
|
|
.fetch();
|
2016-06-07 00:45:30 +08:00
|
|
|
|
2019-08-22 20:05:06 +08:00
|
|
|
const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { role: 1, locked: 1 } });
|
2019-08-10 07:45:26 +08:00
|
|
|
if (currentUser && currentUser.role === ROLE_VIEWER && currentUser.locked) {
|
2019-08-22 23:19:54 +08:00
|
|
|
const meeting = Meetings.findOne({ meetingId: Auth.meetingID },
|
|
|
|
{ fields: { 'lockSettingsProps.hideUserList': 1 } });
|
2019-08-10 07:45:26 +08:00
|
|
|
if (meeting && meeting.lockSettingsProps && meeting.lockSettingsProps.hideUserList) {
|
|
|
|
const moderatorOrCurrentUser = u => u.role === ROLE_MODERATOR || u.userId === Auth.userID;
|
|
|
|
users = users.filter(moderatorOrCurrentUser);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-10 06:28:49 +08:00
|
|
|
return users.sort(sortUsers);
|
2016-05-31 19:29:38 +08:00
|
|
|
};
|
2016-05-20 02:22:56 +08:00
|
|
|
|
2019-08-22 20:05:06 +08:00
|
|
|
const hasBreakoutRoom = () => Breakouts.find({ parentMeetingId: Auth.meetingID },
|
|
|
|
{ fields: {} }).count() > 0;
|
2018-10-02 21:48:12 +08:00
|
|
|
|
2019-08-23 03:14:36 +08:00
|
|
|
const isMe = userId => userId === Auth.userID;
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
const getActiveChats = (chatID) => {
|
2018-08-01 01:13:36 +08:00
|
|
|
const privateChat = GroupChat
|
2019-08-23 03:14:36 +08:00
|
|
|
.find({ users: { $all: [Auth.userID] } })
|
2018-08-01 01:13:36 +08:00
|
|
|
.fetch()
|
|
|
|
.map(chat => chat.chatId);
|
|
|
|
|
|
|
|
const filter = {
|
|
|
|
chatId: { $ne: PUBLIC_GROUP_CHAT_ID },
|
|
|
|
};
|
|
|
|
|
|
|
|
if (privateChat) {
|
|
|
|
filter.chatId = { $in: privateChat };
|
|
|
|
}
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
let activeChats = GroupChatMsg
|
2018-08-01 01:13:36 +08:00
|
|
|
.find(filter)
|
2017-04-13 04:19:39 +08:00
|
|
|
.fetch()
|
2019-01-14 21:23:35 +08:00
|
|
|
.map(mapActiveChats);
|
2016-06-28 21:10:20 +08:00
|
|
|
|
2016-06-30 22:45:19 +08:00
|
|
|
if (chatID) {
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats.push(chatID);
|
2016-06-28 21:10:20 +08:00
|
|
|
}
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats = _.uniq(_.compact(activeChats));
|
2016-06-28 21:10:20 +08:00
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats = Users
|
2019-08-23 03:14:36 +08:00
|
|
|
.find({ userId: { $in: activeChats } })
|
2017-06-03 03:25:02 +08:00
|
|
|
.map((op) => {
|
2019-01-14 21:23:35 +08:00
|
|
|
const activeChat = op;
|
2019-08-22 20:05:06 +08:00
|
|
|
activeChat.unreadCounter = UnreadMessages.count(op.userId);
|
2019-08-23 01:23:18 +08:00
|
|
|
activeChat.name = op.name;
|
2019-09-05 02:32:58 +08:00
|
|
|
activeChat.isModerator = op.role === ROLE_MODERATOR;
|
2019-01-14 21:23:35 +08:00
|
|
|
return activeChat;
|
2017-04-13 04:19:39 +08:00
|
|
|
});
|
2017-03-01 06:40:16 +08:00
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
const currentClosedChats = Storage.getItem(CLOSED_CHAT_LIST_KEY) || [];
|
|
|
|
const filteredChatList = [];
|
2017-03-01 06:55:00 +08:00
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats.forEach((op) => {
|
2017-03-07 01:25:35 +08:00
|
|
|
// When a new private chat message is received, ensure the conversation view is restored.
|
2017-03-03 04:33:49 +08:00
|
|
|
if (op.unreadCounter > 0) {
|
2019-09-06 02:26:54 +08:00
|
|
|
if (_.indexOf(currentClosedChats, op.userId) > -1) {
|
|
|
|
Storage.setItem(CLOSED_CHAT_LIST_KEY, _.without(currentClosedChats, op.userId));
|
2017-03-02 05:27:05 +08:00
|
|
|
}
|
2017-03-03 04:33:49 +08:00
|
|
|
}
|
2017-03-01 06:40:16 +08:00
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
// Compare activeChats with session and push it into filteredChatList
|
|
|
|
// if one of the activeChat is not in session.
|
|
|
|
// It will pass to activeChats.
|
2019-09-06 02:26:54 +08:00
|
|
|
if (_.indexOf(currentClosedChats, op.userId) < 0) {
|
2017-03-03 04:33:49 +08:00
|
|
|
filteredChatList.push(op);
|
2017-03-01 06:40:16 +08:00
|
|
|
}
|
2017-03-03 04:33:49 +08:00
|
|
|
});
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats = filteredChatList;
|
2016-06-28 21:10:20 +08:00
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
activeChats.push({
|
2019-08-23 01:23:18 +08:00
|
|
|
userId: 'public',
|
2016-06-28 21:10:20 +08:00
|
|
|
name: 'Public Chat',
|
2017-03-02 09:03:02 +08:00
|
|
|
icon: 'group_chat',
|
2018-07-27 21:44:21 +08:00
|
|
|
unreadCounter: UnreadMessages.count(PUBLIC_GROUP_CHAT_ID),
|
2016-06-28 21:10:20 +08:00
|
|
|
});
|
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
return activeChats
|
2017-04-13 04:19:39 +08:00
|
|
|
.sort(sortChats);
|
2016-06-28 21:10:20 +08:00
|
|
|
};
|
|
|
|
|
2017-12-09 00:40:52 +08:00
|
|
|
const isVoiceOnlyUser = userId => userId.toString().startsWith('v_');
|
|
|
|
|
2019-01-29 23:17:09 +08:00
|
|
|
const isMeetingLocked = (id) => {
|
2019-08-22 23:19:54 +08:00
|
|
|
const meeting = Meetings.findOne({ meetingId: id }, { fields: { lockSettingsProps: 1 } });
|
2019-01-29 23:17:09 +08:00
|
|
|
let isLocked = false;
|
|
|
|
|
2019-04-04 01:23:31 +08:00
|
|
|
if (meeting.lockSettingsProps !== undefined) {
|
|
|
|
const lockSettings = meeting.lockSettingsProps;
|
2019-01-29 23:17:09 +08:00
|
|
|
|
|
|
|
if (lockSettings.disableCam
|
|
|
|
|| lockSettings.disableMic
|
2019-04-10 21:44:34 +08:00
|
|
|
|| lockSettings.disablePrivateChat
|
2020-05-13 03:43:10 +08:00
|
|
|
|| lockSettings.disablePublicChat) {
|
2019-01-29 23:17:09 +08:00
|
|
|
isLocked = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return isLocked;
|
|
|
|
};
|
|
|
|
|
2019-04-17 21:24:44 +08:00
|
|
|
const areUsersUnmutable = () => {
|
2019-08-30 00:26:07 +08:00
|
|
|
const meeting = Meetings.findOne({ meetingId: Auth.meetingID },
|
|
|
|
{ fields: { 'usersProp.allowModsToUnmuteUsers': 1 } });
|
2019-04-11 04:55:24 +08:00
|
|
|
if (meeting.usersProp) {
|
2019-04-23 23:30:55 +08:00
|
|
|
return meeting.usersProp.allowModsToUnmuteUsers;
|
2019-04-11 04:55:24 +08:00
|
|
|
}
|
|
|
|
return false;
|
2019-06-29 04:52:19 +08:00
|
|
|
};
|
2019-04-11 04:55:24 +08:00
|
|
|
|
2019-08-22 23:19:54 +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,
|
|
|
|
};
|
|
|
|
};
|
2017-12-08 06:07:02 +08:00
|
|
|
|
2019-09-07 04:28:02 +08:00
|
|
|
const getAvailableActions = (amIModerator, isBreakoutRoom, subjectUser, subjectVoiceUser) => {
|
2019-08-22 23:19:54 +08:00
|
|
|
const isDialInUser = isVoiceOnlyUser(subjectUser.userId) || subjectUser.phone_user;
|
2019-09-05 02:32:58 +08:00
|
|
|
const amISubjectUser = isMe(subjectUser.userId);
|
2019-09-06 02:21:07 +08:00
|
|
|
const isSubjectUserModerator = subjectUser.role === ROLE_MODERATOR;
|
2019-08-22 23:19:54 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const hasAuthority = amIModerator || amISubjectUser;
|
|
|
|
const allowedToChatPrivately = !amISubjectUser && !isDialInUser;
|
2017-10-31 02:27:17 +08:00
|
|
|
const allowedToMuteAudio = hasAuthority
|
2019-09-06 02:21:07 +08:00
|
|
|
&& subjectVoiceUser.isVoiceUser
|
|
|
|
&& !subjectVoiceUser.isMuted
|
|
|
|
&& !subjectVoiceUser.isListenOnly;
|
2017-12-08 06:07:02 +08:00
|
|
|
|
2017-10-26 20:50:55 +08:00
|
|
|
const allowedToUnmuteAudio = hasAuthority
|
2019-09-06 02:21:07 +08:00
|
|
|
&& subjectVoiceUser.isVoiceUser
|
|
|
|
&& !subjectVoiceUser.isListenOnly
|
|
|
|
&& subjectVoiceUser.isMuted
|
2019-09-05 02:32:58 +08:00
|
|
|
&& (amISubjectUser || areUsersUnmutable());
|
2017-12-08 06:07:02 +08:00
|
|
|
|
|
|
|
const allowedToResetStatus = hasAuthority
|
2019-08-22 23:19:54 +08:00
|
|
|
&& subjectUser.emoji !== EMOJI_STATUSES.none
|
2019-01-14 21:23:35 +08:00
|
|
|
&& !isDialInUser;
|
2017-08-16 22:56:31 +08:00
|
|
|
|
2018-01-10 06:28:48 +08:00
|
|
|
// if currentUser is a moderator, allow removing other users
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToRemove = amIModerator
|
|
|
|
&& !amISubjectUser
|
2019-08-22 23:19:54 +08:00
|
|
|
&& !isBreakoutRoom;
|
2017-08-16 22:56:31 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToSetPresenter = amIModerator
|
2019-08-22 23:19:54 +08:00
|
|
|
&& !subjectUser.presenter
|
2019-01-14 21:23:35 +08:00
|
|
|
&& !isDialInUser;
|
2017-12-08 06:07:02 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToPromote = amIModerator
|
|
|
|
&& !amISubjectUser
|
|
|
|
&& !isSubjectUserModerator
|
2019-03-12 21:15:08 +08:00
|
|
|
&& !isDialInUser
|
|
|
|
&& !isBreakoutRoom;
|
2017-08-16 22:56:31 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToDemote = amIModerator
|
|
|
|
&& !amISubjectUser
|
|
|
|
&& isSubjectUserModerator
|
2019-03-12 21:15:08 +08:00
|
|
|
&& !isDialInUser
|
|
|
|
&& !isBreakoutRoom;
|
2017-08-23 02:39:34 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToChangeStatus = amISubjectUser;
|
2018-07-03 09:48:28 +08:00
|
|
|
|
2019-09-05 02:32:58 +08:00
|
|
|
const allowedToChangeUserLockStatus = amIModerator
|
|
|
|
&& !isSubjectUserModerator
|
|
|
|
&& isMeetingLocked(Auth.meetingID);
|
2019-01-29 23:17:09 +08:00
|
|
|
|
2017-08-16 22:56:31 +08:00
|
|
|
return {
|
|
|
|
allowedToChatPrivately,
|
|
|
|
allowedToMuteAudio,
|
|
|
|
allowedToUnmuteAudio,
|
|
|
|
allowedToResetStatus,
|
2018-01-10 06:28:48 +08:00
|
|
|
allowedToRemove,
|
2017-08-16 22:56:31 +08:00
|
|
|
allowedToSetPresenter,
|
2017-08-23 02:39:34 +08:00
|
|
|
allowedToPromote,
|
|
|
|
allowedToDemote,
|
2018-07-03 09:48:28 +08:00
|
|
|
allowedToChangeStatus,
|
2019-01-29 23:17:09 +08:00
|
|
|
allowedToChangeUserLockStatus,
|
2017-08-16 22:56:31 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-09-23 01:03:14 +08:00
|
|
|
const normalizeEmojiName = emoji => (
|
2017-11-21 18:50:20 +08:00
|
|
|
emoji in EMOJI_STATUSES ? EMOJI_STATUSES[emoji] : emoji
|
2017-09-23 01:03:14 +08:00
|
|
|
);
|
2017-08-16 22:56:31 +08:00
|
|
|
|
2019-08-19 20:56:21 +08:00
|
|
|
const setEmojiStatus = (userId, emoji) => {
|
|
|
|
const statusAvailable = (Object.keys(EMOJI_STATUSES).includes(emoji));
|
2018-07-12 04:08:22 +08:00
|
|
|
|
|
|
|
return statusAvailable
|
2019-08-19 20:56:21 +08:00
|
|
|
? makeCall('setEmojiStatus', Auth.userID, emoji)
|
|
|
|
: makeCall('setEmojiStatus', userId, 'none');
|
2018-07-10 01:08:19 +08:00
|
|
|
};
|
2017-09-29 02:19:57 +08:00
|
|
|
|
2017-10-03 23:25:56 +08:00
|
|
|
const assignPresenter = (userId) => { makeCall('assignPresenter', userId); };
|
2017-09-29 02:19:57 +08:00
|
|
|
|
2020-05-22 04:40:08 +08:00
|
|
|
const removeUser = (userId, banUser) => {
|
2017-12-09 00:40:52 +08:00
|
|
|
if (isVoiceOnlyUser(userId)) {
|
2020-05-22 22:45:28 +08:00
|
|
|
makeCall('ejectUserFromVoice', userId);
|
2017-12-09 00:40:52 +08:00
|
|
|
} else {
|
2020-05-22 04:40:08 +08:00
|
|
|
makeCall('removeUser', userId, banUser);
|
2017-12-09 00:40:52 +08:00
|
|
|
}
|
|
|
|
};
|
2017-09-29 02:19:57 +08:00
|
|
|
|
2019-01-14 21:23:35 +08:00
|
|
|
const toggleVoice = (userId) => {
|
|
|
|
if (userId === Auth.userID) {
|
2019-07-26 02:41:24 +08:00
|
|
|
AudioService.toggleMuteMicrophone();
|
2019-01-14 21:23:35 +08:00
|
|
|
} else {
|
|
|
|
makeCall('toggleVoice', userId);
|
2019-07-26 02:41:24 +08:00
|
|
|
logger.info({
|
2020-06-27 02:51:01 +08:00
|
|
|
logCode: 'usermenu_option_mute_toggle_audio',
|
|
|
|
extraInfo: { logType: 'moderator_action', userId },
|
2019-07-26 02:41:24 +08:00
|
|
|
}, 'moderator muted user microphone');
|
2019-01-14 21:23:35 +08:00
|
|
|
}
|
|
|
|
};
|
2018-02-09 00:06:41 +08:00
|
|
|
|
2018-09-29 05:32:52 +08:00
|
|
|
const muteAllUsers = (userId) => { makeCall('muteAllUsers', userId); };
|
|
|
|
|
|
|
|
const muteAllExceptPresenter = (userId) => { makeCall('muteAllExceptPresenter', userId); };
|
|
|
|
|
2017-10-03 23:25:56 +08:00
|
|
|
const changeRole = (userId, role) => { makeCall('changeRole', userId, role); };
|
2017-09-29 02:19:57 +08:00
|
|
|
|
2019-08-14 05:16:14 +08:00
|
|
|
const roving = (event, changeState, elementsList, element) => {
|
|
|
|
this.selectedElement = element;
|
|
|
|
const menuOpen = Session.get('dropdownOpen') || false;
|
|
|
|
|
|
|
|
if (menuOpen) {
|
2018-05-09 01:47:55 +08:00
|
|
|
const menuChildren = document.activeElement.getElementsByTagName('li');
|
|
|
|
|
|
|
|
if ([KEY_CODES.ESCAPE, KEY_CODES.ARROW_LEFT].includes(event.keyCode)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-06 03:13:11 +08:00
|
|
|
if ([KEY_CODES.ESCAPE, KEY_CODES.TAB].includes(event.keyCode)) {
|
2017-12-07 01:05:32 +08:00
|
|
|
document.activeElement.blur();
|
2019-08-14 05:16:14 +08:00
|
|
|
changeState(null);
|
2017-12-06 03:13:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (event.keyCode === KEY_CODES.ARROW_DOWN) {
|
2019-08-14 05:16:14 +08:00
|
|
|
const firstElement = elementsList.firstChild;
|
|
|
|
let elRef = element ? element.nextSibling : firstElement;
|
|
|
|
elRef = elRef || firstElement;
|
|
|
|
changeState(elRef);
|
2017-12-06 03:13:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (event.keyCode === KEY_CODES.ARROW_UP) {
|
2019-08-14 05:16:14 +08:00
|
|
|
const lastElement = elementsList.lastChild;
|
|
|
|
let elRef = element ? element.previousSibling : lastElement;
|
|
|
|
elRef = elRef || lastElement;
|
|
|
|
changeState(elRef);
|
2017-12-06 03:13:11 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 01:47:55 +08:00
|
|
|
if ([KEY_CODES.ARROW_RIGHT, KEY_CODES.SPACE, KEY_CODES.ENTER].includes(event.keyCode)) {
|
2017-12-06 03:13:11 +08:00
|
|
|
document.activeElement.firstChild.click();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-31 19:53:53 +08:00
|
|
|
const hasPrivateChatBetweenUsers = (senderId, receiverId) => GroupChat
|
|
|
|
.findOne({ users: { $all: [receiverId, senderId] } });
|
2018-07-26 22:56:26 +08:00
|
|
|
|
2019-08-22 23:19:54 +08:00
|
|
|
const getGroupChatPrivate = (senderUserId, receiver) => {
|
|
|
|
if (!hasPrivateChatBetweenUsers(senderUserId, receiver.userId)) {
|
2018-07-27 21:44:21 +08:00
|
|
|
makeCall('createGroupChat', receiver);
|
2018-07-26 22:56:26 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-29 23:17:09 +08:00
|
|
|
const toggleUserLock = (userId, lockStatus) => {
|
|
|
|
makeCall('toggleUserLock', userId, lockStatus);
|
|
|
|
};
|
|
|
|
|
2019-04-06 06:32:21 +08:00
|
|
|
const requestUserInformation = (userId) => {
|
|
|
|
makeCall('requestUserInformation', userId);
|
|
|
|
};
|
|
|
|
|
2020-08-29 10:17:04 +08:00
|
|
|
const sortUsersByFirstName = (a, b) => {
|
|
|
|
const aName = a.firstName.toLowerCase();
|
|
|
|
const bName = b.firstName.toLowerCase();
|
|
|
|
if (aName < bName) return -1;
|
|
|
|
if (aName > bName) return 1;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortUsersByLastName = (a, b) => {
|
|
|
|
if (a.lastName && !b.lastName) return -1;
|
|
|
|
if (!a.lastName && b.lastName) return 1;
|
|
|
|
|
|
|
|
const aName = a.lastName.toLowerCase();
|
|
|
|
const bName = b.lastName.toLowerCase();
|
|
|
|
|
|
|
|
if (aName < bName) return -1;
|
|
|
|
if (aName > bName) return 1;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2020-09-10 22:11:18 +08:00
|
|
|
const isUserPresenter = (userId) => {
|
|
|
|
const user = Users.findOne({ userId },
|
|
|
|
{ fields: { presenter: 1 } });
|
|
|
|
return user ? user.presenter : false;
|
|
|
|
};
|
|
|
|
|
2020-08-29 10:17:04 +08:00
|
|
|
export const getUserNamesLink = (docTitle, fnSortedLabel, lnSortedLabel) => {
|
2019-09-07 04:28:02 +08:00
|
|
|
const mimeType = 'text/plain';
|
2020-08-29 10:17:04 +08:00
|
|
|
const userNamesObj = getUsers()
|
|
|
|
.map((u) => {
|
2020-09-17 21:26:38 +08:00
|
|
|
const name = u.name.split(' ');
|
2020-08-29 10:17:04 +08:00
|
|
|
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)
|
|
|
|
.map(u => getUsernameString(u)).join('\r\n');
|
|
|
|
|
|
|
|
const namesByLastName = userNamesObj.sort(sortUsersByLastName)
|
|
|
|
.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, ' ');
|
2020-08-29 10:17:04 +08:00
|
|
|
|
2019-09-07 04:28:02 +08:00
|
|
|
const link = document.createElement('a');
|
|
|
|
link.setAttribute('download', `save-users-list-${Date.now()}.txt`);
|
|
|
|
link.setAttribute(
|
|
|
|
'href',
|
2020-08-29 10:17:04 +08:00
|
|
|
`data: ${mimeType} ;charset=utf-16,${encodeURIComponent(namesListsString)}`,
|
2019-09-07 04:28:02 +08:00
|
|
|
);
|
|
|
|
return link;
|
|
|
|
};
|
|
|
|
|
2016-06-01 04:25:42 +08:00
|
|
|
export default {
|
2019-09-18 20:32:00 +08:00
|
|
|
sortUsersByName,
|
2019-08-10 06:28:49 +08:00
|
|
|
sortUsers,
|
2017-09-29 02:19:57 +08:00
|
|
|
setEmojiStatus,
|
|
|
|
assignPresenter,
|
2018-01-10 06:28:48 +08:00
|
|
|
removeUser,
|
2017-09-29 02:19:57 +08:00
|
|
|
toggleVoice,
|
2018-09-29 05:32:52 +08:00
|
|
|
muteAllUsers,
|
|
|
|
muteAllExceptPresenter,
|
2017-09-29 02:19:57 +08:00
|
|
|
changeRole,
|
2016-06-07 00:45:30 +08:00
|
|
|
getUsers,
|
2019-01-14 21:23:35 +08:00
|
|
|
getActiveChats,
|
2017-08-16 22:56:31 +08:00
|
|
|
getAvailableActions,
|
2019-08-22 23:19:54 +08:00
|
|
|
curatedVoiceUser,
|
2017-08-16 22:56:31 +08:00
|
|
|
normalizeEmojiName,
|
2017-09-12 03:11:03 +08:00
|
|
|
isMeetingLocked,
|
2017-09-22 22:24:24 +08:00
|
|
|
isPublicChat,
|
2017-12-06 03:13:11 +08:00
|
|
|
roving,
|
2018-03-21 03:35:28 +08:00
|
|
|
getCustomLogoUrl,
|
2018-07-26 22:56:26 +08:00
|
|
|
getGroupChatPrivate,
|
2018-10-02 21:48:12 +08:00
|
|
|
hasBreakoutRoom,
|
2018-07-12 04:08:22 +08:00
|
|
|
getEmojiList: () => EMOJI_STATUSES,
|
2019-08-30 00:26:07 +08:00
|
|
|
getEmoji: () => Users.findOne({ userId: Auth.userID }, { fields: { emoji: 1 } }).emoji,
|
2019-01-15 00:58:01 +08:00
|
|
|
hasPrivateChatBetweenUsers,
|
2019-01-29 23:17:09 +08:00
|
|
|
toggleUserLock,
|
2019-04-06 06:32:21 +08:00
|
|
|
requestUserInformation,
|
2020-09-10 22:11:18 +08:00
|
|
|
isUserPresenter,
|
2016-06-01 04:25:42 +08:00
|
|
|
};
|