feat: add read receipt handling based on user preferences
- Integrated `UsersService` into `MessagesService` for retrieving user preferences. - Updated `markAsRead` functionality to respect `showReadReceipts` preference. - Enhanced real-time read receipt notifications via `EventsGateway`. - Added `markAsRead` method to the frontend message service.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { ForbiddenException } from "@nestjs/common";
|
import { ForbiddenException } from "@nestjs/common";
|
||||||
import { Test, TestingModule } from "@nestjs/testing";
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
import { EventsGateway } from "../realtime/events.gateway";
|
import { EventsGateway } from "../realtime/events.gateway";
|
||||||
|
import { UsersService } from "../users/users.service";
|
||||||
import { MessagesService } from "./messages.service";
|
import { MessagesService } from "./messages.service";
|
||||||
import { MessagesRepository } from "./repositories/messages.repository";
|
import { MessagesRepository } from "./repositories/messages.repository";
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ describe("MessagesService", () => {
|
|||||||
createMessage: jest.fn(),
|
createMessage: jest.fn(),
|
||||||
findAllConversations: jest.fn(),
|
findAllConversations: jest.fn(),
|
||||||
isParticipant: jest.fn(),
|
isParticipant: jest.fn(),
|
||||||
|
getParticipants: jest.fn(),
|
||||||
findMessagesByConversationId: jest.fn(),
|
findMessagesByConversationId: jest.fn(),
|
||||||
markAsRead: jest.fn(),
|
markAsRead: jest.fn(),
|
||||||
countUnreadMessages: jest.fn(),
|
countUnreadMessages: jest.fn(),
|
||||||
@@ -25,12 +27,17 @@ describe("MessagesService", () => {
|
|||||||
sendToUser: jest.fn(),
|
sendToUser: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockUsersService = {
|
||||||
|
findOne: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
MessagesService,
|
MessagesService,
|
||||||
{ provide: MessagesRepository, useValue: mockMessagesRepository },
|
{ provide: MessagesRepository, useValue: mockMessagesRepository },
|
||||||
{ provide: EventsGateway, useValue: mockEventsGateway },
|
{ provide: EventsGateway, useValue: mockEventsGateway },
|
||||||
|
{ provide: UsersService, useValue: mockUsersService },
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ForbiddenException, Injectable } from "@nestjs/common";
|
import { ForbiddenException, Injectable } from "@nestjs/common";
|
||||||
import { EventsGateway } from "../realtime/events.gateway";
|
import { EventsGateway } from "../realtime/events.gateway";
|
||||||
|
import { UsersService } from "../users/users.service";
|
||||||
import type { CreateMessageDto } from "./dto/create-message.dto";
|
import type { CreateMessageDto } from "./dto/create-message.dto";
|
||||||
import { MessagesRepository } from "./repositories/messages.repository";
|
import { MessagesRepository } from "./repositories/messages.repository";
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ export class MessagesService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly messagesRepository: MessagesRepository,
|
private readonly messagesRepository: MessagesRepository,
|
||||||
private readonly eventsGateway: EventsGateway,
|
private readonly eventsGateway: EventsGateway,
|
||||||
|
private readonly usersService: UsersService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async sendMessage(senderId: string, dto: CreateMessageDto) {
|
async sendMessage(senderId: string, dto: CreateMessageDto) {
|
||||||
@@ -62,9 +64,25 @@ export class MessagesService {
|
|||||||
throw new ForbiddenException("You are not part of this conversation");
|
throw new ForbiddenException("You are not part of this conversation");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marquer comme lus
|
// Récupérer les préférences de l'utilisateur actuel
|
||||||
|
const user = await this.usersService.findOne(userId);
|
||||||
|
|
||||||
|
// Marquer comme lus seulement si l'utilisateur l'autorise
|
||||||
|
if (user?.showReadReceipts) {
|
||||||
await this.messagesRepository.markAsRead(conversationId, userId);
|
await this.messagesRepository.markAsRead(conversationId, userId);
|
||||||
|
|
||||||
|
// Notifier l'expéditeur que les messages ont été lus
|
||||||
|
const participants =
|
||||||
|
await this.messagesRepository.getParticipants(conversationId);
|
||||||
|
const otherParticipant = participants.find((p) => p.userId !== userId);
|
||||||
|
if (otherParticipant) {
|
||||||
|
this.eventsGateway.sendToUser(otherParticipant.userId, "messages_read", {
|
||||||
|
conversationId,
|
||||||
|
readerId: userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.messagesRepository.findMessagesByConversationId(conversationId);
|
return this.messagesRepository.findMessagesByConversationId(conversationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +94,26 @@ export class MessagesService {
|
|||||||
if (!isParticipant) {
|
if (!isParticipant) {
|
||||||
throw new ForbiddenException("You are not part of this conversation");
|
throw new ForbiddenException("You are not part of this conversation");
|
||||||
}
|
}
|
||||||
return this.messagesRepository.markAsRead(conversationId, userId);
|
|
||||||
|
const user = await this.usersService.findOne(userId);
|
||||||
|
if (!user?.showReadReceipts) return;
|
||||||
|
|
||||||
|
const result = await this.messagesRepository.markAsRead(
|
||||||
|
conversationId,
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notifier l'autre participant
|
||||||
|
const participants =
|
||||||
|
await this.messagesRepository.getParticipants(conversationId);
|
||||||
|
const otherParticipant = participants.find((p) => p.userId !== userId);
|
||||||
|
if (otherParticipant) {
|
||||||
|
this.eventsGateway.sendToUser(otherParticipant.userId, "messages_read", {
|
||||||
|
conversationId,
|
||||||
|
readerId: userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,4 +55,8 @@ export const MessageService = {
|
|||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async markAsRead(conversationId: string): Promise<void> {
|
||||||
|
await api.patch(`/messages/conversations/${conversationId}/read`);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user