Skip to content

Commit

Permalink
Merge pull request #180 from 00sOrg/Feat/179
Browse files Browse the repository at this point in the history
✨ [Feat] Implement delete comment api
  • Loading branch information
gitwub5 authored Oct 3, 2024
2 parents 49d3c7d + 461e87d commit 333a90a
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 10 deletions.
12 changes: 12 additions & 0 deletions src/common/api/status/error.status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,16 @@ export class ErrorStatus implements BaseCode {
400,
'이미지 삭제에 실패했습니다.',
);

static readonly COMMENT_NOT_FOUND = new ErrorStatus(
false,
400,
'해당 댓글이 존재하지 않습니다.',
);

static readonly COMMENT_NOT_MATCH = new ErrorStatus(
false,
400,
'댓글 작성자가 아닙니다.',
);
}
4 changes: 4 additions & 0 deletions src/modules/events/entities/event.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export class Event extends DefaultEntity {
this.commentsCount++;
}

subCommentCount(): void {
this.commentsCount = this.commentsCount > 0 ? this.commentsCount - 1 : 0;
}

addLikeCount() {
this.likesCount++;
}
Expand Down
15 changes: 15 additions & 0 deletions src/modules/events/events.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,21 @@ export class EventsController {
return await this.eventsService.getEvents(member);
}

@Delete('/comment/:commentId')
@ApiOperation({ summary: '댓글 삭제' })
@ApiSuccessResponse()
@ApiFailureResponse(
ErrorStatus.MEMBER_NOT_FOUND,
ErrorStatus.COMMENT_NOT_FOUND,
ErrorStatus.COMMENT_NOT_MATCH,
ErrorStatus.EVENT_NOT_FOUND,
ErrorStatus.INTERNAL_SERVER_ERROR,
)
async deleteComment(@Param('commentId') commentId: string, @Request() req) {
const member = req.user;
await this.commentService.deleteComment(Number(commentId), member);
}

@Delete(':id(\\d+)')
@ApiOperation({ summary: '이벤트 삭제' })
@ApiSuccessResponse()
Expand Down
13 changes: 13 additions & 0 deletions src/modules/events/repository/comment.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,17 @@ export class CommentRepository {
async create(comment: Comment): Promise<Comment> {
return this.commentRepository.save(comment);
}

async findOne(commentId: number): Promise<Comment | null> {
return this.commentRepository
.createQueryBuilder('comment')
.where('comment.id=:commentId', { commentId })
.leftJoinAndSelect('comment.member', 'member')
.leftJoinAndSelect('comment.event', 'event')
.getOne();
}

async delete(commentId: number): Promise<void> {
await this.commentRepository.delete(commentId);
}
}
19 changes: 17 additions & 2 deletions src/modules/events/services/comment.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Injectable } from '@nestjs/common';
import { MembersRepository } from 'src/modules/members/repository/members.repository';
import { CommentRepository } from '../repository/comment.repository';
import { ExceptionHandler } from 'src/common/filters/exception/exception.handler';
import { ErrorStatus } from 'src/common/api/status/error.status';
Expand All @@ -10,7 +9,6 @@ import { Member } from '../../members/entities';
@Injectable()
export class CommentService {
constructor(
private readonly membersRepository: MembersRepository,
private readonly eventsRepository: EventsRepository,
private readonly commentRepository: CommentRepository,
) {}
Expand All @@ -28,4 +26,21 @@ export class CommentService {
await this.eventsRepository.update(event);
await this.commentRepository.create(comment);
}

async deleteComment(commentId: number, member: Member): Promise<void> {
const comment = await this.commentRepository.findOne(commentId);
if (!comment) {
throw new ExceptionHandler(ErrorStatus.COMMENT_NOT_FOUND);
}
if (comment.member.id !== member.id) {
throw new ExceptionHandler(ErrorStatus.COMMENT_NOT_MATCH);
}
const event = await this.eventsRepository.findOne(comment.event.id);
if (!event) {
throw new ExceptionHandler(ErrorStatus.EVENT_NOT_FOUND);
}
event.subCommentCount();
await this.eventsRepository.update(event);
await this.commentRepository.delete(commentId);
}
}
64 changes: 56 additions & 8 deletions test/unit/comment.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,18 @@ import { Member } from 'src/modules/members/entities';
import { MembersRepository } from 'src/modules/members/repository/members.repository';
import { MemberBuilder } from '../../src/modules/members/entities/builder/member.builder';
import { EventBuilder } from '../../src/modules/events/entities/builder/event.builder';
import { Comment } from '../../src/modules/events/entities';
import { CommentBuilder } from '../../src/modules/events/entities/builder/comment.builder';

