Spaces:
Paused
Paused
| const ChatRoom = require("../models/ChatRoom"); | |
| const User = require("../models/User"); | |
| const catchAsyncError = require("../utilities/catchAsyncError"); | |
| const ReqError = require("../utilities/ReqError"); | |
| exports.createChatRoom = async (chatRoomDetails) => | |
| await ChatRoom.create(chatRoomDetails); | |
| exports.getChatRoom = catchAsyncError(async (req, res, next) => { | |
| const chatRoom = await ChatRoom.findById(req.params.chatRoomId); | |
| if (!chatRoom) return next(new ReqError(400, "Chat does not exist")); | |
| res.status(200).json({ | |
| status: "success", | |
| data: { chatRoom }, | |
| }); | |
| }); | |
| exports.getChatRoomSummaryForUser = catchAsyncError(async (req, res, next) => { | |
| // Get user | |
| const user = await User.findById(req.cookies.userId); | |
| let chatRoomSummary = await Promise.all( | |
| user.chatRooms.map(async (chatRoomId) => { | |
| const outputSummary = {}; | |
| // Get chatRoom object | |
| const chatRoom = await ChatRoom.findById(chatRoomId).populate({ | |
| path: "members", | |
| select: "id username avatar bio status", | |
| }); | |
| if (!chatRoom) return next(new ReqError("Chat room can't be found")); | |
| // If there are messages in the room message in chatRoom | |
| if (chatRoom.messageHistory.length) { | |
| // Get chatRoom latest message | |
| const lastDay = | |
| chatRoom.messageHistory[chatRoom.messageHistory.length - 1]; | |
| outputSummary.latestMessage = | |
| lastDay.messages[lastDay.messages.length - 1]; | |
| // Get how many messages are unread by user in the chatRoom | |
| outputSummary.unreadMessagesCount = user.unreadMessages.reduce( | |
| (acc, curr) => { | |
| if (chatRoomId.toString() === curr.chatRoomId.toString()) | |
| return (acc += 1); | |
| return acc; | |
| }, | |
| 0 | |
| ); | |
| } else { | |
| outputSummary.latestMessage = {}; | |
| outputSummary.unreadMessagesCount = 0; | |
| } | |
| // Attach chatRoomId | |
| outputSummary.chatRoomId = chatRoomId; | |
| outputSummary.roomType = chatRoom.roomType; | |
| // If roomType is private | |
| if (chatRoom.roomType === "Private") { | |
| const profile = chatRoom.members.find( | |
| (member) => user._id.toString() !== member._id.toString() | |
| ); | |
| outputSummary.profile = profile; | |
| outputSummary.profile.name = user.contacts.find( | |
| (contact) => | |
| contact.contactDetails.toString() === profile._id.toString() | |
| )?.name; | |
| } | |
| outputSummary.mode = null; | |
| // Check if chat is pinned | |
| outputSummary.pinned = user.pinnedChatRooms.some( | |
| (chatRoom) => chatRoom.toString() === chatRoomId.toString() | |
| ); | |
| return outputSummary; | |
| }) | |
| ); | |
| // Get all pinned chats and sort based on newest message | |
| const pinnedChats = chatRoomSummary | |
| .filter((chatRoom) => chatRoom.pinned) | |
| .sort((a, b) => { | |
| const latestMessageInATime = new Date(a.latestMessage.timeSent).getTime(); | |
| const latestMessageInBTime = new Date(b.latestMessage.timeSent).getTime(); | |
| return latestMessageInBTime - latestMessageInATime; | |
| }); | |
| // Get all unpinned chats and sort based on newest message | |
| const unpinnedChats = chatRoomSummary | |
| .filter((chatRoom) => !chatRoom.pinned) | |
| .sort((a, b) => { | |
| const latestMessageInATime = new Date(a.latestMessage.timeSent).getTime(); | |
| const latestMessageInBTime = new Date(b.latestMessage.timeSent).getTime(); | |
| return latestMessageInBTime - latestMessageInATime; | |
| }); | |
| // Concatenate both arrays | |
| chatRoomSummary = [...pinnedChats, ...unpinnedChats]; | |
| res.status(200).json({ | |
| status: "success", | |
| data: { | |
| chatRoomSummary, | |
| }, | |
| }); | |
| }); | |
| exports.pinChatRoom = catchAsyncError(async (req, res, next) => { | |
| const user = await User.findById(req.cookies.userId); | |
| user.pinnedChatRooms.push(req.params.chatRoomId); | |
| await user.save(); | |
| res.status(200).json({ | |
| status: "success", | |
| data: { | |
| pinnedChatRooms: user.pinnedChatRooms, | |
| }, | |
| }); | |
| }); | |
| exports.unpinChatRoom = catchAsyncError(async (req, res, next) => { | |
| const user = await User.findById(req.cookies.userId); | |
| user.pinnedChatRooms = user.pinnedChatRooms.filter( | |
| (chatRoomId) => chatRoomId.toString() !== req.params.chatRoomId | |
| ); | |
| await user.save(); | |
| res.status(200).json({ | |
| status: "success", | |
| data: { | |
| pinnedChatRooms: user.pinnedChatRooms, | |
| }, | |
| }); | |
| }); | |
| exports.checkIfChatRoomExists = async (user, secondaryUser) => { | |
| let chatRoomId; | |
| // secondaryUser is the user not performing the action | |
| // Chat room exists if secondaryUser already has user as a contact | |
| secondaryUser.contacts.forEach((contact) => { | |
| if (contact.contactDetails.toString() === user._id.toString()) { | |
| chatRoomId = contact.chatRoomId; | |
| } | |
| }); | |
| return chatRoomId; | |
| }; | |
| exports.deleteChatRoom = async (chatRoomId) => { | |
| await ChatRoom.findByIdAndDelete(chatRoomId); | |
| }; | |
| exports.clearChatRoom = async ({ chatRoomId }) => { | |
| const chatRoom = await ChatRoom.findById(chatRoomId); | |
| chatRoom.messageHistory = []; | |
| for (memberId of chatRoom.members) { | |
| const memberModel = await User.findById(memberId); | |
| memberModel.unreadMessages = memberModel.unreadMessages.filter( | |
| (data) => data.chatRoomId.toString() !== chatRoom._id.toString() | |
| ); | |
| memberModel.undeliveredMessages = memberModel.undeliveredMessages.filter( | |
| (data) => data.chatRoomId.toString() !== chatRoom._id.toString() | |
| ); | |
| await memberModel.save(); | |
| } | |
| await chatRoom.save(); | |
| }; | |
| // Get all chat room user belongs to | |
| exports.getAllChatRoomUserIn = async (userId) => { | |
| const user = await User.findById(userId); | |
| return user.chatRooms; | |
| }; | |
| // Add message to chatroom | |
| exports.addMessageToChatRoom = async (chatRoomId, message) => { | |
| const chatRoom = await ChatRoom.findById(chatRoomId); | |
| // Get last chatRoom day message | |
| const lastDayMessage = | |
| chatRoom.messageHistory[chatRoom.messageHistory.length - 1]; | |
| // Get day message was sent | |
| const dayString = new Date(message.timeSent).toLocaleString("en-US", { | |
| month: "long", | |
| day: "2-digit", | |
| year: "numeric", | |
| }); | |
| // Convert day string to milliseconds | |
| const day = new Date(dayString).getTime(); | |
| // Add list of all members to message undelivered and unread members | |
| message.undeliveredMembers = chatRoom.members; | |
| message.unreadMembers = chatRoom.members.filter( | |
| (memberId) => memberId.toString() !== message.sender.toString() | |
| ); | |
| // Check if day is today | |
| if (lastDayMessage?.day === day) { | |
| // Add to object if day is today | |
| lastDayMessage.messages.push(message); | |
| } else { | |
| // Else create new object for day | |
| const newDayObject = { | |
| day, | |
| messages: [message], | |
| }; | |
| chatRoom.messageHistory.push(newDayObject); | |
| } | |
| await chatRoom.save(); | |
| // Return message object included with message id | |
| const messageObj = | |
| chatRoom.messageHistory[chatRoom.messageHistory.length - 1].messages[ | |
| chatRoom.messageHistory[chatRoom.messageHistory.length - 1].messages | |
| .length - 1 | |
| ]; | |
| return { messageObj, chatRoom, day }; | |
| }; | |
| exports.getMessageFromChatRoom = async ({ chatRoomId, messageId, day }) => { | |
| // Get chat room | |
| const chatRoom = await ChatRoom.findById(chatRoomId); | |
| if (!chatRoom.messageHistory.length) return {}; | |
| // Get dayMessages | |
| const dayMessage = chatRoom.messageHistory.find( | |
| (dayMessage) => dayMessage.day === day | |
| ); | |
| // Get message obj | |
| const message = dayMessage.messages.find( | |
| (message) => message._id.toString() === messageId.toString() | |
| ); | |
| return { chatRoom, message }; | |
| }; | |
| // Check member off undelivered list in message | |
| exports.checkMembersOffUndeliveredListInMessage = async ({ | |
| membersId, | |
| messageId, | |
| chatRoomId, | |
| day, | |
| io, | |
| }) => { | |
| const { message, chatRoom } = await this.getMessageFromChatRoom({ | |
| day, | |
| messageId, | |
| chatRoomId, | |
| }); | |
| if (!message) return; | |
| message.undeliveredMembers = message.undeliveredMembers.filter( | |
| (memberId) => !membersId.includes(memberId.toString()) | |
| ); | |
| if (!message.undeliveredMembers.length) { | |
| message.deliveredStatus = true; | |
| // Emit message been delivered | |
| io.to(chatRoomId).emit("user:messageDelivered", { | |
| messageId: message._id, | |
| senderId: message.sender, | |
| chatRoomId, | |
| day, | |
| }); | |
| } | |
| await chatRoom.save(); | |
| return { | |
| undeliveredMembers: message.undeliveredMembers, | |
| messageDelivered: message.deliveredStatus, | |
| }; | |
| }; | |
| // Add message as unread to users | |
| exports.addMessageAsUndeliveredToUser = async ({ | |
| undeliveredMembers, | |
| chatRoomId, | |
| messageId, | |
| day, | |
| }) => { | |
| for (let memberId of undeliveredMembers) { | |
| const memberModel = await User.findById(memberId.toString()); | |
| // If message hasn't been added as undelivered before, add | |
| memberModel.undeliveredMessages.push({ | |
| day, | |
| chatRoomId, | |
| messageId, | |
| }); | |
| await memberModel.save(); | |
| } | |
| }; | |
| exports.addMessageAsUnreadToUser = async ({ | |
| unreadMembers, | |
| chatRoomId, | |
| messageId, | |
| day, | |
| }) => { | |
| for (let memberId of unreadMembers) { | |
| const memberModel = await User.findById(memberId); | |
| memberModel.unreadMessages.push({ | |
| day, | |
| chatRoomId, | |
| messageId, | |
| }); | |
| await memberModel.save(); | |
| } | |
| }; | |
| // Mark messages as read by user | |
| exports.markMessageAsReadByUser = async ({ | |
| messageId, | |
| chatRoomId, | |
| day, | |
| userId, | |
| io, | |
| }) => { | |
| const { message, chatRoom } = await this.getMessageFromChatRoom({ | |
| messageId, | |
| chatRoomId, | |
| day, | |
| }); | |
| if (!message) return; | |
| const user = await User.findById(userId); | |
| user.unreadMessages = user.unreadMessages.filter( | |
| (message) => message.messageId.toString() !== messageId.toString() | |
| ); | |
| message.unreadMembers = message.unreadMembers.filter( | |
| (memberId) => memberId.toString() !== userId.toString() | |
| ); | |
| if (!message.unreadMembers.length) { | |
| message.readStatus = true; | |
| // Emit message as been read by all members | |
| io.to(chatRoomId).emit("user:messageReadByAllMembers", { | |
| messageId: message._id, | |
| senderId: message.sender, | |
| chatRoomId, | |
| day, | |
| }); | |
| } | |
| await chatRoom.save(); | |
| await user.save(); | |
| }; | |