Skip to content

Commit be030d0

Browse files
authored
feat(be): power deletion (#219)
* feat: question power delete * feat: reply power delete
1 parent 04a2b18 commit be030d0

File tree

6 files changed

+34
-17
lines changed

6 files changed

+34
-17
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- DropForeignKey
2+
ALTER TABLE "Reply" DROP CONSTRAINT "Reply_question_id_fkey";
3+
4+
-- AddForeignKey
5+
ALTER TABLE "Reply" ADD CONSTRAINT "Reply_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "Question"("question_id") ON DELETE CASCADE ON UPDATE CASCADE;

apps/server/prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ model Reply {
8181
deleted Boolean @default(false)
8282
8383
session Session @relation("SessionReplies", fields: [sessionId], references: [sessionId])
84-
question Question @relation("QuestionReplies", fields: [questionId], references: [questionId])
84+
question Question @relation("QuestionReplies", fields: [questionId], references: [questionId], onDelete: Cascade)
8585
createUserTokenEntity UserSessionToken @relation("TokenReplies", fields: [createUserToken], references: [token])
8686
replyLikes ReplyLike[] @relation("ReplyLikes")
8787
}

apps/server/src/questions/questions.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ export class QuestionsController {
9292

9393
@Delete(':questionId')
9494
@DeleteQuestionSwagger()
95-
@UseGuards(SessionTokenValidationGuard, QuestionExistenceGuard, QuestionOwnershipGuard)
95+
@UseGuards(SessionTokenValidationGuard, QuestionExistenceGuard)
9696
async deleteQuestion(@Param('questionId', ParseIntPipe) questionId: number, @Query() data: BaseDto, @Req() req: any) {
97-
await this.questionsService.deleteQuestion(questionId, req.question);
9897
const { sessionId, token } = data;
98+
await this.questionsService.deleteQuestion(questionId, req.question, data);
9999
const resultForOther = { questionId };
100100
this.socketGateway.broadcastQuestionDelete(sessionId, token, resultForOther);
101101
return {};

apps/server/src/questions/questions.service.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { CreateQuestionDto } from './dto/create-question.dto';
55
import { GetQuestionDto } from './dto/get-question.dto';
66
import { QuestionsRepository } from './questions.repository';
77

8+
import { BaseDto } from '@common/base.dto';
89
import {
910
UpdateQuestionBodyDto,
1011
UpdateQuestionClosedDto,
@@ -127,13 +128,20 @@ export class QuestionsService {
127128
return await this.questionRepository.updateBody(questionId, body);
128129
}
129130

130-
async deleteQuestion(questionId: number, question: Question) {
131-
const isReplied = await this.repliesRepository.findReplyByQuestionId(questionId);
132-
if (isReplied) {
133-
throw new ForbiddenException('답변이 달린 질문은 삭제할 수 없습니다.');
134-
}
135-
if (question.closed) {
136-
throw new ForbiddenException('이미 완료된 답변은 삭제할 수 없습니다.');
131+
async deleteQuestion(questionId: number, question: Question, { token }: BaseDto) {
132+
const { isHost } = await this.sessionAuthRepository.findByToken(token);
133+
134+
if (!isHost) {
135+
if (question.createUserToken !== token) {
136+
throw new ForbiddenException('권한이 없습니다.');
137+
}
138+
const isReplied = await this.repliesRepository.findReplyByQuestionId(questionId);
139+
if (isReplied) {
140+
throw new ForbiddenException('답변이 달린 질문은 삭제할 수 없습니다.');
141+
}
142+
if (question.closed) {
143+
throw new ForbiddenException('이미 완료된 답변은 삭제할 수 없습니다.');
144+
}
137145
}
138146
return await this.questionRepository.deleteQuestion(questionId);
139147
}

apps/server/src/replies/replies.controller.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Patch,
88
Post,
99
Query,
10+
Req,
1011
UseGuards,
1112
UseInterceptors,
1213
} from '@nestjs/common';
@@ -68,10 +69,10 @@ export class RepliesController {
6869

6970
@Delete(':replyId')
7071
@DeleteReplySwagger()
71-
@UseGuards(SessionTokenValidationGuard, ReplyExistenceGuard, ReplyOwnershipGuard)
72-
async delete(@Param('replyId', ParseIntPipe) replyId: number, @Query() data: BaseDto) {
73-
const { questionId } = await this.repliesService.deleteReply(replyId);
72+
@UseGuards(SessionTokenValidationGuard, ReplyExistenceGuard)
73+
async delete(@Param('replyId', ParseIntPipe) replyId: number, @Query() data: BaseDto, @Req() request: Request) {
7474
const { sessionId, token } = data;
75+
const { questionId } = await this.repliesService.deleteReply(replyId, token, request['reply']);
7576
const resultForOther = { replyId, questionId };
7677
this.socketGateway.broadcastReplyDelete(sessionId, token, resultForOther);
7778
return {};

apps/server/src/replies/replies.service.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { create } from 'node:domain';
2-
3-
import { Injectable } from '@nestjs/common';
1+
import { ForbiddenException, Injectable } from '@nestjs/common';
2+
import { Reply } from '@prisma/client';
43

54
import { CreateReplyDto } from './dto/create-reply.dto';
65
import { UpdateReplyBodyDto } from './dto/update-reply.dto';
@@ -39,7 +38,11 @@ export class RepliesService {
3938
return await this.repliesRepository.updateBody(replyId, body);
4039
}
4140

42-
async deleteReply(replyId: number) {
41+
async deleteReply(replyId: number, token: string, reply: Reply) {
42+
const { isHost } = await this.sessionAuthRepository.findByToken(token);
43+
44+
if (!isHost && reply.createUserToken !== token) throw new ForbiddenException('권한이 없습니다.');
45+
4346
return await this.repliesRepository.deleteReply(replyId);
4447
}
4548

0 commit comments

Comments
 (0)