diff --git a/docs/api/chat.swagger.ts b/docs/api/chat.swagger.ts index d397fd8..177256e 100644 --- a/docs/api/chat.swagger.ts +++ b/docs/api/chat.swagger.ts @@ -124,6 +124,20 @@ * items: * type: string * description: IDs of users blocked by this member. + * unreadMessages: + * type: array + * items: + * type: object + * properties: + * chatId: + * type: string + * description: Unique identifier of the chat this message belongs to. + * unreadMessagesCount: + * type: string + * description: Number of unread messages in the chat. + * isMentioned: + * type: boolean + * description: Indicates if the user is mentioned in the chat. * lastMessages: * type: array * items: @@ -171,12 +185,6 @@ * type: string * format: date-time * description: Timestamp when the message was sent. - * __v: - * type: integer - * description: Version key. - * id: - * type: string - * description: Alias for `_id`. * 401: * description: User is not logged in or the request is invalid. * content: diff --git a/docs/api/sockets.swagger.ts b/docs/api/sockets.swagger.ts index 785f66b..b031547 100644 --- a/docs/api/sockets.swagger.ts +++ b/docs/api/sockets.swagger.ts @@ -45,6 +45,9 @@ * isForward: * type: boolean * description: Indicates if the message is forwarded. + * isAnouncement: + * type: boolean + * description: Indicates if the message is an anouncement. * responses: * 200: * description: Message sent successfully. diff --git a/src/controllers/chatController.ts b/src/controllers/chatController.ts index 2fbbbdb..61fd401 100644 --- a/src/controllers/chatController.ts +++ b/src/controllers/chatController.ts @@ -45,7 +45,7 @@ export const getAllChats = catchAsync( 'username screenFirstName screenLastName phoneNumber photo status isAdmin stories blockedUsers' ), getLastMessage(allChats), - getUnreadMessages(allChats, userId), + getUnreadMessages(allChats, user), ]); res.status(200).json({ diff --git a/src/services/chatService.ts b/src/services/chatService.ts index cc92021..f3405f7 100644 --- a/src/services/chatService.ts +++ b/src/services/chatService.ts @@ -25,17 +25,21 @@ export const getLastMessage = async (chats: any) => { return lastMessages; }; -export const getUnreadMessages = async ( - chats: any, - userId: mongoose.Types.ObjectId -) => +export const getUnreadMessages = async (chats: any, user: any) => Promise.all( chats.map(async (chat: any) => ({ chatId: chat.chat._id, unreadMessagesCount: await Message.countDocuments({ chatId: chat.chat._id, - readBy: { $nin: [userId] }, + readBy: { $nin: [user._id] }, }), + isMentioned: + (await Message.exists({ + chatId: chat.chat._id, + readBy: { $nin: [user._id] }, + senderId: { $ne: user._id }, + content: new RegExp(`@${user.username}`, 'i'), + })) !== null, })) ); diff --git a/src/services/googleAIService.ts b/src/services/googleAIService.ts index de0e7c0..b4af570 100644 --- a/src/services/googleAIService.ts +++ b/src/services/googleAIService.ts @@ -5,33 +5,37 @@ const hf = new HfInference(process.env.HF_API_KEY); const modelName = 'unitary/toxic-bert'; async function detectInappropriateContent(text: string): Promise { - try { - const response = await hf.textClassification({ - model: modelName, - inputs: text, - }); + try { + const response = await hf.textClassification({ + model: modelName, + inputs: text, + }); - console.log('Model Response:', JSON.stringify(response, null, 2)); + console.log('Model Response:', JSON.stringify(response, null, 2)); - const relevantLabels = ['toxic', 'obscene', 'insult', 'severe_toxic']; - const threshold = 0.7; + const relevantLabels = ['toxic', 'obscene', 'insult', 'severe_toxic']; + const threshold = 0.7; - interface TextClassificationResult { - label: string; - score: number; - } - - const toxicityScore = (response as TextClassificationResult[]) - .filter((result) => relevantLabels.includes(result.label.toLowerCase()) && result.score > threshold) - .reduce((acc, curr) => acc + curr.score, 0); - - console.log(`Total Toxicity Score: ${toxicityScore}`); - - return toxicityScore < threshold; - } catch (error) { - console.error('Error detecting inappropriate content:', error); - throw new Error('Failed to detect inappropriate content'); + interface TextClassificationResult { + label: string; + score: number; } + + const toxicityScore = (response as TextClassificationResult[]) + .filter( + (result) => + relevantLabels.includes(result.label.toLowerCase()) && + result.score > threshold + ) + .reduce((acc, curr) => acc + curr.score, 0); + + console.log(`Total Toxicity Score: ${toxicityScore}`); + + return toxicityScore >= threshold; + } catch (error) { + console.error('Error detecting inappropriate content:', error); + throw new Error('Failed to detect inappropriate content'); + } } -export default detectInappropriateContent; \ No newline at end of file +export default detectInappropriateContent; diff --git a/src/sockets/MessagingServices.ts b/src/sockets/MessagingServices.ts index ca076c8..c3301ae 100644 --- a/src/sockets/MessagingServices.ts +++ b/src/sockets/MessagingServices.ts @@ -58,17 +58,11 @@ export const check = async ( message: 'you do not have permission as you are not an admin', }); - if (sendMessage && sender.Role !== 'admin' && chat.type !== 'private') { + if (sendMessage && chat.type !== 'private') { const groupChannelChat = await GroupChannel.findById(chat._id); - - if (!groupChannelChat.messagingPermission) - return ack({ - success: false, - message: 'only admins can post and reply to this chat', - }); if ( chat?.type === 'group' && - !chat.isFilterd && + chat.isFilterd && (await detectInappropriateContent(content)) ) { return ack({ @@ -76,11 +70,18 @@ export const check = async ( message: 'inappropriate content', }); } - if (chat.type === 'channel' && !newMessageIsReply) - return ack({ - success: false, - message: 'only admins can post to this channel', - }); + if (sender.Role !== 'admin') { + if (!groupChannelChat.messagingPermission) + return ack({ + success: false, + message: 'only admins can post and reply to this chat', + }); + if (chat.type === 'channel' && !newMessageIsReply) + return ack({ + success: false, + message: 'only admins can post to this channel', + }); + } } return true; }; diff --git a/src/sockets/chats.ts b/src/sockets/chats.ts index d8f661f..1faad14 100644 --- a/src/sockets/chats.ts +++ b/src/sockets/chats.ts @@ -121,7 +121,7 @@ const handleAddMembers = async ( chat?.members.push({ user: userId, Role: 'member' }); const userWasMember = user.chats.some((c: any) => c.chat.equals(chatId)); if (!userWasMember) - User.findByIdAndUpdate( + await User.findByIdAndUpdate( userId, { $push: { chats: { chat: chatId } } }, { new: true } @@ -263,35 +263,20 @@ const handleDeleteGroupChannel = async ( senderId: any ) => { const { chatId } = data; - const chat = await Chat.findById(chatId); - if (!chat || chat.isDeleted) - return ack({ - success: false, - message: 'Could not delete the group', - error: 'no chat found with the provided id', - }); + const chat = await GroupChannel.findById(chatId); + const func = await check(chat, ack, senderId, { + chatType: ['group', 'channel'], + checkAdmin: true, + }); + if (!func) return func; - const chatMembers = chat.members; - const isCreator = chatMembers.some( - (member) => member.user.toString() === senderId && member.Role === 'admin' + await User.updateMany( + { _id: { $in: chat.members.map((m: any) => m.user) } }, + { $pull: { chats: { chat: chatId } } } ); - if (!isCreator) - return ack({ - success: false, - message: 'Could not delete the group', - error: 'you are not authorized to delete the group', - }); - - chatMembers.map(async (member: any) => { - await informSessions( - io, - member.user, - { chatId }, - 'DELETE_GROUP_CHANNEL_SERVER' - ); - }); + socket.to(chatId).emit('DELETE_GROUP_CHANNEL_SERVER', { chatId }); chat.members = []; chat.isDeleted = true;