diff --git a/http/question/QuestionControllerHttpRequest.http b/http/question/QuestionControllerHttpRequest.http new file mode 100644 index 0000000..1002ede --- /dev/null +++ b/http/question/QuestionControllerHttpRequest.http @@ -0,0 +1,33 @@ +### 4.1 질문 리스트 조회하기 +//@no-log +GET {{host_url}}/v1/questions?id=1&week=1 +Authorization: Bearer {{access_token}} + +### 4.2 답변 리스트 조회하기 +//@no-log +GET {{host_url}}/v1/questions/3/replies +Authorization: Bearer {{access_token}} + + +### 4.3 질문 등록하기 +//@no-log +POST {{host_url}}/v1/questions +Authorization: Bearer {{access_token}} +Content-Type: application/json + +{ + "lecture_id": 1, + "week": 1, + "title": "질문 제목", + "content": "질문 내용" +} + +### 4.4 답변 등록하기 +//@no-log +POST {{host_url}}/v1/questions/3/replies +Authorization: Bearer {{access_token}} +Content-Type: application/json + +{ + "content": "답변 내용" +} \ No newline at end of file diff --git a/src/main/java/org/dongguk/onroad/core/utility/DateTimeUtil.java b/src/main/java/org/dongguk/onroad/core/utility/DateTimeUtil.java index 6d1ca4a..a229718 100644 --- a/src/main/java/org/dongguk/onroad/core/utility/DateTimeUtil.java +++ b/src/main/java/org/dongguk/onroad/core/utility/DateTimeUtil.java @@ -10,7 +10,7 @@ */ public class DateTimeUtil { - public static final DateTimeFormatter ISODateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static final DateTimeFormatter ISODateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"); public static final DateTimeFormatter ISODateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final DateTimeFormatter ISOTimeFormatter = DateTimeFormatter.ofPattern("HH:mm"); /** diff --git a/src/main/java/org/dongguk/onroad/question/application/controller/.keep b/src/main/java/org/dongguk/onroad/question/application/controller/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/dongguk/onroad/question/application/controller/command/QuestionCommandV1Controller.java b/src/main/java/org/dongguk/onroad/question/application/controller/command/QuestionCommandV1Controller.java new file mode 100644 index 0000000..6011e10 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/controller/command/QuestionCommandV1Controller.java @@ -0,0 +1,42 @@ +package org.dongguk.onroad.question.application.controller.command; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.annotation.security.UserID; +import org.dongguk.onroad.core.dto.ResponseDto; +import org.dongguk.onroad.question.application.dto.request.CreateQuestionRequestDto; +import org.dongguk.onroad.question.application.dto.request.CreateReplyRequestDto; +import org.dongguk.onroad.question.application.usecase.CreateQuestionUseCase; +import org.dongguk.onroad.question.application.usecase.CreateReplyUseCase; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +public class QuestionCommandV1Controller { + private final CreateQuestionUseCase createQuestionUseCase; + private final CreateReplyUseCase createReplyUseCase; + + @PostMapping("/v1/questions") + public ResponseDto createQuestion( + @UserID UUID userId, + @RequestBody @Valid CreateQuestionRequestDto requestDto + ) { + createQuestionUseCase.execute(userId, requestDto); + return ResponseDto.created(null); + } + + @PostMapping("/v1/questions/{id}/replies") + public ResponseDto createReply( + @UserID UUID userId, + @PathVariable Long id, + @RequestBody @Valid CreateReplyRequestDto requestDto + ) { + createReplyUseCase.execute(userId, id, requestDto); + return ResponseDto.created(null); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/controller/query/QuestionQueryV1Controller.java b/src/main/java/org/dongguk/onroad/question/application/controller/query/QuestionQueryV1Controller.java new file mode 100644 index 0000000..4cce322 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/controller/query/QuestionQueryV1Controller.java @@ -0,0 +1,40 @@ +package org.dongguk.onroad.question.application.controller.query; + +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.annotation.security.UserID; +import org.dongguk.onroad.core.dto.ResponseDto; +import org.dongguk.onroad.question.application.dto.response.ReadQuestionResponseDto; +import org.dongguk.onroad.question.application.dto.response.ReadReplyResponseDto; +import org.dongguk.onroad.question.application.usecase.ReadQuestionUseCase; +import org.dongguk.onroad.question.application.usecase.ReadReplyUseCase; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +public class QuestionQueryV1Controller { + + private final ReadQuestionUseCase readQuestionUseCase; + private final ReadReplyUseCase readReplyUseCase; + + @GetMapping("/v1/questions") + public ResponseDto readQuestions( + @UserID UUID userId, + @RequestParam("id") Long lectureId, + @RequestParam("week") Integer weekIndex + ) { + return ResponseDto.ok(readQuestionUseCase.execute(userId, lectureId, weekIndex)); + } + + @GetMapping("/v1/questions/{id}/replies") + public ResponseDto readReplies( + @UserID UUID userId, + @PathVariable Long id + ) { + return ResponseDto.ok(readReplyUseCase.execute(userId, id)); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/dto/.keep b/src/main/java/org/dongguk/onroad/question/application/dto/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateQuestionRequestDto.java b/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateQuestionRequestDto.java new file mode 100644 index 0000000..6c14947 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateQuestionRequestDto.java @@ -0,0 +1,18 @@ +package org.dongguk.onroad.question.application.dto.request; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public record CreateQuestionRequestDto( + @JsonProperty("lecture_id") + Long lectureId, + + @JsonProperty("week") + Integer week, + + @JsonProperty("title") + String title, + + @JsonProperty("content") + String content +) { +} diff --git a/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateReplyRequestDto.java b/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateReplyRequestDto.java new file mode 100644 index 0000000..a321a56 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/dto/request/CreateReplyRequestDto.java @@ -0,0 +1,9 @@ +package org.dongguk.onroad.question.application.dto.request; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public record CreateReplyRequestDto( + @JsonProperty("content") + String content +) { +} diff --git a/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadQuestionResponseDto.java b/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadQuestionResponseDto.java new file mode 100644 index 0000000..b3cc148 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadQuestionResponseDto.java @@ -0,0 +1,104 @@ +package org.dongguk.onroad.question.application.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Getter; +import org.dongguk.onroad.core.dto.SelfValidating; +import org.dongguk.onroad.core.utility.DateTimeUtil; +import org.dongguk.onroad.question.domain.Question; + +import java.util.List; + +@Getter +public class ReadQuestionResponseDto extends SelfValidating { + + @JsonProperty("question_list") + @NotNull(message = "question_list는 null일 수 없습니다.") + private final List questionList; + + @Builder + public ReadQuestionResponseDto(List questionList) { + this.questionList = questionList; + this.validateSelf(); + } + + @Getter + public static class QuestionDto extends SelfValidating { + + @JsonProperty("question_info") + @NotNull(message = "question_info는 null일 수 없습니다.") + private final QuestionInfoDto questionInfo; + + @JsonProperty("reply_count") + @NotNull(message = "reply_count는 null일 수 없습니다.") + private final Integer replyCount; + + @Builder + public QuestionDto(QuestionInfoDto questionInfo, Integer replyCount) { + this.questionInfo = questionInfo; + this.replyCount = replyCount; + this.validateSelf(); + } + + public static QuestionDto of(QuestionInfoDto questionInfo, Integer replyCount) { + return QuestionDto.builder() + .questionInfo(questionInfo) + .replyCount(replyCount) + .build(); + } + } + + @Getter + public static class QuestionInfoDto extends SelfValidating { + + @JsonProperty("writer_name") + @NotNull(message = "writer_name은 null일 수 없습니다.") + private final String writerName; + + @JsonProperty("created_at") + @NotNull(message = "created_at은 null일 수 없습니다.") + private final String createdAt; + + @JsonProperty("title") + @NotNull(message = "title은 null일 수 없습니다.") + private final String title; + + @JsonProperty("content") + @NotNull(message = "content는 null일 수 없습니다.") + private final String content; + + @Builder + public QuestionInfoDto(String writerName, String createdAt, String title, String content) { + this.writerName = writerName; + this.createdAt = createdAt; + this.title = title; + this.content = content; + this.validateSelf(); + } + + public static QuestionInfoDto fromEntityProfessor(Question question) { + return QuestionInfoDto.builder() + .writerName(question.getStudent().getName()) + .createdAt(DateTimeUtil.convertLocalDateTimeToString(question.getCreatedAt())) + .title(question.getTitle()) + .content(question.getContent()) + .build(); + } + + public static QuestionInfoDto fromEntityStudent(Question question) { + return QuestionInfoDto.builder() + .writerName("annoymous") + .createdAt(DateTimeUtil.convertLocalDateTimeToString(question.getCreatedAt())) + .title(question.getTitle()) + .content(question.getContent()) + .build(); + } + } + + public static ReadQuestionResponseDto of(List questionList) { + return ReadQuestionResponseDto.builder() + .questionList(questionList) + .build(); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadReplyResponseDto.java b/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadReplyResponseDto.java new file mode 100644 index 0000000..3ebab80 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/dto/response/ReadReplyResponseDto.java @@ -0,0 +1,71 @@ +package org.dongguk.onroad.question.application.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Getter; +import org.dongguk.onroad.core.dto.SelfValidating; +import org.dongguk.onroad.core.utility.DateTimeUtil; +import org.dongguk.onroad.question.domain.Reply; + +import java.util.List; + +@Getter +public class ReadReplyResponseDto extends SelfValidating { + + @JsonProperty("reply_list") + @NotNull(message = "reply_list는 null일 수 없습니다.") + private final List replyList; + + @Builder + public ReadReplyResponseDto(List replyList) { + this.replyList = replyList; + this.validateSelf(); + } + + @Getter + public static class ReplyDto extends SelfValidating { + + @JsonProperty("writer_name") + @NotNull(message = "writer_name은 null일 수 없습니다.") + private final String writerName; + + @JsonProperty("created_at") + @NotNull(message = "created_at은 null일 수 없습니다.") + private final String createdAt; + + @JsonProperty("content") + @NotNull(message = "content는 null일 수 없습니다.") + private final String content; + + @Builder + public ReplyDto(String writerName, String createdAt, String content) { + this.writerName = writerName; + this.createdAt = createdAt; + this.content = content; + this.validateSelf(); + } + + public static ReplyDto fromEntityProfessor(Reply reply) { + return ReplyDto.builder() + .writerName(reply.getUser().getName()) + .createdAt(DateTimeUtil.convertLocalDateTimeToString(reply.getCreatedAt())) + .content(reply.getContent()) + .build(); + } + + public static ReplyDto fromEntityStudent(Reply reply) { + return ReplyDto.builder() + .writerName("anonymous") + .createdAt(DateTimeUtil.convertLocalDateTimeToString(reply.getCreatedAt())) + .content(reply.getContent()) + .build(); + } + } + + public static ReadReplyResponseDto of(List replyList) { + return ReadReplyResponseDto.builder() + .replyList(replyList) + .build(); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/service/.keep b/src/main/java/org/dongguk/onroad/question/application/service/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/dongguk/onroad/question/application/service/CreateQuestionService.java b/src/main/java/org/dongguk/onroad/question/application/service/CreateQuestionService.java new file mode 100644 index 0000000..41ccafe --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/service/CreateQuestionService.java @@ -0,0 +1,58 @@ +package org.dongguk.onroad.question.application.service; + +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.exception.error.ErrorCode; +import org.dongguk.onroad.core.exception.type.CommonException; +import org.dongguk.onroad.question.application.dto.request.CreateQuestionRequestDto; +import org.dongguk.onroad.question.application.usecase.CreateQuestionUseCase; +import org.dongguk.onroad.question.domain.Question; +import org.dongguk.onroad.question.domain.service.QuestionService; +import org.dongguk.onroad.question.repository.QuestionRepository; +import org.dongguk.onroad.roadmap.domain.Lecture; +import org.dongguk.onroad.roadmap.repository.LectureRepository; +import org.dongguk.onroad.security.domain.mysql.User; +import org.dongguk.onroad.security.domain.service.UserService; +import org.dongguk.onroad.security.repository.mysql.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class CreateQuestionService implements CreateQuestionUseCase { + + private final UserRepository userRepository; + private final QuestionRepository questionRepository; + private final LectureRepository lectureRepository; + + private final UserService userService; + private final QuestionService questionService; + + @Override + @Transactional + public void execute(UUID userId, CreateQuestionRequestDto requestDto) { + + // 유저 조회 + User user = userRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // 학생 자격 검증 + userService.validateStudent(user); + + // 강의 조회 + Lecture lecture = lectureRepository.findById(requestDto.lectureId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // 질문 생성 + Question question = questionService.createQuestion( + requestDto.title(), + requestDto.content(), + requestDto.week(), + lecture, + user); + + questionRepository.save(question); + } + +} diff --git a/src/main/java/org/dongguk/onroad/question/application/service/CreateReplyService.java b/src/main/java/org/dongguk/onroad/question/application/service/CreateReplyService.java new file mode 100644 index 0000000..ec87fa9 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/service/CreateReplyService.java @@ -0,0 +1,46 @@ +package org.dongguk.onroad.question.application.service; + +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.exception.error.ErrorCode; +import org.dongguk.onroad.core.exception.type.CommonException; +import org.dongguk.onroad.question.application.dto.request.CreateReplyRequestDto; +import org.dongguk.onroad.question.application.usecase.CreateReplyUseCase; +import org.dongguk.onroad.question.domain.Question; +import org.dongguk.onroad.question.domain.Reply; +import org.dongguk.onroad.question.domain.service.ReplyService; +import org.dongguk.onroad.question.repository.QuestionRepository; +import org.dongguk.onroad.question.repository.ReplyRepository; +import org.dongguk.onroad.security.domain.mysql.User; +import org.dongguk.onroad.security.repository.mysql.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class CreateReplyService implements CreateReplyUseCase { + + private final UserRepository userRepository; + private final ReplyRepository replyRepository; + private final QuestionRepository questionRepository; + + private final ReplyService replyService; + + @Override + @Transactional + public void execute(UUID userId, Long questionId, CreateReplyRequestDto requestDto) { + + // 유저 조회 + User user = userRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // 질문 조회 + Question question = questionRepository.findById(questionId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // 답변 생성 + Reply reply = replyService.createReply(user, question, requestDto.content()); + replyRepository.save(reply); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/service/ReadQuestionService.java b/src/main/java/org/dongguk/onroad/question/application/service/ReadQuestionService.java new file mode 100644 index 0000000..2df01eb --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/service/ReadQuestionService.java @@ -0,0 +1,65 @@ +package org.dongguk.onroad.question.application.service; + +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.exception.error.ErrorCode; +import org.dongguk.onroad.core.exception.type.CommonException; +import org.dongguk.onroad.question.application.dto.response.ReadQuestionResponseDto; +import org.dongguk.onroad.question.application.usecase.ReadQuestionUseCase; +import org.dongguk.onroad.question.domain.Question; +import org.dongguk.onroad.question.repository.QuestionRepository; +import org.dongguk.onroad.question.repository.ReplyRepository; +import org.dongguk.onroad.security.domain.mysql.User; +import org.dongguk.onroad.security.domain.type.ESecurityRole; +import org.dongguk.onroad.security.repository.mysql.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class ReadQuestionService implements ReadQuestionUseCase { + + private final UserRepository userRepository; + private final QuestionRepository questionRepository; + private final ReplyRepository replyRepository; + + @Override + @Transactional(readOnly = true) + public ReadQuestionResponseDto execute(UUID userId, Long lectureId, Integer weekIndex) { + + User user = userRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // 학생이라면, 모든 질문의 질문자 명이 anonymous로 변경 + if (user.getRole() == ESecurityRole.STUDENT) { + // 질문 조회 + List questions = questionRepository.findAllByLectureIdAndWeekIndex(lectureId, weekIndex); + + List questionDto = questions.stream() + .map(question -> { + Integer replyCount = replyRepository.findAllByQuestionId(question.getId()).size(); + ReadQuestionResponseDto.QuestionInfoDto infoDto = ReadQuestionResponseDto.QuestionInfoDto.fromEntityStudent(question); + return ReadQuestionResponseDto.QuestionDto.of(infoDto, replyCount); + } + ).toList(); + + return ReadQuestionResponseDto.of(questionDto); + } + + // 질문 조회 + List questions = questionRepository.findAllByLectureIdAndWeekIndex(lectureId, weekIndex); + + List questionDto = questions.stream() + .map(question -> { + Integer replyCount = replyRepository.findAllByQuestionId(question.getId()).size(); + ReadQuestionResponseDto.QuestionInfoDto infoDto = ReadQuestionResponseDto.QuestionInfoDto.fromEntityProfessor(question); + return ReadQuestionResponseDto.QuestionDto.of(infoDto, replyCount); + } + ).toList(); + + return ReadQuestionResponseDto.of(questionDto); + + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/service/ReadReplyService.java b/src/main/java/org/dongguk/onroad/question/application/service/ReadReplyService.java new file mode 100644 index 0000000..c05df01 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/service/ReadReplyService.java @@ -0,0 +1,47 @@ +package org.dongguk.onroad.question.application.service; + +import lombok.RequiredArgsConstructor; +import org.dongguk.onroad.core.exception.error.ErrorCode; +import org.dongguk.onroad.core.exception.type.CommonException; +import org.dongguk.onroad.question.application.dto.response.ReadReplyResponseDto; +import org.dongguk.onroad.question.application.usecase.ReadReplyUseCase; +import org.dongguk.onroad.question.domain.Reply; +import org.dongguk.onroad.question.repository.ReplyRepository; +import org.dongguk.onroad.security.domain.mysql.User; +import org.dongguk.onroad.security.domain.type.ESecurityRole; +import org.dongguk.onroad.security.repository.mysql.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class ReadReplyService implements ReadReplyUseCase { + + private final ReplyRepository replyRepository; + private final UserRepository userRepository; + + @Override + @Transactional(readOnly = true) + public ReadReplyResponseDto execute(UUID userId, Long questionId) { + + User user = userRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + if (user.getRole() == ESecurityRole.STUDENT) { + List replies = replyRepository.findAllByQuestionId(questionId); + + return ReadReplyResponseDto.of(replies.stream() + .map(ReadReplyResponseDto.ReplyDto::fromEntityStudent) + .toList()); + } + + List replies = replyRepository.findAllByQuestionId(questionId); + + return ReadReplyResponseDto.of(replies.stream() + .map(ReadReplyResponseDto.ReplyDto::fromEntityProfessor) + .toList()); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/application/usecase/.keep b/src/main/java/org/dongguk/onroad/question/application/usecase/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/dongguk/onroad/question/application/usecase/CreateQuestionUseCase.java b/src/main/java/org/dongguk/onroad/question/application/usecase/CreateQuestionUseCase.java new file mode 100644 index 0000000..810cdf3 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/usecase/CreateQuestionUseCase.java @@ -0,0 +1,13 @@ +package org.dongguk.onroad.question.application.usecase; + +import org.dongguk.onroad.core.annotation.bean.UseCase; +import org.dongguk.onroad.question.application.dto.request.CreateQuestionRequestDto; + +import java.util.UUID; + +@UseCase +public interface CreateQuestionUseCase { + + void execute(UUID userId, CreateQuestionRequestDto requestDto); + +} diff --git a/src/main/java/org/dongguk/onroad/question/application/usecase/CreateReplyUseCase.java b/src/main/java/org/dongguk/onroad/question/application/usecase/CreateReplyUseCase.java new file mode 100644 index 0000000..4a51c9a --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/usecase/CreateReplyUseCase.java @@ -0,0 +1,12 @@ +package org.dongguk.onroad.question.application.usecase; + +import org.dongguk.onroad.core.annotation.bean.UseCase; +import org.dongguk.onroad.question.application.dto.request.CreateReplyRequestDto; + +import java.util.UUID; + +@UseCase +public interface CreateReplyUseCase { + + void execute(UUID userId, Long questionId, CreateReplyRequestDto requestDto); +} diff --git a/src/main/java/org/dongguk/onroad/question/application/usecase/ReadQuestionUseCase.java b/src/main/java/org/dongguk/onroad/question/application/usecase/ReadQuestionUseCase.java new file mode 100644 index 0000000..389a376 --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/usecase/ReadQuestionUseCase.java @@ -0,0 +1,11 @@ +package org.dongguk.onroad.question.application.usecase; + +import org.dongguk.onroad.core.annotation.bean.UseCase; +import org.dongguk.onroad.question.application.dto.response.ReadQuestionResponseDto; + +import java.util.UUID; + +@UseCase +public interface ReadQuestionUseCase { + ReadQuestionResponseDto execute(UUID userId, Long lectureId, Integer weekIndex); +} diff --git a/src/main/java/org/dongguk/onroad/question/application/usecase/ReadReplyUseCase.java b/src/main/java/org/dongguk/onroad/question/application/usecase/ReadReplyUseCase.java new file mode 100644 index 0000000..c1f128d --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/application/usecase/ReadReplyUseCase.java @@ -0,0 +1,12 @@ +package org.dongguk.onroad.question.application.usecase; + +import org.dongguk.onroad.core.annotation.bean.UseCase; +import org.dongguk.onroad.question.application.dto.response.ReadReplyResponseDto; + +import java.util.UUID; + +@UseCase +public interface ReadReplyUseCase { + + ReadReplyResponseDto execute(UUID userId, Long questionId); +} diff --git a/src/main/java/org/dongguk/onroad/question/domain/Question.java b/src/main/java/org/dongguk/onroad/question/domain/Question.java index 6835fdf..58a706b 100644 --- a/src/main/java/org/dongguk/onroad/question/domain/Question.java +++ b/src/main/java/org/dongguk/onroad/question/domain/Question.java @@ -35,9 +35,6 @@ public class Question { @Column(nullable = false) private String content; - @Column(name = "img_url") - private String imgUrl; - @Column(name = "week_index", nullable = false) private Integer weekIndex; @@ -68,10 +65,9 @@ public class Question { /* Methods ------------------------------------ */ /* -------------------------------------------- */ @Builder - public Question(String title, String content, String imgUrl, Integer weekIndex, Lecture lecture, User student) { + public Question(String title, String content, Integer weekIndex, Lecture lecture, User student) { this.title = title; this.content = content; - this.imgUrl = imgUrl; this.weekIndex = weekIndex; this.lecture = lecture; this.student = student; diff --git a/src/main/java/org/dongguk/onroad/question/domain/Reply.java b/src/main/java/org/dongguk/onroad/question/domain/Reply.java index c8e0fc8..2a7ac8e 100644 --- a/src/main/java/org/dongguk/onroad/question/domain/Reply.java +++ b/src/main/java/org/dongguk/onroad/question/domain/Reply.java @@ -29,9 +29,6 @@ public class Reply { @Column(nullable = false) private String content; - @Column(name = "img_url") - private String imgUrl; - /* -------------------------------------------- */ /* Timestamp Column --------------------------- */ /* -------------------------------------------- */ @@ -53,9 +50,8 @@ public class Reply { /* Methods ------------------------------------ */ /* -------------------------------------------- */ @Builder - public Reply(String content, String imgUrl, User user, Question question) { + public Reply(String content, User user, Question question) { this.content = content; - this.imgUrl = imgUrl; this.user = user; this.question = question; this.createdAt = LocalDateTime.now(); diff --git a/src/main/java/org/dongguk/onroad/question/domain/service/QuestionService.java b/src/main/java/org/dongguk/onroad/question/domain/service/QuestionService.java new file mode 100644 index 0000000..1e9794f --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/domain/service/QuestionService.java @@ -0,0 +1,26 @@ +package org.dongguk.onroad.question.domain.service; + +import org.dongguk.onroad.question.domain.Question; +import org.dongguk.onroad.roadmap.domain.Lecture; +import org.dongguk.onroad.security.domain.mysql.User; +import org.springframework.stereotype.Service; + +@Service +public class QuestionService { + + public Question createQuestion( + String title, + String content, + Integer weekIndex, + Lecture lecture, + User student + ) { + return Question.builder() + .title(title) + .content(content) + .weekIndex(weekIndex) + .lecture(lecture) + .student(student) + .build(); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/domain/service/ReplyService.java b/src/main/java/org/dongguk/onroad/question/domain/service/ReplyService.java new file mode 100644 index 0000000..b3e57ec --- /dev/null +++ b/src/main/java/org/dongguk/onroad/question/domain/service/ReplyService.java @@ -0,0 +1,18 @@ +package org.dongguk.onroad.question.domain.service; + +import org.dongguk.onroad.question.domain.Question; +import org.dongguk.onroad.question.domain.Reply; +import org.dongguk.onroad.security.domain.mysql.User; +import org.springframework.stereotype.Service; + +@Service +public class ReplyService { + + public Reply createReply(User user, Question question, String content) { + return Reply.builder() + .content(content) + .user(user) + .question(question) + .build(); + } +} diff --git a/src/main/java/org/dongguk/onroad/question/repository/QuestionRepository.java b/src/main/java/org/dongguk/onroad/question/repository/QuestionRepository.java index 741c734..e942c17 100644 --- a/src/main/java/org/dongguk/onroad/question/repository/QuestionRepository.java +++ b/src/main/java/org/dongguk/onroad/question/repository/QuestionRepository.java @@ -4,6 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface QuestionRepository extends JpaRepository { + + List findAllByLectureIdAndWeekIndex(Long lectureId, Integer weekIndex); } diff --git a/src/main/java/org/dongguk/onroad/question/repository/ReplyRepository.java b/src/main/java/org/dongguk/onroad/question/repository/ReplyRepository.java index 31e7795..e551109 100644 --- a/src/main/java/org/dongguk/onroad/question/repository/ReplyRepository.java +++ b/src/main/java/org/dongguk/onroad/question/repository/ReplyRepository.java @@ -4,6 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ReplyRepository extends JpaRepository { + + List findAllByQuestionId(Long questionId); } diff --git a/src/main/java/org/dongguk/onroad/security/domain/service/UserService.java b/src/main/java/org/dongguk/onroad/security/domain/service/UserService.java index 8f48873..bc3be25 100644 --- a/src/main/java/org/dongguk/onroad/security/domain/service/UserService.java +++ b/src/main/java/org/dongguk/onroad/security/domain/service/UserService.java @@ -1,5 +1,7 @@ package org.dongguk.onroad.security.domain.service; +import org.dongguk.onroad.core.exception.error.ErrorCode; +import org.dongguk.onroad.core.exception.type.CommonException; import org.dongguk.onroad.security.domain.mysql.User; import org.dongguk.onroad.security.domain.type.ESecurityRole; import org.dongguk.onroad.security.info.CustomUserPrincipal; @@ -28,13 +30,13 @@ public User createUser( public void validateStudent(User user) { if (!user.getRole().equals(ESecurityRole.STUDENT)) { - throw new IllegalArgumentException("유저의 권한이 학생이 아닙니다."); + throw new CommonException(ErrorCode.ACCESS_DENIED); } } public void validateProfessor(User user) { if (!user.getRole().equals(ESecurityRole.PROFESSOR)) { - throw new IllegalArgumentException("유저의 권한이 교수가 아닙니다."); + throw new CommonException(ErrorCode.ACCESS_DENIED); } } }