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
173 changes: 172 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"sharp": "^0.34.2",
"socket.io": "^4.8.3",
"winston": "^3.17.0",
"zod": "^3.24.3"
},
Expand Down
82 changes: 68 additions & 14 deletions src/api/v1/chats/chats.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as Storage from '@/lib/storage';
import * as Service from './chats.service';
import * as Middlewares from '@/middlewares';
import { Request, Response, Router } from 'express';
import logger from '@/lib/logger';

export const chatsRouter = Router();

Expand All @@ -28,32 +29,53 @@ chatsRouter.get('/', Middlewares.authValidator, async (req, res) => {
const userId = Utils.getCurrentUserIdFromReq(req)!;
const filters = Utils.getBasePaginationFiltersFromReqQuery(req);
const chats = await Service.getUserChats(userId, filters);
res.json(chats);
res.json(chats).on('finish', () => {
const rooms = Service.getOtherChatsMemberIds(userId, chats);
Utils.emitToRoomsIfAny({ rooms, event: 'chats:received', volatile: true });
});
});

chatsRouter.get('/members/:profileId', Middlewares.authValidator, async (req, res) => {
const userId = Utils.getCurrentUserIdFromReq(req)!;
const chats = await Service.getUserChatsByMember(userId, req.params.profileId);
res.json(chats);
res.json(chats).on('finish', () => {
const rooms = Service.getOtherChatsMemberIds(userId, chats);
Utils.emitToRoomsIfAny({ rooms, event: 'chats:received', volatile: true });
});
});

chatsRouter.get('/:id', Middlewares.authValidator, async (req, res) => {
const chatId = req.params.id;
const userId = Utils.getCurrentUserIdFromReq(req)!;
const chat = await Service.getUserChatById(userId, req.params.id);
res.json(chat);
const chat = await Service.getUserChatById(userId, chatId);
res.json(chat).on('finish', () => {
Service.getOtherChatMemberIds(userId, chatId)
.then((rooms) => Utils.emitToRoomsIfAny({ rooms, event: 'chats:received', volatile: true }))
.catch((error: unknown) => logger.error('Failed to broadcast "chats:received"', error));
});
});

chatsRouter.get('/:id/messages', Middlewares.authValidator, async (req, res) => {
const chatId = req.params.id;
const userId = Utils.getCurrentUserIdFromReq(req)!;
const filters = Utils.getBasePaginationFiltersFromReqQuery(req);
const messages = await Service.getUserChatMessages(userId, req.params.id, filters);
res.json(messages);
const messages = await Service.getUserChatMessages(userId, chatId, filters);
res.json(messages).on('finish', () => {
Service.getOtherChatMemberIds(userId, chatId)
.then((rooms) => Utils.emitToRoomsIfAny({ rooms, event: 'chats:received', volatile: true }))
.catch((error: unknown) => logger.error('Failed to broadcast "chats:received"', error));
});
});

chatsRouter.get('/:id/messages/:msgId', Middlewares.authValidator, async (req, res) => {
const chatId = req.params.id;
const userId = Utils.getCurrentUserIdFromReq(req)!;
const msg = await Service.getUserChatMessageById(userId, req.params.id, req.params.msgId);
res.json(msg);
const msg = await Service.getUserChatMessageById(userId, chatId, req.params.msgId);
res.json(msg).on('finish', () => {
Service.getOtherChatMemberIds(userId, chatId)
.then((rooms) => Utils.emitToRoomsIfAny({ rooms, event: 'chats:received', volatile: true }))
.catch((error: unknown) => logger.error('Failed to broadcast "chats:received"', error));
});
});

chatsRouter.post(
Expand All @@ -67,33 +89,65 @@ chatsRouter.post(
);
const preparedImageData = await prepareImageData(req, chatData.message.imagedata, user);
const createdChat = await Service.createChat(user, chatData, ...preparedImageData);
res.status(201).json(createdChat);
res
.status(201)
.json(createdChat)
.on('finish', () => {
Service.getOtherChatMemberIds(user.id, createdChat.id)
.then((rooms) =>
Utils.emitToRoomsIfAny({ rooms, event: 'chats:updated', volatile: true }),
)
.catch((error: unknown) => logger.error('Failed to broadcast "chats:updated"', error));
});
},
);

chatsRouter.patch('/:id/seen', Middlewares.authValidator, async (req, res) => {
const chatId = req.params.id;
const userId = Utils.getCurrentUserIdFromReq(req)!;
res.json(await Service.updateProfileChatLastSeenDate(userId, req.params.id));
res.json(await Service.updateProfileChatLastSeenDate(userId, chatId)).on('finish', () => {
Service.getOtherChatMemberIds(userId, chatId)
.then((rooms) => Utils.emitToRoomsIfAny({ rooms, event: 'chats:updated', volatile: true }))
.catch((error: unknown) => logger.error('Failed to broadcast "chats:updated"', error));
});
});

chatsRouter.post(
'/:id/messages',
Middlewares.authValidator,
Middlewares.createFileProcessor('image'),
async (req: Request, res: Response) => {
const chatId = req.params.id;
const user = Utils.getCurrentUserFromReq(req)!;
const { imagedata, ...msgData } = (
req.file ? Schema.optionalMessageSchema : Schema.messageSchema
).parse(req.body);
const preparedImageData = await prepareImageData(req, imagedata, user);
const msgArgs = [user, req.params.id, msgData, ...preparedImageData] as const;
const msgArgs = [user, chatId, msgData, ...preparedImageData] as const;
const createdMessage = await Service.createUserChatMessage(...msgArgs);
res.status(201).json(createdMessage);
res
.status(201)
.json(createdMessage)
.on('finish', () => {
Service.getOtherChatMemberIds(user.id, chatId)
.then((rooms) =>
Utils.emitToRoomsIfAny({ rooms, event: 'chats:updated', volatile: true }),
)
.catch((error: unknown) => logger.error('Failed to broadcast "chats:updated"', error));
});
},
);

chatsRouter.delete('/:id', Middlewares.authValidator, async (req, res) => {
const chatId = req.params.id;
const userId = Utils.getCurrentUserIdFromReq(req)!;
await Service.deleteChat(userId, req.params.id);
res.status(204).send();
await Service.deleteChat(userId, chatId);
res
.status(204)
.send()
.on('finish', () => {
Service.getOtherChatMemberIds(userId, chatId)
.then((rooms) => Utils.emitToRoomsIfAny({ rooms, event: 'chats:updated', volatile: true }))
.catch((error: unknown) => logger.error('Failed to broadcast "chats:updated"', error));
});
});
Loading