feat: add WebSocket notifications for new comments
- Introduced enriched comment retrieval with user information and like statistics. - Implemented WebSocket notifications to notify users of new comments on content. - Updated dependency injection to include `EventsGateway` and `RealtimeModule`.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { AuthModule } from "../auth/auth.module";
|
import { AuthModule } from "../auth/auth.module";
|
||||||
|
import { RealtimeModule } from "../realtime/realtime.module";
|
||||||
import { S3Module } from "../s3/s3.module";
|
import { S3Module } from "../s3/s3.module";
|
||||||
import { CommentsController } from "./comments.controller";
|
import { CommentsController } from "./comments.controller";
|
||||||
import { CommentsService } from "./comments.service";
|
import { CommentsService } from "./comments.service";
|
||||||
@@ -7,7 +8,7 @@ import { CommentLikesRepository } from "./repositories/comment-likes.repository"
|
|||||||
import { CommentsRepository } from "./repositories/comments.repository";
|
import { CommentsRepository } from "./repositories/comments.repository";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [AuthModule, S3Module],
|
imports: [AuthModule, S3Module, RealtimeModule],
|
||||||
controllers: [CommentsController],
|
controllers: [CommentsController],
|
||||||
providers: [CommentsService, CommentsRepository, CommentLikesRepository],
|
providers: [CommentsService, CommentsRepository, CommentLikesRepository],
|
||||||
exports: [CommentsService],
|
exports: [CommentsService],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
|
import { EventsGateway } from "../realtime/events.gateway";
|
||||||
import { S3Service } from "../s3/s3.service";
|
import { S3Service } from "../s3/s3.service";
|
||||||
import type { CreateCommentDto } from "./dto/create-comment.dto";
|
import type { CreateCommentDto } from "./dto/create-comment.dto";
|
||||||
import { CommentLikesRepository } from "./repositories/comment-likes.repository";
|
import { CommentLikesRepository } from "./repositories/comment-likes.repository";
|
||||||
@@ -14,6 +15,7 @@ export class CommentsService {
|
|||||||
private readonly commentsRepository: CommentsRepository,
|
private readonly commentsRepository: CommentsRepository,
|
||||||
private readonly commentLikesRepository: CommentLikesRepository,
|
private readonly commentLikesRepository: CommentLikesRepository,
|
||||||
private readonly s3Service: S3Service,
|
private readonly s3Service: S3Service,
|
||||||
|
private readonly eventsGateway: EventsGateway,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(userId: string, contentId: string, dto: CreateCommentDto) {
|
async create(userId: string, contentId: string, dto: CreateCommentDto) {
|
||||||
@@ -24,11 +26,36 @@ export class CommentsService {
|
|||||||
parentId: dto.parentId,
|
parentId: dto.parentId,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enrichir le commentaire créé (pour le retour API)
|
// Récupérer le commentaire avec les infos utilisateur pour le WebSocket
|
||||||
|
const enrichedComment = await this.findOneEnriched(comment.id, userId);
|
||||||
|
|
||||||
|
// Notifier les autres utilisateurs sur ce contenu
|
||||||
|
this.eventsGateway.sendToContent(contentId, "new_comment", enrichedComment);
|
||||||
|
|
||||||
|
return enrichedComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOneEnriched(commentId: string, currentUserId?: string) {
|
||||||
|
const comment = await this.commentsRepository.findOneEnriched(commentId);
|
||||||
|
if (!comment) return null;
|
||||||
|
|
||||||
|
const [likesCount, isLiked] = await Promise.all([
|
||||||
|
this.commentLikesRepository.countByCommentId(comment.id),
|
||||||
|
currentUserId
|
||||||
|
? this.commentLikesRepository.isLikedByUser(comment.id, currentUserId)
|
||||||
|
: Promise.resolve(false),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...comment,
|
...comment,
|
||||||
likesCount: 0,
|
likesCount,
|
||||||
isLiked: false,
|
isLiked,
|
||||||
|
user: {
|
||||||
|
...comment.user,
|
||||||
|
avatarUrl: comment.user.avatarUrl
|
||||||
|
? this.s3Service.getPublicUrl(comment.user.avatarUrl)
|
||||||
|
: null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,27 @@ export class CommentsRepository {
|
|||||||
return results[0];
|
return results[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findOneEnriched(id: string) {
|
||||||
|
const results = await this.databaseService.db
|
||||||
|
.select({
|
||||||
|
id: comments.id,
|
||||||
|
text: comments.text,
|
||||||
|
parentId: comments.parentId,
|
||||||
|
createdAt: comments.createdAt,
|
||||||
|
updatedAt: comments.updatedAt,
|
||||||
|
user: {
|
||||||
|
uuid: users.uuid,
|
||||||
|
username: users.username,
|
||||||
|
displayName: users.displayName,
|
||||||
|
avatarUrl: users.avatarUrl,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.from(comments)
|
||||||
|
.innerJoin(users, eq(comments.userId, users.uuid))
|
||||||
|
.where(and(eq(comments.id, id), isNull(comments.deletedAt)));
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
|
||||||
async delete(id: string) {
|
async delete(id: string) {
|
||||||
await this.databaseService.db
|
await this.databaseService.db
|
||||||
.update(comments)
|
.update(comments)
|
||||||
|
|||||||
Reference in New Issue
Block a user