diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/index.js b/bigbluebutton-html5/imports/api/group-chat-msg/index.js index 8a0e3b5fff..6d6b838d7d 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/index.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/index.js @@ -1,9 +1,11 @@ import { Meteor } from 'meteor/meteor'; const GroupChatMsg = new Mongo.Collection('group-chat-msg'); +const UsersTyping = new Mongo.Collection('users-typing'); if (Meteor.isServer) { GroupChatMsg._ensureIndex({ meetingId: 1, chatId: 1 }); + UsersTyping._ensureIndex({ meetingId: 1, userId: 1 }); } -export default GroupChatMsg; +export { GroupChatMsg, UsersTyping }; diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/handlers/userTyping.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/handlers/userTyping.js index 6991677840..24456ec547 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/handlers/userTyping.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/handlers/userTyping.js @@ -1,5 +1,5 @@ import { check } from 'meteor/check'; -import Users from '/imports/api/users'; +import { UsersTyping } from '/imports/api/group-chat-msg'; import startTyping from '../modifiers/startTyping'; export default function handleUserTyping({ body }, meetingId) { @@ -9,16 +9,5 @@ export default function handleUserTyping({ body }, meetingId) { check(userId, String); check(chatId, String); - const user = Users.findOne({ - userId, - meetingId, - }, { - fields: { - isTyping: 1, - }, - }); - - if (user && !user.isTyping) { - startTyping(meetingId, userId, chatId); - } + startTyping(meetingId, userId, chatId); } diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/startUserTyping.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/startUserTyping.js index 4b88e07055..0823891959 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/startUserTyping.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/startUserTyping.js @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; +import { UsersTyping } from '/imports/api/group-chat-msg'; import RedisPubSub from '/imports/startup/server/redis'; export default function startUserTyping(credentials, chatId) { @@ -14,6 +15,13 @@ export default function startUserTyping(credentials, chatId) { check(requesterUserId, String); check(chatId, String); + const userTyping = UsersTyping.findOne({ + meetingId, + userId: requesterUserId, + }); + + if (userTyping) return; + const payload = { chatId: chatId || PUBLIC_GROUP_CHAT_ID, }; diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/stopUserTyping.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/stopUserTyping.js index d219d8096f..31cc951a9a 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/stopUserTyping.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/methods/stopUserTyping.js @@ -1,5 +1,5 @@ import { check } from 'meteor/check'; -import Users from '/imports/api/users'; +import { UsersTyping } from '/imports/api/group-chat-msg'; import stopTyping from '../modifiers/stopTyping'; export default function stopUserTyping(credentials) { @@ -8,16 +8,12 @@ export default function stopUserTyping(credentials) { check(meetingId, String); check(requesterUserId, String); - const user = Users.findOne({ - userId: requesterUserId, + const userTyping = UsersTyping.findOne({ meetingId, - }, { - fields: { - isTyping: 1, - }, + userId: requesterUserId, }); - if (user && user.isTyping) { + if (userTyping) { stopTyping(meetingId, requesterUserId); } } diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/addGroupChatMsg.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/addGroupChatMsg.js index 60377b0e45..05d60b1073 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/addGroupChatMsg.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/addGroupChatMsg.js @@ -1,7 +1,7 @@ import flat from 'flat'; import { Match, check } from 'meteor/check'; import Logger from '/imports/startup/server/logger'; -import GroupChatMsg from '/imports/api/group-chat-msg'; +import { GroupChatMsg } from '/imports/api/group-chat-msg'; import { BREAK_LINE } from '/imports/utils/lineEndings'; const parseMessage = (message) => { diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/startTyping.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/startTyping.js index 0632830896..618a6fc35d 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/startTyping.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/startTyping.js @@ -1,6 +1,7 @@ import { check } from 'meteor/check'; import Logger from '/imports/startup/server/logger'; import Users from '/imports/api/users'; +import { UsersTyping } from '/imports/api/group-chat-msg'; export default function startTyping(meetingId, userId, chatId) { check(meetingId, String); @@ -11,11 +12,13 @@ export default function startTyping(meetingId, userId, chatId) { userId, }; - const modifier = { - $set: { - isTyping: true, - isTypingTo: chatId, - }, + const user = Users.findOne(selector); + + const mod = { + meetingId, + userId, + name: user.name, + isTypingTo: chatId, }; const cb = (err) => { @@ -25,5 +28,5 @@ export default function startTyping(meetingId, userId, chatId) { return Logger.info(`Typing indicator update for userId={${userId}} chatId={${chatId}}`); }; - return Users.update(selector, modifier, cb); + return UsersTyping.upsert(selector, mod, cb); } diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/stopTyping.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/stopTyping.js index b08328333e..7e538f1138 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/stopTyping.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/modifiers/stopTyping.js @@ -1,6 +1,6 @@ import { check } from 'meteor/check'; import Logger from '/imports/startup/server/logger'; -import Users from '/imports/api/users'; +import { UsersTyping } from '/imports/api/group-chat-msg'; export default function stopTyping(meetingId, userId) { check(meetingId, String); @@ -9,22 +9,14 @@ export default function stopTyping(meetingId, userId) { const selector = { meetingId, userId, - isTyping: true, - }; - - const modifier = { - $set: { - isTyping: false, - isTypingTo: '', - }, }; const cb = (err) => { if (err) { return Logger.error(`Stop user=${userId} typing indicator error: ${err}`); } - return Logger.info(`Stopped user=${userId} typing indicator`); + return Logger.info(`Stopped typing indicator for user=${userId}`); }; - return Users.update(selector, modifier, cb); + return UsersTyping.remove(selector, cb); } diff --git a/bigbluebutton-html5/imports/api/group-chat-msg/server/publishers.js b/bigbluebutton-html5/imports/api/group-chat-msg/server/publishers.js index d5cc4fd5ba..cc9282cdfe 100644 --- a/bigbluebutton-html5/imports/api/group-chat-msg/server/publishers.js +++ b/bigbluebutton-html5/imports/api/group-chat-msg/server/publishers.js @@ -1,4 +1,4 @@ -import GroupChatMsg from '/imports/api/group-chat-msg'; +import { GroupChatMsg, UsersTyping } from '/imports/api/group-chat-msg'; import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; @@ -30,3 +30,20 @@ function publish(...args) { } Meteor.publish('group-chat-msg', publish); + +function usersTyping(credentials) { + const { meetingId, requesterUserId, requesterToken } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(requesterToken, String); + + return UsersTyping.find({ meetingId }); +} + +function pubishUsersTyping(...args) { + const boundUsersTyping = usersTyping.bind(this); + return boundUsersTyping(...args); +} + +Meteor.publish('users-typing', pubishUsersTyping); diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js index aaf00a1fbc..f07769e758 100755 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js @@ -62,8 +62,6 @@ export default function addUser(meetingId, user) { inactivityCheck: false, responseDelay: 0, loggedOut: false, - isTyping: false, - isTypingTo: '', }, flat(user), ), diff --git a/bigbluebutton-html5/imports/ui/components/chat/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/component.jsx index ad942295a4..8ae1877821 100755 --- a/bigbluebutton-html5/imports/ui/components/chat/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/component.jsx @@ -54,7 +54,7 @@ const Chat = (props) => { UnsentMessagesCollection, isMeteorConnected, typingUsers, - currentUser, + currentUserId, startUserTyping, stopUserTyping, } = props; @@ -63,13 +63,13 @@ const Chat = (props) => { const CLOSE_CHAT_AK = shortcuts.closePrivateChat; let names = []; + names = typingUsers.map((user) => { - const { userId } = currentUser; const { userId: typingUserId, isTypingTo, name } = user; - if (userId === typingUserId) return null; + if (currentUserId === typingUserId) return null; if (chatID !== isTypingTo) { if (typingUserId === chatID) { - return userId !== isTypingTo + return currentUserId !== isTypingTo ? null : name; } return null; diff --git a/bigbluebutton-html5/imports/ui/components/chat/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/container.jsx index d18fb3837c..09c4853d37 100755 --- a/bigbluebutton-html5/imports/ui/components/chat/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/container.jsx @@ -4,6 +4,7 @@ import { withTracker } from 'meteor/react-meteor-data'; import { Session } from 'meteor/session'; import Auth from '/imports/ui/services/auth'; import Users from '/imports/api/users'; +import { UsersTyping } from '/imports/api/group-chat-msg'; import { makeCall } from '/imports/ui/services/api'; import Chat from './component'; import ChatService from './service'; @@ -149,15 +150,8 @@ export default injectIntl(withTracker(({ intl }) => { const { connected: isMeteorConnected } = Meteor.status(); - const typingUsers = Users.find({ + const typingUsers = UsersTyping.find({ meetingId: Auth.meetingID, - isTyping: true, - }, { - fields: { - userId: 1, - isTypingTo: 1, - name: 1, - }, }).fetch(); const currentUser = Users.findOne({ @@ -172,7 +166,7 @@ export default injectIntl(withTracker(({ intl }) => { return { startUserTyping: chatId => makeCall('startUserTyping', chatId), stopUserTyping: () => makeCall('stopUserTyping'), - currentUser, + currentUserId: currentUser ? currentUser.userId : null, typingUsers, chatID, chatName, diff --git a/bigbluebutton-html5/imports/ui/components/chat/service.js b/bigbluebutton-html5/imports/ui/components/chat/service.js index ae60731d45..f1f7c7aa47 100755 --- a/bigbluebutton-html5/imports/ui/components/chat/service.js +++ b/bigbluebutton-html5/imports/ui/components/chat/service.js @@ -1,6 +1,6 @@ import Users from '/imports/api/users'; import Meetings from '/imports/api/meetings'; -import GroupChatMsg 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'; diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx index 3b2206686b..fbd017a097 100644 --- a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx @@ -17,7 +17,7 @@ const SUBSCRIPTIONS = [ 'users', 'meetings', 'polls', 'presentations', 'slides', 'captions', 'voiceUsers', 'whiteboard-multi-user', 'screenshare', 'group-chat', 'presentation-pods', 'users-settings', 'guestUser', 'users-infos', 'note', - 'network-information', 'ping-pong', + 'network-information', 'ping-pong', 'users-typing', ]; class Subscriptions extends React.Component { diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js index 48841c0a42..d8cdaa5cae 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/service.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js @@ -1,6 +1,6 @@ import Users from '/imports/api/users'; import GroupChat from '/imports/api/group-chat'; -import GroupChatMsg from '/imports/api/group-chat-msg'; +import { GroupChatMsg } from '/imports/api/group-chat-msg'; import Breakouts from '/imports/api/breakouts/'; import Meetings from '/imports/api/meetings'; import Auth from '/imports/ui/services/auth'; diff --git a/bigbluebutton-html5/imports/ui/services/unread-messages/index.js b/bigbluebutton-html5/imports/ui/services/unread-messages/index.js index 70d5c1d052..7eb0f22041 100755 --- a/bigbluebutton-html5/imports/ui/services/unread-messages/index.js +++ b/bigbluebutton-html5/imports/ui/services/unread-messages/index.js @@ -3,7 +3,7 @@ import { Tracker } from 'meteor/tracker'; import Storage from '/imports/ui/services/storage/session'; import Auth from '/imports/ui/services/auth'; import GroupChat from '/imports/api/group-chat'; -import GroupChatMsg from '/imports/api/group-chat-msg'; +import { GroupChatMsg } from '/imports/api/group-chat-msg'; const CHAT_CONFIG = Meteor.settings.public.chat; const STORAGE_KEY = CHAT_CONFIG.storage_key;