describe('CommentService', () => {
let commentService: CommentService;
let memberRepository: Partial<jest.Mocked<MembersRepository>>;
let eventsRepository: Partial<jest.Mocked<EventsRepository>>;
let commentRepository: Partial<jest.Mocked<CommentRepository>>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CommentService,
{
provide: MembersRepository,
useValue: {
findById: jest.fn(),
},
},
{
provide: EventsRepository,
useValue: {
Expand All @@ -38,13 +33,14 @@ describe('CommentService', () => {
provide: CommentRepository,
useValue: {
create: jest.fn(),
findOne: jest.fn(),
delete: jest.fn(),
},
},
],
}).compile();

commentService = module.get<CommentService>(CommentService);
memberRepository = module.get(MembersRepository);
eventsRepository = module.get(EventsRepository);
commentRepository = module.get(CommentRepository);
});
Expand Down Expand Up @@ -81,4 +77,56 @@ describe('CommentService', () => {
).rejects.toThrow(new ExceptionHandler(ErrorStatus.EVENT_NOT_FOUND));
});
});

describe('deleteComment', () => {
let comment: Comment;
let member: Member;

beforeEach(async () => {
member = new MemberBuilder().id(1).build();
const event = new EventBuilder().id(1).commentsCount(1).build();
comment = new CommentBuilder().id(1).member(member).event(event).build();
});

it('should delete a comment successfully', async () => {
jest.spyOn(commentRepository, 'findOne').mockResolvedValue(comment);
jest.spyOn(eventsRepository, 'findOne').mockResolvedValue(comment.event);
jest.spyOn(eventsRepository, 'update').mockResolvedValue(undefined);
jest.spyOn(commentRepository, 'delete').mockResolvedValue(undefined);

await commentService.deleteComment(1, member);

expect(commentRepository.findOne).toHaveBeenCalledWith(1);
expect(eventsRepository.findOne).toHaveBeenCalledWith(1);
expect(eventsRepository.update).toHaveBeenCalledTimes(1);
expect(commentRepository.delete).toHaveBeenCalledWith(1);
expect(comment.event.commentsCount).toBe(0);
});

it('should throw COMMENT_NOT_FOUND if comment does not exist', async () => {
jest.spyOn(commentRepository, 'findOne').mockResolvedValue(null);

await expect(commentService.deleteComment(1, member)).rejects.toThrow(
new ExceptionHandler(ErrorStatus.COMMENT_NOT_FOUND),
);
});

it('should throw COMMENT_NOT_MATCH if comment does not match', async () => {
const anotherMember = new MemberBuilder().id(2).build();
jest.spyOn(commentRepository, 'findOne').mockResolvedValue(comment);

await expect(
commentService.deleteComment(1, anotherMember),
).rejects.toThrow(new ExceptionHandler(ErrorStatus.COMMENT_NOT_MATCH));
});

it('should throw EVENT_NOT_FOUND if event does not exist', async () => {
jest.spyOn(commentRepository, 'findOne').mockResolvedValue(comment);
jest.spyOn(eventsRepository, 'findOne').mockResolvedValue(null);

await expect(commentService.deleteComment(1, member)).rejects.toThrow(
new ExceptionHandler(ErrorStatus.EVENT_NOT_FOUND),
);
});
});
});

0 comments on commit 333a90a

Please sign in to comment.