use group chat messages in html5 client
This commit is contained in:
parent
aef2fe577d
commit
d8391f450b
@ -1,14 +1,12 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
const GroupChat = new Mongo.Collection('group-chat-msg');
|
||||
const GroupChatMsg = new Mongo.Collection('group-chat-msg');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
GroupChat._ensureIndex({
|
||||
meetingId: 1, chatId: 1, access: 1, users: 1,
|
||||
});
|
||||
GroupChatMsg._ensureIndex({ meetingId: 1, chatId: 1 });
|
||||
}
|
||||
|
||||
export default GroupChat;
|
||||
export default GroupChatMsg;
|
||||
|
||||
export const CHAT_ACCESS = {
|
||||
PUBLIC: 'PUBLIC_ACCESS',
|
||||
@ -17,3 +15,4 @@ export const CHAT_ACCESS = {
|
||||
|
||||
export const CHAT_ACCESS_PUBLIC = CHAT_ACCESS.PUBLIC;
|
||||
export const CHAT_ACCESS_PRIVATE = CHAT_ACCESS.PRIVATE;
|
||||
export const GROUP_MESSAGE_PUBLIC_ID = 'MAIN-PUBLIC-GROUP-CHAT';
|
||||
|
@ -29,6 +29,7 @@ const parseMessage = (message) => {
|
||||
export default function sendGroupChatMsg(credentials, chatId, message) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'SendGroupChatMessageMsg';
|
||||
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
|
||||
@ -37,19 +38,14 @@ export default function sendGroupChatMsg(credentials, chatId, message) {
|
||||
check(requesterToken, String);
|
||||
check(message, Object);
|
||||
|
||||
const eventName = 'SendGroupChatMessageMsg';
|
||||
const parsedMessage = parseMessage(message.message);
|
||||
|
||||
message.message = parsedMessage
|
||||
|
||||
const parsedMessage = parseMessage(message);
|
||||
const payload = {
|
||||
chatId,
|
||||
// correlationId: `${Date.now()}`,
|
||||
sender: {
|
||||
id: requesterUserId,
|
||||
name: '',
|
||||
},
|
||||
// color: '1',
|
||||
message: parsedMessage,
|
||||
msg: message,
|
||||
chatId: chatId
|
||||
};
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, eventName, meetingId, requesterUserId, payload);
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import GroupChatMsg, { CHAT_ACCESS_PUBLIC, GROUP_MESSAGE_PUBLIC_ID } from '/imports/api/group-chat-msg';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
import { GroupChat, CHAT_ACCESS_PUBLIC } from '/imports/api/group-chat-msg';
|
||||
|
||||
function groupChatMsg(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
|
||||
@ -15,17 +14,7 @@ function groupChatMsg(credentials) {
|
||||
|
||||
Logger.info(`Publishing group-chat-msg for ${meetingId} ${requesterUserId} ${requesterToken}`);
|
||||
|
||||
return GroupChat.find({
|
||||
$or: [
|
||||
{
|
||||
access: CHAT_ACCESS_PUBLIC,
|
||||
meetingId,
|
||||
}, {
|
||||
users: { $in: [requesterUserId] },
|
||||
meetingId,
|
||||
},
|
||||
],
|
||||
});
|
||||
return GroupChatMsg.find({ meetingId });
|
||||
}
|
||||
|
||||
function publish(...args) {
|
||||
|
@ -10,7 +10,7 @@ if (Meteor.isServer) {
|
||||
|
||||
export default GroupChat;
|
||||
|
||||
export const CHAT_ACCESS = {
|
||||
const CHAT_ACCESS = {
|
||||
PUBLIC: 'PUBLIC_ACCESS',
|
||||
PRIVATE: 'PRIVATE_ACCESS',
|
||||
};
|
||||
|
@ -1,31 +1,28 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import { CHAT_ACCESS_PUBLIC, CHAT_ACCESS_PRIVATE } from '/imports/api/group-chat'
|
||||
|
||||
export default function createGroupChat(credentials) {
|
||||
|
||||
export default function createGroupChat(credentials, receiver) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'CreateGroupChatReqMsg';
|
||||
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
check(requesterToken, String);
|
||||
check(receiver, Object);
|
||||
|
||||
const eventName = 'CreateGroupChatReqMsg';
|
||||
|
||||
const payload = {
|
||||
// TODO: Implement this together with #4988
|
||||
// correlationId: String,
|
||||
// name: String,
|
||||
// access: String,
|
||||
// users: Vector[String],
|
||||
// msg: Vector[{
|
||||
// correlationId: String,
|
||||
// sender: GroupChatUser,
|
||||
// color: String,
|
||||
// message: String
|
||||
// }],
|
||||
let payload = {
|
||||
correlationId: `${requesterUserId}-${Date.now()}`,
|
||||
msg: [],
|
||||
users: [receiver.id],
|
||||
access: CHAT_ACCESS_PRIVATE,
|
||||
name: receiver.name
|
||||
};
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, eventName, meetingId, requesterUserId, payload);
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import GroupChat, { CHAT_ACCESS_PUBLIC } from '/imports/api/group-chat';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
import { GroupChat, CHAT_ACCESS_PUBLIC } from '/imports/api/group-chat';
|
||||
|
||||
function groupChat(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
|
||||
@ -15,17 +14,7 @@ function groupChat(credentials) {
|
||||
|
||||
Logger.info(`Publishing group-chat for ${meetingId} ${requesterUserId} ${requesterToken}`);
|
||||
|
||||
return GroupChat.find({
|
||||
$or: [
|
||||
{
|
||||
access: CHAT_ACCESS_PUBLIC,
|
||||
meetingId,
|
||||
}, {
|
||||
users: { $in: [requesterUserId] },
|
||||
meetingId,
|
||||
},
|
||||
],
|
||||
});
|
||||
return GroupChat.find({ meetingId });
|
||||
}
|
||||
|
||||
function publish(...args) {
|
||||
|
@ -100,6 +100,7 @@ Base.defaultProps = defaultProps;
|
||||
const SUBSCRIPTIONS_NAME = [
|
||||
'users', 'chat', 'meetings', 'polls', 'presentations',
|
||||
'slides', 'captions', 'breakouts', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
|
||||
'group-chat', 'group-chat-msg',
|
||||
];
|
||||
|
||||
const BaseContainer = withRouter(withTracker(({ params, router }) => {
|
||||
|
@ -52,9 +52,11 @@ export default injectIntl(withTracker(({ params, intl }) => {
|
||||
let systemMessageIntl = {};
|
||||
|
||||
if (chatID === PUBLIC_CHAT_KEY) {
|
||||
messages = ChatService.reduceAndMapMessages((ChatService.getPublicMessages()));
|
||||
messages = ChatService.reduceAndMapGroupMessages(ChatService.getPublicGroupMessages());
|
||||
} else {
|
||||
messages = ChatService.getPrivateMessages(chatID);
|
||||
// messages = ChatService.getPrivateMessages(chatID);
|
||||
messages = ChatService.getPrivateGroupMessages(chatID);
|
||||
|
||||
const user = ChatService.getUser(chatID);
|
||||
chatName = user.name;
|
||||
systemMessageIntl = { 0: user.name };
|
||||
@ -115,7 +117,7 @@ export default injectIntl(withTracker(({ params, intl }) => {
|
||||
|
||||
handleSendMessage: (message) => {
|
||||
ChatService.updateScrollPosition(chatID, null);
|
||||
return ChatService.sendMessage(chatID, message);
|
||||
return ChatService.sendGroupMessage(chatID, message);
|
||||
},
|
||||
|
||||
handleScrollUpdate: position => ChatService.updateScrollPosition(chatID, position),
|
||||
|
@ -1,6 +1,8 @@
|
||||
import Chats from '/imports/api/chat';
|
||||
import Users from '/imports/api/users';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import GroupChatMsg, { GROUP_MESSAGE_PUBLIC_ID, CHAT_ACCESS_PRIVATE } from '/imports/api/group-chat-msg';
|
||||
import GroupChat from '/imports/api/group-chat';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import UnreadMessages from '/imports/ui/services/unread-messages';
|
||||
import Storage from '/imports/ui/services/storage/session';
|
||||
@ -48,6 +50,21 @@ const mapMessage = (message) => {
|
||||
return mappedMessage;
|
||||
};
|
||||
|
||||
const mapGroupMessage = (message) => {
|
||||
const mappedMessage = {
|
||||
id: message._id,
|
||||
content: message.content,
|
||||
time: message.timestamp, // + message.from_tz_offset,
|
||||
sender: null,
|
||||
};
|
||||
|
||||
if (message.sender !== SYSTEM_CHAT_TYPE) {
|
||||
mappedMessage.sender = getUser(message.sender);
|
||||
}
|
||||
|
||||
return mappedMessage;
|
||||
};
|
||||
|
||||
const reduceMessages = (previous, current) => {
|
||||
const lastMessage = previous[previous.length - 1];
|
||||
const currentMessage = current;
|
||||
@ -78,6 +95,42 @@ const reduceMessages = (previous, current) => {
|
||||
const reduceAndMapMessages = messages =>
|
||||
(messages.reduce(reduceMessages, []).map(mapMessage));
|
||||
|
||||
const reduceAndMapGroupMessages = messages => (messages.reduce(reduceGroupMessages, []).map(mapGroupMessage));
|
||||
|
||||
const reduceGroupMessages = (previous, current) => {
|
||||
const lastMessage = previous[previous.length - 1];
|
||||
const currentMessage = current;
|
||||
currentMessage.content = [{
|
||||
id: current.id,
|
||||
text: current.message,
|
||||
time: current.timestamp,
|
||||
}];
|
||||
if (!lastMessage || !currentMessage.chatId === GROUP_MESSAGE_PUBLIC_ID) {
|
||||
return previous.concat(currentMessage);
|
||||
}
|
||||
// Check if the last message is from the same user and time discrepancy
|
||||
// between the two messages exceeds window and then group current message
|
||||
// with the last one
|
||||
const timeOfLastMessage = lastMessage.content[lastMessage.content.length - 1].time;
|
||||
if (lastMessage.sender === currentMessage.sender
|
||||
&& (currentMessage.timestamp - timeOfLastMessage) <= GROUPING_MESSAGES_WINDOW) {
|
||||
lastMessage.content.push(currentMessage.content.pop());
|
||||
return previous;
|
||||
}
|
||||
|
||||
return previous.concat(currentMessage);
|
||||
};
|
||||
|
||||
const getPublicGroupMessages = () => {
|
||||
const publicGroupMessages = GroupChatMsg.find({
|
||||
chatId: GROUP_MESSAGE_PUBLIC_ID
|
||||
}, {
|
||||
sort: ['timestamp']
|
||||
}).fetch();
|
||||
|
||||
return publicGroupMessages;
|
||||
};
|
||||
|
||||
const getPublicMessages = () => {
|
||||
const publicMessages = Chats.find({
|
||||
type: { $in: [PUBLIC_CHAT_TYPE, SYSTEM_CHAT_TYPE] },
|
||||
@ -101,6 +154,28 @@ const getPrivateMessages = (userID) => {
|
||||
return reduceAndMapMessages(messages);
|
||||
};
|
||||
|
||||
const getPrivateGroupMessages = (chatID) => {
|
||||
const sender = getUser(Auth.userID);
|
||||
|
||||
const privateChat = GroupChat.findOne({ users: { $all: [chatID, sender.id] } });
|
||||
|
||||
let messages = [];
|
||||
|
||||
if (privateChat) {
|
||||
const {
|
||||
chatId
|
||||
} = privateChat;
|
||||
|
||||
messages = GroupChatMsg.find({
|
||||
chatId: chatId
|
||||
}, {
|
||||
sort: ['timestamp']
|
||||
}).fetch();
|
||||
}
|
||||
|
||||
return reduceAndMapGroupMessages(messages, []);
|
||||
};
|
||||
|
||||
const isChatLocked = (receiverID) => {
|
||||
const isPublic = receiverID === PUBLIC_CHAT_ID;
|
||||
|
||||
@ -132,6 +207,35 @@ const lastReadMessageTime = (receiverID) => {
|
||||
return UnreadMessages.get(chatType);
|
||||
};
|
||||
|
||||
const sendGroupMessage = (chatID, message) => {
|
||||
|
||||
const isPublicChat = chatID === 'public';
|
||||
|
||||
let chatId = GROUP_MESSAGE_PUBLIC_ID;
|
||||
|
||||
const sender = getUser(Auth.userID);
|
||||
|
||||
if (!isPublicChat) {
|
||||
let privateChat = GroupChat.findOne({ users: { $all: [chatID, sender.id] } });
|
||||
|
||||
if (privateChat) {
|
||||
chatId = privateChat.chatId;
|
||||
}
|
||||
}
|
||||
|
||||
const payload = {
|
||||
color: "0",
|
||||
correlationId: `${sender.id}-${Date.now()}`,
|
||||
sender: {
|
||||
id: sender.id,
|
||||
name: sender.name
|
||||
},
|
||||
message: message
|
||||
};
|
||||
|
||||
return makeCall('sendGroupChatMsg', chatId, payload);
|
||||
};
|
||||
|
||||
const sendMessage = (receiverID, message) => {
|
||||
const isPublic = receiverID === PUBLIC_CHAT_ID;
|
||||
|
||||
@ -247,8 +351,11 @@ const getNotified = (chat) => {
|
||||
|
||||
export default {
|
||||
reduceAndMapMessages,
|
||||
reduceAndMapGroupMessages,
|
||||
getPublicGroupMessages,
|
||||
getPublicMessages,
|
||||
getPrivateMessages,
|
||||
getPrivateGroupMessages,
|
||||
getUser,
|
||||
getScrollPosition,
|
||||
hasUnreadMessages,
|
||||
@ -256,6 +363,7 @@ export default {
|
||||
isChatLocked,
|
||||
updateScrollPosition,
|
||||
updateUnreadMessage,
|
||||
sendGroupMessage,
|
||||
sendMessage,
|
||||
closePrivateChat,
|
||||
removeFromClosedChatsSession,
|
||||
|
@ -27,6 +27,7 @@ const propTypes = {
|
||||
toggleVoice: PropTypes.func.isRequired,
|
||||
changeRole: PropTypes.func.isRequired,
|
||||
roving: PropTypes.func.isRequired,
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
};
|
||||
const SHOW_BRANDING = Meteor.settings.public.app.branding.displayBrandingArea;
|
||||
const defaultProps = {
|
||||
@ -62,6 +63,7 @@ class UserList extends Component {
|
||||
isPublicChat,
|
||||
roving,
|
||||
CustomLogoUrl,
|
||||
getGroupChatPrivate,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -91,6 +93,7 @@ class UserList extends Component {
|
||||
isMeetingLocked,
|
||||
isPublicChat,
|
||||
roving,
|
||||
getGroupChatPrivate,
|
||||
}
|
||||
}
|
||||
/>}
|
||||
|
@ -22,6 +22,7 @@ const propTypes = {
|
||||
toggleVoice: PropTypes.func.isRequired,
|
||||
changeRole: PropTypes.func.isRequired,
|
||||
roving: PropTypes.func.isRequired,
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const UserListContainer = props => <UserList {...props} />;
|
||||
@ -46,4 +47,5 @@ export default withTracker(({ chatID, compact }) => ({
|
||||
roving: Service.roving,
|
||||
CustomLogoUrl: Service.getCustomLogoUrl(),
|
||||
compact,
|
||||
getGroupChatPrivate: Service.getGroupChatPrivate,
|
||||
}))(UserListContainer);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Users from '/imports/api/users';
|
||||
import Chat from '/imports/api/chat';
|
||||
import GroupChat from '/imports/api/group-chat';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import UnreadMessages from '/imports/ui/services/unread-messages';
|
||||
@ -393,6 +394,14 @@ const roving = (event, itemCount, changeState) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getGroupChatPrivate = (sender, receiver) => {
|
||||
let privateChat = GroupChat.findOne({ users: { $all: [receiver.id, sender.id] } });
|
||||
|
||||
if (!privateChat) {
|
||||
makeCall("createGroupChat", receiver);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
setEmojiStatus,
|
||||
assignPresenter,
|
||||
@ -409,4 +418,5 @@ export default {
|
||||
roving,
|
||||
setCustomLogoUrl,
|
||||
getCustomLogoUrl,
|
||||
getGroupChatPrivate,
|
||||
};
|
||||
|
@ -24,6 +24,7 @@ const propTypes = {
|
||||
toggleVoice: PropTypes.func.isRequired,
|
||||
changeRole: PropTypes.func.isRequired,
|
||||
roving: PropTypes.func.isRequired,
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -65,6 +66,7 @@ class UserContent extends Component {
|
||||
normalizeEmojiName={this.props.normalizeEmojiName}
|
||||
isMeetingLocked={this.props.isMeetingLocked}
|
||||
roving={this.props.roving}
|
||||
getGroupChatPrivate={this.props.getGroupChatPrivate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -142,13 +142,17 @@ class UserParticipants extends Component {
|
||||
setEmojiStatus,
|
||||
removeUser,
|
||||
toggleVoice,
|
||||
getGroupChatPrivate,
|
||||
} = this.props;
|
||||
|
||||
const userActions =
|
||||
{
|
||||
openChat: {
|
||||
label: () => intl.formatMessage(intlMessages.ChatLabel),
|
||||
handler: (router, user) => router.push(`/users/chat/${user.id}`),
|
||||
handler: (router, user) => {
|
||||
getGroupChatPrivate(currentUser, user)
|
||||
router.push(`/users/chat/${user.id}`)
|
||||
},
|
||||
icon: 'chat',
|
||||
},
|
||||
clearStatus: {
|
||||
|
@ -12,6 +12,7 @@ import '/imports/api/slides/server';
|
||||
import '/imports/api/breakouts/server';
|
||||
import '/imports/api/chat/server';
|
||||
import '/imports/api/group-chat/server';
|
||||
import '/imports/api/group-chat-msg/server';
|
||||
import '/imports/api/screenshare/server';
|
||||
import '/imports/api/voice-users/server';
|
||||
import '/imports/api/whiteboard-multi-user/server';
|
||||
|
Loading…
Reference in New Issue
Block a user