Skip to content

Commit f917771

Browse files
authored
fix(chat): get messages (#116)
1 parent 6aee912 commit f917771

File tree

6 files changed

+91
-68
lines changed

6 files changed

+91
-68
lines changed

src/messages/messages.controller.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,19 @@ export class MessagesController {
101101
@Query() query: GetMessagesQueryDto,
102102
@GetUserId() user_id: string
103103
) {
104-
return this.messages_service.getMessages(user_id, chat_id, query);
104+
const result = await this.messages_service.getMessages(user_id, chat_id, query);
105+
const { next_cursor, has_more, ...response_data } = result;
106+
107+
return {
108+
data: {
109+
chat_id,
110+
...response_data,
111+
},
112+
pagination: {
113+
next_cursor,
114+
has_more,
115+
},
116+
};
105117
}
106118

107119
@ApiOperation(update_message_swagger.operation)

src/messages/messages.gateway.spec.ts

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { JwtService } from '@nestjs/jwt';
55
import { ConfigService } from '@nestjs/config';
66
import { Server, Socket } from 'socket.io';
77
import { WsJwtGuard } from 'src/auth/guards/ws-jwt.guard';
8+
import { ChatRepository } from 'src/chat/chat.repository';
89

910
interface IAuthenticatedSocket extends Socket {
1011
user?: {
@@ -17,6 +18,7 @@ describe('MessagesGateway', () => {
1718
let messages_service: jest.Mocked<MessagesService>;
1819
let jwt_service: jest.Mocked<JwtService>;
1920
let config_service: jest.Mocked<ConfigService>;
21+
let chat_repository: jest.Mocked<ChatRepository>;
2022

2123
const mock_user_id = 'user-123';
2224
const mock_chat_id = 'chat-456';
@@ -36,6 +38,12 @@ describe('MessagesGateway', () => {
3638
deleteMessage: jest.fn(),
3739
},
3840
},
41+
{
42+
provide: ChatRepository,
43+
useValue: {
44+
findOne: jest.fn(),
45+
},
46+
},
3947
{
4048
provide: JwtService,
4149
useValue: {
@@ -55,6 +63,7 @@ describe('MessagesGateway', () => {
5563
messages_service = module.get(MessagesService);
5664
jwt_service = module.get(JwtService);
5765
config_service = module.get(ConfigService);
66+
chat_repository = module.get(ChatRepository);
5867

5968
// Mock the server
6069
gateway.server = {
@@ -127,13 +136,22 @@ describe('MessagesGateway', () => {
127136

128137
describe('handleJoinChat', () => {
129138
it('should allow user to join chat room', async () => {
139+
const mock_chat = {
140+
id: mock_chat_id,
141+
user1_id: mock_user_id,
142+
user2_id: 'user-999',
143+
unread_count_user1: 5,
144+
unread_count_user2: 0,
145+
};
146+
130147
const mock_client = {
131148
id: 'socket-123',
132149
user: { user_id: mock_user_id },
133-
join: jest.fn(),
150+
join: jest.fn().mockResolvedValue(undefined),
134151
} as any;
135152

136-
messages_service.validateChatParticipation.mockResolvedValue({} as any);
153+
messages_service.validateChatParticipation.mockResolvedValue(mock_chat as any);
154+
chat_repository.update = jest.fn().mockResolvedValue(undefined);
137155

138156
const result = await gateway.handleJoinChat(mock_client, {
139157
chat_id: mock_chat_id,
@@ -143,6 +161,10 @@ describe('MessagesGateway', () => {
143161
mock_user_id,
144162
mock_chat_id
145163
);
164+
expect(chat_repository.update).toHaveBeenCalledWith(
165+
{ id: mock_chat_id },
166+
{ unread_count_user1: 0 }
167+
);
146168
expect(mock_client.join).toHaveBeenCalledWith(mock_chat_id);
147169
expect(result.event).toBe('joined_chat');
148170
expect(result.data.chat_id).toBe(mock_chat_id);
@@ -198,28 +220,35 @@ describe('MessagesGateway', () => {
198220
user: { user_id: mock_user_id },
199221
} as IAuthenticatedSocket;
200222

223+
const mock_chat = {
224+
id: mock_chat_id,
225+
user1_id: mock_user_id,
226+
user2_id: 'user-999',
227+
};
228+
201229
const mock_message = {
202230
id: mock_message_id,
203231
content: 'Test message',
204232
sender_id: mock_user_id,
205233
recipient_id: 'user-999',
206234
};
207235

236+
messages_service.validateChatParticipation.mockResolvedValue(mock_chat as any);
208237
messages_service.sendMessage.mockResolvedValue(mock_message as any);
238+
jest.spyOn(gateway as any, 'isUserInChatRoom').mockResolvedValue(true);
239+
jest.spyOn(gateway as any, 'emitToUser').mockImplementation(() => {});
209240

210241
const result = await gateway.handleSendMessage(mock_client, {
211242
chat_id: mock_chat_id,
212243
message: { content: 'Test message' } as any,
213244
});
214245

215-
expect(messages_service.sendMessage).toHaveBeenCalledWith(mock_user_id, mock_chat_id, {
216-
content: 'Test message',
217-
});
218-
expect(gateway.server.to).toHaveBeenCalledWith(mock_chat_id);
219-
expect(gateway.server.emit).toHaveBeenCalledWith('new_message', {
220-
chat_id: mock_chat_id,
221-
message: mock_message,
222-
});
246+
expect(messages_service.sendMessage).toHaveBeenCalledWith(
247+
mock_user_id,
248+
mock_chat_id,
249+
{ content: 'Test message' },
250+
true
251+
);
223252
expect(result.event).toBe('message_sent');
224253
expect(result.data).toEqual(mock_message);
225254
});
@@ -230,7 +259,7 @@ describe('MessagesGateway', () => {
230259
user: { user_id: mock_user_id },
231260
} as IAuthenticatedSocket;
232261

233-
messages_service.sendMessage.mockRejectedValue(new Error('Send failed'));
262+
messages_service.validateChatParticipation.mockRejectedValue(new Error('Send failed'));
234263

235264
const result = await gateway.handleSendMessage(mock_client, {
236265
chat_id: mock_chat_id,
@@ -242,35 +271,6 @@ describe('MessagesGateway', () => {
242271
});
243272
});
244273

245-
describe('handleGetMessages', () => {
246-
it('should retrieve messages for a chat', async () => {
247-
const mock_client = {
248-
id: 'socket-123',
249-
user: { user_id: mock_user_id },
250-
} as IAuthenticatedSocket;
251-
252-
const mock_messages = {
253-
data: [{ id: mock_message_id, content: 'Test' }],
254-
count: 1,
255-
};
256-
257-
messages_service.getMessages.mockResolvedValue(mock_messages as any);
258-
259-
const result = await gateway.handleGetMessages(mock_client, {
260-
chat_id: mock_chat_id,
261-
query: {},
262-
});
263-
264-
expect(messages_service.getMessages).toHaveBeenCalledWith(
265-
mock_user_id,
266-
mock_chat_id,
267-
{}
268-
);
269-
expect(result.event).toBe('messages_retrieved');
270-
expect(result.data).toEqual(mock_messages);
271-
});
272-
});
273-
274274
describe('handleUpdateMessage', () => {
275275
it('should update message and emit to chat room', async () => {
276276
const mock_client = {

src/messages/messages.repository.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ describe('MessageRepository', () => {
9393
content: dto.content,
9494
message_type: dto.message_type,
9595
reply_to_message_id: null,
96+
is_read: false,
9697
});
9798
expect(repository.save).toHaveBeenCalled();
9899
expect(chat_repository.update).toHaveBeenCalledWith(
@@ -116,7 +117,8 @@ describe('MessageRepository', () => {
116117
chat_id: mock_chat_id,
117118
content: dto.content,
118119
message_type: dto.message_type,
119-
reply_to_message_id: 'original-message-id',
120+
reply_to_message_id: dto.reply_to_message_id || null,
121+
is_read: false,
120122
});
121123
});
122124

src/messages/messages.service.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ describe('MessagesService', () => {
180180
expect(message_repository.createMessage).toHaveBeenCalledWith(
181181
mock_user_id,
182182
mock_chat_id,
183-
send_dto
183+
send_dto,
184+
false
184185
);
185186
expect(chat_repository.increment).toHaveBeenCalledWith(
186187
{ id: mock_chat_id },

src/messages/messages.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export class MessagesService {
3030
) {
3131
const chat = await this.chat_repository.findOne({
3232
where: { id: chat_id },
33+
relations: ['user1', 'user2'],
3334
});
3435

3536
if (!chat) throw new NotFoundException(ERROR_MESSAGES.CHAT_NOT_FOUND);

src/messages/messages.swagger.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,32 +94,39 @@ Get a paginated list of messages from a specific chat, ordered by creation time.
9494
schema: {
9595
example: {
9696
data: {
97-
sender: {
98-
id: 'user_456def-789abc-012ghi',
99-
username: 'mariooo',
100-
name: 'Mario Raafat',
101-
avatar_url: 'https://wqjblkqbw.jpg',
102-
},
103-
messages: [
104-
{
105-
id: 'msg_789def-012abc-345ghi',
106-
content: 'take a kiss my friend 😘',
107-
message_type: 'text',
108-
reply_to: null,
109-
is_read: false,
110-
created_at: '2025-10-16T10:45:00.000Z',
111-
updated_at: '2025-10-16T10:45:00.000Z',
112-
},
113-
{
114-
id: 'msg_456abc-789def-012ghi',
115-
content: 'el back team is top el top',
116-
message_type: 'reply',
117-
reply_to: 'msg_789def-012abc-345ghi',
118-
is_read: true,
119-
created_at: '2025-10-16T10:46:00.000Z',
120-
updated_at: '2025-10-16T10:46:00.000Z',
97+
data: {
98+
chat_id: 'chat_123abc-def456-789ghi',
99+
sender: {
100+
id: 'user_456def-789abc-012ghi',
101+
username: 'mariooo',
102+
name: 'Mario Raafat',
103+
avatar_url: 'https://wqjblkqbw.jpg',
121104
},
122-
],
105+
messages: [
106+
{
107+
id: 'msg_789def-012abc-345ghi',
108+
content: 'take a kiss my friend 😘',
109+
message_type: 'text',
110+
reply_to: null,
111+
is_read: false,
112+
created_at: '2025-10-16T10:45:00.000Z',
113+
updated_at: '2025-10-16T10:45:00.000Z',
114+
},
115+
{
116+
id: 'msg_456abc-789def-012ghi',
117+
content: 'el back team is top el top',
118+
message_type: 'reply',
119+
reply_to: 'msg_789def-012abc-345ghi',
120+
is_read: true,
121+
created_at: '2025-10-16T10:46:00.000Z',
122+
updated_at: '2025-10-16T10:46:00.000Z',
123+
},
124+
],
125+
},
126+
pagination: {
127+
has_more: true,
128+
next_cursor: 'msg_456abc-789def-012ghi',
129+
},
123130
},
124131
count: 2,
125132
message: SUCCESS_MESSAGES.MESSAGES_RETRIEVED,

0 commit comments

Comments
 (0)