Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions docs/api/chat.swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions docs/api/sockets.swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/chatController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
14 changes: 9 additions & 5 deletions src/services/chatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}))
);

Expand Down
52 changes: 28 additions & 24 deletions src/services/googleAIService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,37 @@ const hf = new HfInference(process.env.HF_API_KEY);
const modelName = 'unitary/toxic-bert';

async function detectInappropriateContent(text: string): Promise<boolean> {
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;
export default detectInappropriateContent;
27 changes: 14 additions & 13 deletions src/sockets/MessagingServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,30 @@ 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({
success: false,
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;
};
Expand Down
37 changes: 11 additions & 26 deletions src/sockets/chats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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;
Expand Down