Skip to content

Commit

Permalink
[REFACTOR] qna 도메인 리펙토링 (#191)
Browse files Browse the repository at this point in the history
Co-authored-by: KyungMin Lee <[email protected]>
  • Loading branch information
voidmelody and tidavid1 authored Jan 18, 2024
1 parent f4b4ca6 commit 1359e16
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public enum ErrorCode {
// 403
INVALID_USER(FORBIDDEN, "유효하지 않은 사용자입니다."),
SECURITY_ACCESS_DENIED(FORBIDDEN, "접근 권한이 없습니다."),
QUESTION_ACCESS_DENIED(FORBIDDEN, "해당 질문에 대한 접근 권한이 없습니다."),
// 404
USER_NOT_FOUND(NOT_FOUND, "사용자를 찾을 수 없습니다."),
QUESTION_NOT_FOUND(NOT_FOUND, "문의를 찾을 수 없습니다"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.programmers.smrtstore.domain.qna.application;

import com.programmers.smrtstore.core.properties.ErrorCode;
import com.programmers.smrtstore.domain.qna.domain.entity.ProductAnswer;
import com.programmers.smrtstore.domain.qna.domain.entity.ProductQuestion;
import com.programmers.smrtstore.domain.qna.exception.QnAException;
import com.programmers.smrtstore.domain.qna.infrastructure.ProductAnswerRepository;
import com.programmers.smrtstore.domain.qna.infrastructure.ProductQuestionRepository;
import com.programmers.smrtstore.domain.qna.presentation.dto.req.CreateAnswerRequest;
import com.programmers.smrtstore.domain.qna.presentation.dto.req.UpdateAnswerRequest;
import com.programmers.smrtstore.domain.qna.presentation.dto.res.AnswerResponse;
import com.programmers.smrtstore.domain.qna.presentation.dto.res.UpdateAnswerResponse;
import com.programmers.smrtstore.domain.user.infrastructure.UserJpaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


@Service
@Transactional
@RequiredArgsConstructor
public class ProductAnswerService {
private final ProductAnswerRepository answerRepository;
private final ProductQuestionRepository questionRepository;
private final UserJpaRepository userJpaRepository;

@Secured({ "ROLE_ADMIN" })
public AnswerResponse addAnswer(Long userId, CreateAnswerRequest request) {
checkUserExist(userId);
Long questionId = request.getQuestionId();
String content = request.getContent();
ProductQuestion productQuestion = questionRepository.findById(questionId).orElseThrow(() -> new QnAException(ErrorCode.QUESTION_NOT_FOUND));
ProductAnswer productAnswer = ProductAnswer.builder()
.productQuestion(productQuestion)
.content(content)
.build();
return AnswerResponse.of(productAnswer);
}

@Transactional(readOnly = true)
public List<AnswerResponse> getAnswersByQuestionId(Long userId, Long questionId) {
ProductQuestion productQuestion = questionRepository.findById(questionId).orElseThrow();
return productQuestion.getProductAnswerList()
.stream()
.map(AnswerResponse::of)
.toList();
}

@Secured({ "ROLE_ADMIN" })
public UpdateAnswerResponse updateAnswer(Long userId, UpdateAnswerRequest request) {
checkUserExist(userId);
ProductAnswer productAnswer = answerRepository.findById(request.getId()).orElseThrow(() -> new QnAException(ErrorCode.ANSWER_NOT_FOUND));
productAnswer.updateContent(request.getContent());
return UpdateAnswerResponse.of(productAnswer);
}

private void checkUserExist(Long userId) {
userJpaRepository.findById(userId).orElseThrow(() -> new QnAException(ErrorCode.USER_NOT_FOUND));
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package com.programmers.smrtstore.domain.qna.application;

import com.programmers.smrtstore.core.properties.ErrorCode;
import com.programmers.smrtstore.domain.qna.domain.entity.ProductAnswer;
import com.programmers.smrtstore.domain.qna.domain.entity.ProductQuestion;
import com.programmers.smrtstore.domain.qna.exception.QnAException;
import com.programmers.smrtstore.domain.qna.infrastructure.ProductAnswerRepository;
import com.programmers.smrtstore.domain.qna.infrastructure.ProductQuestionRepository;
import com.programmers.smrtstore.domain.qna.presentation.dto.req.*;
import com.programmers.smrtstore.domain.qna.presentation.dto.res.*;
Expand All @@ -20,15 +18,13 @@
@Service
@Transactional
@RequiredArgsConstructor
public class ProductQnAService {
private final ProductAnswerRepository productAnswerRepository;

public class ProductQuestionService {
private final ProductQuestionRepository questionRepository;
private final UserJpaRepository userJpaRepository;

public CreateQuestionResponse createQuestion(Long userId, CreateQuestionRequest request) {
checkUserValid(userId, request.getUserId());
checkUserExist(userId);
checkUserValid(userId, request.getUserId());
ProductQuestion productQuestion = ProductQuestion.builder()
.userId(request.getUserId())
.productId(request.getProductId())
Expand All @@ -40,21 +36,24 @@ public CreateQuestionResponse createQuestion(Long userId, CreateQuestionRequest

@Transactional(readOnly = true)
public List<QuestionResponse> findByUserId(Long userId, FindQuestionRequest request) {
checkUserValid(userId, request.getUserId());
checkUserExist(userId);
checkUserValid(userId, request.getUserId());
return questionRepository.findByUserId(userId);
}

public UpdateQuestionResponse updateQuestion(Long userId, UpdateQuestionRequest request) {
checkUserExist(userId);
ProductQuestion productQuestion = questionRepository.findById(request.getId()).orElseThrow(() -> new QnAException(ErrorCode.QUESTION_NOT_FOUND));
productQuestion.updateContent(request.getContent());
productQuestion.updateContent(userId, request.getContent());
return UpdateQuestionResponse.of(productQuestion);
}

public DeleteQuestionResponse deleteQuestion(Long userId, Long deleteId) {
checkUserExist(userId);
ProductQuestion deleteProductQuestion = questionRepository.findById(deleteId).orElseThrow(() -> new QnAException(ErrorCode.QUESTION_NOT_FOUND));
if (!deleteProductQuestion.checkUserEquals(userId)) {
throw new QnAException(ErrorCode.QUESTION_ACCESS_DENIED);
}
questionRepository.delete(deleteProductQuestion);
return DeleteQuestionResponse.of(deleteProductQuestion);
}
Expand All @@ -64,41 +63,14 @@ public List<QuestionResponse> findByProductId(Long productId) {
return questionRepository.findByProductId(productId);
}

public AnswerResponse addAnswer(Long userId, CreateAnswerRequest request) {
checkUserExist(userId);
Long questionId = request.getQuestionId();
String content = request.getContent();
ProductQuestion productQuestion = questionRepository.findById(questionId).orElseThrow(() -> new QnAException(ErrorCode.QUESTION_NOT_FOUND));
ProductAnswer productAnswer = ProductAnswer.builder()
.productQuestion(productQuestion)
.content(content)
.build();
return AnswerResponse.of(productAnswer);
}

@Transactional(readOnly = true)
public List<AnswerResponse> getAnswersByQuestionId(Long userId, Long questionId) {
ProductQuestion productQuestion = questionRepository.findById(questionId).orElseThrow();
return productQuestion.getProductAnswerList()
.stream()
.map(AnswerResponse::of)
.toList();
}

public UpdateAnswerResponse updateAnswer(Long userId, UpdateAnswerRequest request) {
checkUserExist(userId);
ProductAnswer productAnswer = productAnswerRepository.findById(request.getId()).orElseThrow(() -> new QnAException(ErrorCode.ANSWER_NOT_FOUND));
productAnswer.updateContent(request.getContent());
return UpdateAnswerResponse.of(productAnswer);
}

void checkUserValid(Long tokenUserId, Long requestUserId) {
private void checkUserValid(Long tokenUserId, Long requestUserId) {
if(!tokenUserId.equals(requestUserId)) {
throw new QnAException(ErrorCode.USER_NOT_FOUND);
}
}

void checkUserExist(Long userId) {
private void checkUserExist(Long userId) {
userJpaRepository.findById(userId).orElseThrow(() -> new QnAException(ErrorCode.USER_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.programmers.smrtstore.domain.qna.domain.entity;

import com.programmers.smrtstore.core.properties.ErrorCode;
import com.programmers.smrtstore.domain.qna.exception.QnAException;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
Expand Down Expand Up @@ -50,7 +52,14 @@ public ProductQuestion(Long userId, Long productId, String content) {
this.content = content;
}

public void updateContent(String updateContent) {
public void updateContent(Long userId, String updateContent) {
if (!checkUserEquals(userId)) {
throw new QnAException(ErrorCode.QUESTION_ACCESS_DENIED);
}
this.content = updateContent;
}

public Boolean checkUserEquals(Long userId) {
return this.userId.equals(userId);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.programmers.smrtstore.domain.qna.presentation.controller;

import com.programmers.smrtstore.common.annotation.UserId;
import com.programmers.smrtstore.domain.qna.application.ProductQnAService;
import com.programmers.smrtstore.domain.qna.application.ProductAnswerService;
import com.programmers.smrtstore.domain.qna.application.ProductQuestionService;
import com.programmers.smrtstore.domain.qna.presentation.dto.req.*;
import com.programmers.smrtstore.domain.qna.presentation.dto.res.*;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,60 +15,61 @@
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class ProductQnAController {
private final ProductQnAService qnAService;
private final ProductQuestionService questionService;
private final ProductAnswerService answerService;

@PostMapping("/qna")
public ResponseEntity<CreateQuestionResponse> createQuestion(@UserId Long userId,
@RequestBody CreateQuestionRequest request) {
CreateQuestionResponse response = qnAService.createQuestion(userId, request);
CreateQuestionResponse response = questionService.createQuestion(userId, request);
return ResponseEntity.ok(response);
}

@GetMapping("/my/qna")
public ResponseEntity<List<QuestionResponse>> findMyQuestion(@UserId Long userId,
@RequestBody FindQuestionRequest request) {
List<QuestionResponse> response = qnAService.findByUserId(userId, request);
List<QuestionResponse> response = questionService.findByUserId(userId, request);
return ResponseEntity.ok(response);
}

@PutMapping("/qna")
public ResponseEntity<UpdateQuestionResponse> updateQuestion(@UserId Long userId,
@RequestBody UpdateQuestionRequest request) {
UpdateQuestionResponse response = qnAService.updateQuestion(userId, request);
UpdateQuestionResponse response = questionService.updateQuestion(userId, request);
return ResponseEntity.ok(response);
}

@DeleteMapping("/qna/{id}")
public ResponseEntity<DeleteQuestionResponse> deleteQuestion(@UserId Long userId,
@PathVariable("id") Long deleteId) {
DeleteQuestionResponse response = qnAService.deleteQuestion(userId, deleteId);
DeleteQuestionResponse response = questionService.deleteQuestion(userId, deleteId);
return ResponseEntity.ok(response);
}

@GetMapping("/products/{productId}/qna")
public ResponseEntity<List<QuestionResponse>> getQuestionByProductId(@PathVariable("productId") Long productId) {
List<QuestionResponse> response = qnAService.findByProductId(productId);
List<QuestionResponse> response = questionService.findByProductId(productId);
return ResponseEntity.ok(response);
}

@PostMapping("/admin/qna")
public ResponseEntity<AnswerResponse> addAnswerToQuestion(@UserId Long userId,
@RequestBody CreateAnswerRequest request) {
AnswerResponse response = qnAService.addAnswer(userId, request);
AnswerResponse response = answerService.addAnswer(userId, request);
return ResponseEntity.ok(response);
}

@PutMapping("/qna/reply")
public ResponseEntity<UpdateAnswerResponse> updateAnswer(@UserId Long userId,
@RequestBody UpdateAnswerRequest request) {
UpdateAnswerResponse response = qnAService.updateAnswer(userId, request);
UpdateAnswerResponse response = answerService.updateAnswer(userId, request);
return ResponseEntity.ok(response);
}

@GetMapping("/qna/replies/{questionId}")
@GetMapping("/qna/reply/{questionId}")
public ResponseEntity<List<AnswerResponse>> getAnswersByQuestionId(@UserId Long userId,
@PathVariable Long questionId) {
List<AnswerResponse> response = qnAService.getAnswersByQuestionId(userId, questionId);
List<AnswerResponse> response = answerService.getAnswersByQuestionId(userId, questionId);
return ResponseEntity.ok(response);
}
}
Loading

0 comments on commit 1359e16

Please sign in to comment.