fix unread messages counter on public chat and remove some old chat configurations

This commit is contained in:
João Francisco Siebel 2018-07-27 10:44:21 -03:00
parent d8391f450b
commit 655483576f
16 changed files with 72 additions and 168 deletions

View File

@ -7,12 +7,3 @@ if (Meteor.isServer) {
}
export default GroupChatMsg;
export const CHAT_ACCESS = {
PUBLIC: 'PUBLIC_ACCESS',
PRIVATE: 'PRIVATE_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';

View File

@ -40,11 +40,11 @@ export default function sendGroupChatMsg(credentials, chatId, message) {
const parsedMessage = parseMessage(message.message);
message.message = parsedMessage
message.message = parsedMessage;
const payload = {
msg: message,
chatId: chatId
chatId,
};
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);

View File

@ -1,4 +1,4 @@
import GroupChatMsg, { CHAT_ACCESS_PUBLIC, GROUP_MESSAGE_PUBLIC_ID } from '/imports/api/group-chat-msg';
import GroupChatMsg from '/imports/api/group-chat-msg';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

View File

@ -1,7 +1,7 @@
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'
import { CHAT_ACCESS_PRIVATE } from '/imports/api/group-chat';
export default function createGroupChat(credentials, receiver) {
@ -16,12 +16,12 @@ export default function createGroupChat(credentials, receiver) {
check(requesterToken, String);
check(receiver, Object);
let payload = {
const payload = {
correlationId: `${requesterUserId}-${Date.now()}`,
msg: [],
users: [receiver.id],
access: CHAT_ACCESS_PRIVATE,
name: receiver.name
name: receiver.name,
};
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);

View File

@ -1,4 +1,4 @@
import GroupChat, { CHAT_ACCESS_PUBLIC } from '/imports/api/group-chat';
import GroupChat from '/imports/api/group-chat';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
@ -14,7 +14,13 @@ function groupChat(credentials) {
Logger.info(`Publishing group-chat for ${meetingId} ${requesterUserId} ${requesterToken}`);
return GroupChat.find({ meetingId });
return GroupChat.find({
$or: [
{ meetingId },
{ meetingId, users: { $all: [requesterUserId] } },
],
});
}
function publish(...args) {

View File

@ -98,7 +98,7 @@ Base.propTypes = propTypes;
Base.defaultProps = defaultProps;
const SUBSCRIPTIONS_NAME = [
'users', 'chat', 'meetings', 'polls', 'presentations',
'users', 'meetings', 'polls', 'presentations',
'slides', 'captions', 'breakouts', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
'group-chat', 'group-chat-msg',
];

View File

@ -1,4 +1,4 @@
import React, {Component} from 'react';
import React, { Component } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { withTracker } from 'meteor/react-meteor-data';
import Chat from './component';
@ -54,7 +54,6 @@ export default injectIntl(withTracker(({ params, intl }) => {
if (chatID === PUBLIC_CHAT_KEY) {
messages = ChatService.reduceAndMapGroupMessages(ChatService.getPublicGroupMessages());
} else {
// messages = ChatService.getPrivateMessages(chatID);
messages = ChatService.getPrivateGroupMessages(chatID);
const user = ChatService.getUser(chatID);

View File

@ -149,7 +149,7 @@ class ChatNotification extends Component {
.filter(({ fromTime, fromUserId }) => fromTime > (this.state.notified[fromUserId] || 0));
const reduceMessages = Service
.reduceAndMapMessages(getChatmessages);
.reduceAndMapGroupMessages(getChatmessages);
if (!reduceMessages.length) return null;
@ -188,7 +188,7 @@ class ChatNotification extends Component {
} = this.props;
const publicUnread = UnreadMessages.getUnreadMessages(publicUserId);
const publicUnreadReduced = Service.reduceAndMapMessages(publicUnread);
const publicUnreadReduced = Service.reduceAndMapGroupMessages(publicUnread);
if (disableNotify) return;
if (!Service.hasUnreadMessages(publicUserId)) return;

View File

@ -16,6 +16,6 @@ export default withTracker(() => {
disableAudio: !AppSettings.chatAudioNotifications,
disableNotify: !AppSettings.chatPushNotifications,
openChats,
publicUserId: Meteor.settings.public.chat.public_userid,
publicUserId: Meteor.settings.public.chat.public_group_id,
};
})(ChatNotificationContainer);

View File

@ -1,7 +1,6 @@
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 GroupChatMsg 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';
@ -14,11 +13,10 @@ const CHAT_CONFIG = Meteor.settings.public.chat;
const GROUPING_MESSAGES_WINDOW = CHAT_CONFIG.grouping_messages_window;
const SYSTEM_CHAT_TYPE = CHAT_CONFIG.type_system;
const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
const PUBLIC_CHAT_USERID = CHAT_CONFIG.public_userid;
const PUBLIC_CHAT_USERNAME = CHAT_CONFIG.public_username;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
const PRIVATE_CHAT_TYPE = CHAT_CONFIG.type_private;
const ScrollCollection = new Mongo.Collection(null);
@ -35,26 +33,11 @@ const getUser = (userId) => {
return mapUser(user);
};
const mapMessage = (message) => {
const mappedMessage = {
id: message._id,
content: message.content,
time: message.fromTime, // + message.from_tz_offset,
sender: null,
};
if (message.type !== SYSTEM_CHAT_TYPE) {
mappedMessage.sender = getUser(message.fromUserId);
}
return mappedMessage;
};
const mapGroupMessage = (message) => {
const mappedMessage = {
id: message._id,
content: message.content,
time: message.timestamp, // + message.from_tz_offset,
time: message.timestamp,
sender: null,
};
@ -65,47 +48,15 @@ const mapGroupMessage = (message) => {
return mappedMessage;
};
const reduceMessages = (previous, current) => {
const lastMessage = previous[previous.length - 1];
const currentMessage = current;
currentMessage.content = [{
id: current._id,
text: current.message,
time: current.fromTime,
}];
if (!lastMessage || !currentMessage.type === SYSTEM_CHAT_TYPE) {
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.fromUserId === currentMessage.fromUserId
&& (currentMessage.fromTime - timeOfLastMessage) <= GROUPING_MESSAGES_WINDOW) {
lastMessage.content.push(currentMessage.content.pop());
return previous;
}
return previous.concat(currentMessage);
};
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 = [{
currentMessage.content = [{
id: current.id,
text: current.message,
time: current.timestamp,
}];
if (!lastMessage || !currentMessage.chatId === GROUP_MESSAGE_PUBLIC_ID) {
if (!lastMessage || !currentMessage.chatId === PUBLIC_GROUP_CHAT_ID) {
return previous.concat(currentMessage);
}
// Check if the last message is from the same user and time discrepancy
@ -121,55 +72,38 @@ const reduceGroupMessages = (previous, current) => {
return previous.concat(currentMessage);
};
const reduceAndMapGroupMessages = messages =>
(messages.reduce(reduceGroupMessages, []).map(mapGroupMessage));
const getPublicGroupMessages = () => {
const publicGroupMessages = GroupChatMsg.find({
chatId: GROUP_MESSAGE_PUBLIC_ID
chatId: PUBLIC_GROUP_CHAT_ID,
}, {
sort: ['timestamp']
sort: ['timestamp'],
}).fetch();
return publicGroupMessages;
};
const getPublicMessages = () => {
const publicMessages = Chats.find({
type: { $in: [PUBLIC_CHAT_TYPE, SYSTEM_CHAT_TYPE] },
}, {
sort: ['fromTime'],
}).fetch();
return publicMessages;
};
const getPrivateMessages = (userID) => {
const messages = Chats.find({
toUsername: { $ne: PUBLIC_CHAT_USERNAME },
$or: [
{ toUserId: userID },
{ fromUserId: userID },
],
}, {
sort: ['fromTime'],
}).fetch();
return reduceAndMapMessages(messages);
};
const getPrivateGroupMessages = (chatID) => {
const sender = getUser(Auth.userID);
const privateChat = GroupChat.findOne({ users: { $all: [chatID, sender.id] } });
const privateChat = GroupChat.findOne({
users: { $all: [chatID, sender.id] },
access: { $not: { $ne: PRIVATE_CHAT_TYPE } },
});
let messages = [];
if (privateChat) {
const {
chatId
chatId,
} = privateChat;
messages = GroupChatMsg.find({
chatId: chatId
chatId,
}, {
sort: ['timestamp']
sort: ['timestamp'],
}).fetch();
}
@ -196,66 +130,44 @@ const isChatLocked = (receiverID) => {
const hasUnreadMessages = (receiverID) => {
const isPublic = receiverID === PUBLIC_CHAT_ID;
const chatType = isPublic ? PUBLIC_CHAT_USERID : receiverID;
const chatType = isPublic ? PUBLIC_GROUP_CHAT_ID : receiverID;
return UnreadMessages.count(chatType) > 0;
};
const lastReadMessageTime = (receiverID) => {
const isPublic = receiverID === PUBLIC_CHAT_ID;
const chatType = isPublic ? PUBLIC_CHAT_USERID : receiverID;
const chatType = isPublic ? PUBLIC_GROUP_CHAT_ID : receiverID;
return UnreadMessages.get(chatType);
};
const sendGroupMessage = (chatID, message) => {
const isPublicChat = chatID === PUBLIC_CHAT_ID;
const isPublicChat = chatID === 'public';
let chatId = GROUP_MESSAGE_PUBLIC_ID;
let chatId = PUBLIC_GROUP_CHAT_ID;
const sender = getUser(Auth.userID);
const receiver = !isPublicChat ? getUser(chatID) : { id: chatID };
if (!isPublicChat) {
let privateChat = GroupChat.findOne({ users: { $all: [chatID, sender.id] } });
const privateChat = GroupChat.findOne({ users: { $all: [chatID, sender.id] } });
if (privateChat) {
chatId = privateChat.chatId;
const { chatId: privateChatId } = privateChat;
chatId = privateChatId;
}
}
const payload = {
color: "0",
color: '0',
correlationId: `${sender.id}-${Date.now()}`,
sender: {
id: sender.id,
name: sender.name
name: sender.name,
},
message: message
};
return makeCall('sendGroupChatMsg', chatId, payload);
};
const sendMessage = (receiverID, message) => {
const isPublic = receiverID === PUBLIC_CHAT_ID;
const sender = getUser(Auth.userID);
const receiver = !isPublic ? getUser(receiverID) : {
id: PUBLIC_CHAT_USERID,
name: PUBLIC_CHAT_USERNAME,
};
/* FIX: Why we need all this payload to send a message?
* The server only really needs the message, from_userid, to_userid and from_lang
*/
const messagePayload = {
message,
fromUserId: sender.id,
fromUsername: sender.name,
fromTimezoneOffset: (new Date()).getTimezoneOffset(),
toUsername: receiver.name,
toUserId: receiver.id,
fromColor: 0,
};
const currentClosedChats = Storage.getItem(CLOSED_CHAT_LIST_KEY);
@ -265,7 +177,7 @@ const sendMessage = (receiverID, message) => {
Storage.setItem(CLOSED_CHAT_LIST_KEY, _.without(currentClosedChats, receiver.id));
}
return makeCall('sendChat', messagePayload);
return makeCall('sendGroupChatMsg', chatId, payload);
};
const getScrollPosition = (receiverID) => {
@ -281,7 +193,7 @@ const updateScrollPosition =
const updateUnreadMessage = (receiverID, timestamp) => {
const isPublic = receiverID === PUBLIC_CHAT_ID;
const chatType = isPublic ? PUBLIC_CHAT_USERID : receiverID;
const chatType = isPublic ? PUBLIC_GROUP_CHAT_ID : receiverID;
return UnreadMessages.update(chatType, timestamp);
};
@ -350,11 +262,8 @@ const getNotified = (chat) => {
};
export default {
reduceAndMapMessages,
reduceAndMapGroupMessages,
getPublicGroupMessages,
getPublicMessages,
getPrivateMessages,
getPrivateGroupMessages,
getUser,
getScrollPosition,
@ -364,7 +273,6 @@ export default {
updateScrollPosition,
updateUnreadMessage,
sendGroupMessage,
sendMessage,
closePrivateChat,
removeFromClosedChatsSession,
exportChat,

View File

@ -16,7 +16,7 @@ const ALLOW_MODERATOR_TO_UNMUTE_AUDIO = APP_CONFIG.allowModeratorToUnmuteAudio;
const CHAT_CONFIG = Meteor.settings.public.chat;
const PRIVATE_CHAT_TYPE = CHAT_CONFIG.type_private;
const PUBLIC_CHAT_USERID = CHAT_CONFIG.public_userid;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
// session for closed chat list
const CLOSED_CHAT_LIST_KEY = 'closedChatList';
@ -230,7 +230,7 @@ const getOpenChats = (chatID) => {
id: 'public',
name: 'Public Chat',
icon: 'group_chat',
unreadCounter: UnreadMessages.count(PUBLIC_CHAT_USERID),
unreadCounter: UnreadMessages.count(PUBLIC_GROUP_CHAT_ID),
});
return openChats
@ -395,10 +395,10 @@ const roving = (event, itemCount, changeState) => {
};
const getGroupChatPrivate = (sender, receiver) => {
let privateChat = GroupChat.findOne({ users: { $all: [receiver.id, sender.id] } });
const privateChat = GroupChat.findOne({ users: { $all: [receiver.id, sender.id] } });
if (!privateChat) {
makeCall("createGroupChat", receiver);
makeCall('createGroupChat', receiver);
}
};

View File

@ -150,8 +150,8 @@ class UserParticipants extends Component {
openChat: {
label: () => intl.formatMessage(intlMessages.ChatLabel),
handler: (router, user) => {
getGroupChatPrivate(currentUser, user)
router.push(`/users/chat/${user.id}`)
getGroupChatPrivate(currentUser, user);
router.push(`/users/chat/${user.id}`);
},
icon: 'chat',
},

View File

@ -2,16 +2,16 @@ import { Tracker } from 'meteor/tracker';
import Storage from '/imports/ui/services/storage/session';
import Auth from '/imports/ui/services/auth';
import Chats from '/imports/api/chat';
import GroupChatMsg from '/imports/api/group-chat-msg';
const CHAT_CONFIG = Meteor.settings.public.chat;
const STORAGE_KEY = CHAT_CONFIG.storage_key;
const PUBLIC_CHAT_USERID = CHAT_CONFIG.public_userid;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
class UnreadMessagesTracker {
constructor() {
this._tracker = new Tracker.Dependency();
this._unreadChats = { ...Storage.getItem('UNREAD_CHATS'), [PUBLIC_CHAT_USERID]: (new Date()).getTime() };
this._unreadChats = { ...Storage.getItem('UNREAD_CHATS'), [PUBLIC_GROUP_CHAT_ID]: (new Date()).getTime() };
this.get = this.get.bind(this);
}
@ -33,19 +33,19 @@ class UnreadMessagesTracker {
getUnreadMessages(chatID) {
const filter = {
fromTime: {
timestamp: {
$gt: this.get(chatID),
},
fromUserId: { $ne: Auth.userID },
sender: { $ne: Auth.userID },
};
// Minimongo does not support $eq. See https://github.com/meteor/meteor/issues/4142
if (chatID === PUBLIC_CHAT_USERID) {
filter.toUserId = { $not: { $ne: chatID } };
if (chatID === PUBLIC_GROUP_CHAT_ID) {
filter.chatId = { $not: { $ne: chatID } };
} else {
filter.toUserId = { $not: { $ne: Auth.userID } };
filter.fromUserId.$not = { $ne: chatID };
filter.sender.$not = { $ne: chatID };
}
const messages = Chats.find(filter).fetch();
const messages = GroupChatMsg.find(filter).fetch();
return messages;
}

View File

@ -149,11 +149,12 @@
"max_message_length": 5000,
"grouping_messages_window": 10000,
"type_system": "SYSTEM_MESSAGE",
"type_public": "PUBLIC_CHAT",
"type_private": "PRIVATE_CHAT",
"type_public": "PUBLIC_ACCESS",
"type_private": "PRIVATE_ACCESS",
"system_userid": "SYSTEM_MESSAGE",
"system_username": "SYSTEM_MESSAGE",
"public_id": "public",
"public_group_id": "MAIN-PUBLIC-GROUP-CHAT",
"public_userid": "public_chat_userid",
"public_username": "public_chat_username",
"storage_key": "UNREAD_CHATS",
@ -377,7 +378,6 @@
]
},
"log": {
"level": "info"
}

View File

@ -149,11 +149,12 @@
"max_message_length": 5000,
"grouping_messages_window": 10000,
"type_system": "SYSTEM_MESSAGE",
"type_public": "PUBLIC_CHAT",
"type_private": "PRIVATE_CHAT",
"type_public": "PUBLIC_ACCESS",
"type_private": "PRIVATE_ACCESS",
"system_userid": "SYSTEM_MESSAGE",
"system_username": "SYSTEM_MESSAGE",
"public_id": "public",
"public_group_id": "MAIN-PUBLIC-GROUP-CHAT",
"public_userid": "public_chat_userid",
"public_username": "public_chat_username",
"storage_key": "UNREAD_CHATS",

View File

@ -10,7 +10,6 @@ import '/imports/api/captions/server';
import '/imports/api/presentations/server';
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';