Skip to content

Commit

Permalink
[BE] refactor: GroupAccessCode를 발급하지 않고 사용자가 직접 입력하면서 변경되는 사항을 반영 (#441)
Browse files Browse the repository at this point in the history
* feat: GroupAccessCode 클래스 및 비밀번호 검증 로직 추가

* refactor: 그룹 생성 요청 dto에 groupAccessCode 추가

* refactor: 리뷰 상세 조회 로직 변경

* refactor: 리뷰 그룹 생성 로직에 groupAccessCode 검증

* refactor: 리뷰 목록 조회 로직 수정중

* test: 변경된 사항 테스트 반영

* refactor: 로그 메세지 보강

* refactor: 리뷰 목록 조회 로직 수정완

* test: 깨지는 테스트 해결

* docs: 변경된 내용 api 문서에 반영

* refactor: 그룹 액세스 코드의 필드명 변경

* refactor: 네이티브 쿼리를 기본 쿼리 메서드로 변경

* refactor: 사용하지 않는 상수 제거

* refactor: 인증정보 불일치 예외 메시지 구체적으로 변경

* refactor: 사용하지 않는 필드와 클래스 제거

* test: reviewRequestCode와 groupAccessCode 서로 다르게 변경

---------

Co-authored-by: KIMGYUTAE <[email protected]>
Co-authored-by: nayonsoso <[email protected]>
  • Loading branch information
3 people authored Aug 20, 2024
1 parent fa4f70d commit ff2b7cc
Show file tree
Hide file tree
Showing 22 changed files with 222 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package reviewme.global.exception;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class UnexpectedRequestException extends ReviewMeException {

protected UnexpectedRequestException(String errorMessage) {
super(errorMessage);
log.warn("", this);
}
}
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reviewme.global.HeaderProperty;
import reviewme.review.service.CreateReviewService;
Expand Down Expand Up @@ -35,17 +36,22 @@ public ResponseEntity<Void> createReview(@Valid @RequestBody CreateReviewRequest

@GetMapping("/v2/reviews")
public ResponseEntity<ReceivedReviewsResponse> findReceivedReviews(
@RequestParam String reviewRequestCode,
@HeaderProperty(GROUP_ACCESS_CODE_HEADER) String groupAccessCode
) {
ReceivedReviewsResponse response = reviewService.findReceivedReviews(groupAccessCode);
ReceivedReviewsResponse response = reviewService.findReceivedReviews(reviewRequestCode, groupAccessCode);
return ResponseEntity.ok(response);
}

@GetMapping("/v2/reviews/{id}")
public ResponseEntity<TemplateAnswerResponse> findReceivedReviewDetail(
@PathVariable long id,
@HeaderProperty(GROUP_ACCESS_CODE_HEADER) String groupAccessCode) {
TemplateAnswerResponse response = reviewDetailLookupService.getReviewDetail(groupAccessCode, id);
@RequestParam String reviewRequestCode,
@HeaderProperty(GROUP_ACCESS_CODE_HEADER) String groupAccessCode
) {
TemplateAnswerResponse response = reviewDetailLookupService.getReviewDetail(
id, reviewRequestCode, groupAccessCode
);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,14 @@ public interface ReviewRepository extends JpaRepository<Review, Long> {
List<Review> findReceivedReviewsByGroupId(long reviewGroupId);

Optional<Review> findByIdAndReviewGroupId(long reviewId, long reviewGroupId);

@Query(value = """
SELECT r.* FROM review r
INNER JOIN review_group rg
ON rg.id = r.review_group_id
WHERE r.id = :reviewId
AND rg.review_request_code = :reviewRequestCode
AND rg.group_access_code = :groupAccessCode
""", nativeQuery = true)
Optional<Review> findByIdAndCodes(long reviewId, String reviewRequestCode, String groupAccessCode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
import reviewme.review.domain.Review;
import reviewme.review.domain.TextAnswer;
import reviewme.review.domain.TextAnswers;
import reviewme.review.domain.exception.InvalidReviewAccessByReviewGroupException;
import reviewme.review.domain.exception.ReviewGroupNotFoundByGroupAccessCodeException;
import reviewme.review.repository.ReviewRepository;
import reviewme.review.service.dto.response.detail.OptionGroupAnswerResponse;
import reviewme.review.service.dto.response.detail.OptionItemAnswerResponse;
import reviewme.review.service.dto.response.detail.QuestionAnswerResponse;
import reviewme.review.service.dto.response.detail.SectionAnswerResponse;
import reviewme.review.service.dto.response.detail.TemplateAnswerResponse;
import reviewme.review.service.exception.ReviewGroupNotFoundByReviewException;
import reviewme.review.service.exception.ReviewNotFoundByIdAndCodesException;
import reviewme.reviewgroup.domain.ReviewGroup;
import reviewme.reviewgroup.repository.ReviewGroupRepository;
import reviewme.template.domain.Section;
Expand All @@ -41,12 +41,13 @@ public class ReviewDetailLookupService {
private final OptionItemRepository optionItemRepository;
private final OptionGroupRepository optionGroupRepository;

public TemplateAnswerResponse getReviewDetail(String groupAccessCode, long reviewId) {
ReviewGroup reviewGroup = reviewGroupRepository.findByGroupAccessCode(groupAccessCode)
.orElseThrow(() -> new ReviewGroupNotFoundByGroupAccessCodeException(groupAccessCode));
public TemplateAnswerResponse getReviewDetail(long reviewId, String reviewRequestCode, String groupAccessCode) {
Review review = reviewRepository.findByIdAndCodes(reviewId, reviewRequestCode, groupAccessCode)
.orElseThrow(() -> new ReviewNotFoundByIdAndCodesException(reviewId, reviewRequestCode, groupAccessCode));

ReviewGroup reviewGroup = reviewGroupRepository.findById(review.getReviewGroupId())
.orElseThrow(() -> new ReviewGroupNotFoundByReviewException(review.getId(), review.getReviewGroupId()));

Review review = reviewRepository.findByIdAndReviewGroupId(reviewId, reviewGroup.getId())
.orElseThrow(() -> new InvalidReviewAccessByReviewGroupException(reviewId, reviewGroup.getId()));
long templateId = review.getTemplateId();

List<Section> sections = sectionRepository.findAllByTemplateId(templateId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import reviewme.question.domain.OptionType;
import reviewme.question.repository.OptionItemRepository;
import reviewme.review.domain.Review;
import reviewme.review.domain.exception.ReviewGroupNotFoundByGroupAccessCodeException;
import reviewme.review.repository.ReviewRepository;
import reviewme.review.service.dto.response.list.ReceivedReviewCategoryResponse;
import reviewme.review.service.dto.response.list.ReceivedReviewResponse;
import reviewme.review.service.dto.response.list.ReceivedReviewsResponse;
import reviewme.review.service.exception.ReviewGroupNotFoundByCodesException;
import reviewme.reviewgroup.domain.ReviewGroup;
import reviewme.reviewgroup.repository.ReviewGroupRepository;

Expand All @@ -27,9 +27,10 @@ public class ReviewService {
private final ReviewPreviewGenerator reviewPreviewGenerator = new ReviewPreviewGenerator();

@Transactional(readOnly = true)
public ReceivedReviewsResponse findReceivedReviews(String groupAccessCode) {
ReviewGroup reviewGroup = reviewGroupRepository.findByGroupAccessCode(groupAccessCode)
.orElseThrow(() -> new ReviewGroupNotFoundByGroupAccessCodeException(groupAccessCode));
public ReceivedReviewsResponse findReceivedReviews(String reviewRequestCode, String groupAccessCode) {
ReviewGroup reviewGroup = reviewGroupRepository
.findByReviewRequestCodeAndGroupAccessCode_Code(reviewRequestCode, groupAccessCode)
.orElseThrow(() -> new ReviewGroupNotFoundByCodesException(reviewRequestCode, groupAccessCode));

List<ReceivedReviewResponse> reviewResponses =
reviewRepository.findReceivedReviewsByGroupId(reviewGroup.getId())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package reviewme.review.service.exception;

import lombok.extern.slf4j.Slf4j;
import reviewme.global.exception.BadRequestException;

@Slf4j
public class ReviewGroupNotFoundByCodesException extends BadRequestException {

public ReviewGroupNotFoundByCodesException(String reviewRequestCode, String groupAccessCode) {
super("인증 정보에 해당하는 리뷰 확인 코드와 리뷰 요청 코드를 통해 찾을 수 있는 리뷰 그룹이 없어요.");
log.info("ReviewGroup not found by codes - reviewRequestCode: {}, groupAccessCode: {}",
reviewRequestCode, groupAccessCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package reviewme.review.service.exception;

import lombok.extern.slf4j.Slf4j;
import reviewme.global.exception.DataInconsistencyException;

@Slf4j
public class ReviewGroupNotFoundByReviewException extends DataInconsistencyException {

public ReviewGroupNotFoundByReviewException(long reviewId, long reviewGroupId) {
super("서버 내부에서 문제가 발생했어요. 서버에 문의해주세요.");
log.error("ReviewGroup not found from review - reviewId: {}, reviewGroupId: {}", reviewId, reviewGroupId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package reviewme.review.service.exception;

import lombok.extern.slf4j.Slf4j;
import reviewme.global.exception.NotFoundException;

@Slf4j
public class ReviewNotFoundByIdAndCodesException extends NotFoundException {

public ReviewNotFoundByIdAndCodesException(long reviewId, String reviewRequestCode, String groupAccessCode) {
super("리뷰를 찾을 수 없어요");
log.info("Review not found - reviewId: {}, reviewRequestCode: {}, groupAccessCode: {}",
reviewId, reviewRequestCode, groupAccessCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package reviewme.reviewgroup.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import reviewme.reviewgroup.domain.exception.InvalidGroupAccessCodeFormatException;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class GroupAccessCode {

private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{4,20}$");

@Column(name = "group_access_code", nullable = false)
private String code;

public GroupAccessCode(String code) {
validateGroupAccessCode(code);
this.code = code;
}

private void validateGroupAccessCode(String groupAccessCode) {
Matcher matcher = PATTERN.matcher(groupAccessCode);
if (!matcher.matches()) {
throw new InvalidGroupAccessCodeFormatException(groupAccessCode);
}
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package reviewme.reviewgroup.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand Down Expand Up @@ -36,8 +37,8 @@ public class ReviewGroup {
@Column(name = "review_request_code", nullable = false)
private String reviewRequestCode;

@Column(name = "group_access_code", nullable = false)
private String groupAccessCode;
@Embedded
private GroupAccessCode groupAccessCode;

@Column(name = "template_id", nullable = false)
private long templateId = 1L;
Expand All @@ -48,7 +49,7 @@ public ReviewGroup(String reviewee, String projectName, String reviewRequestCode
this.reviewee = reviewee;
this.projectName = projectName;
this.reviewRequestCode = reviewRequestCode;
this.groupAccessCode = groupAccessCode;
this.groupAccessCode = new GroupAccessCode(groupAccessCode);
}

private void validateRevieweeLength(String reviewee) {
Expand All @@ -64,4 +65,8 @@ private void validateProjectNameLength(String projectName) {
);
}
}

public String getGroupAccessCode() {
return groupAccessCode.getCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package reviewme.reviewgroup.domain.exception;

import lombok.extern.slf4j.Slf4j;
import reviewme.global.exception.BadRequestException;

@Slf4j
public class InvalidGroupAccessCodeFormatException extends BadRequestException {

public InvalidGroupAccessCodeFormatException(String groupAccessCode) {
super("그룹 액세스 코드 형식이 올바르지 않아요.");
log.warn("Invalid groupAccessCode format - groupAccessCode: {}", groupAccessCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ public interface ReviewGroupRepository extends JpaRepository<ReviewGroup, Long>

Optional<ReviewGroup> findByReviewRequestCode(String reviewRequestCode);

Optional<ReviewGroup> findByGroupAccessCode(String groupAccessCode);
Optional<ReviewGroup> findByReviewRequestCodeAndGroupAccessCode_Code(String reviewRequestCode, String groupAccessCode);

boolean existsByReviewRequestCode(String reviewRequestCode);

boolean existsByGroupAccessCode(String groupAccessCode);

boolean existsByReviewRequestCodeAndGroupAccessCode(String reviewRequestCode, String groupAccessCode);
boolean existsByReviewRequestCodeAndGroupAccessCode_Code(String reviewRequestCode, String groupAccessCode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import reviewme.reviewgroup.repository.ReviewGroupRepository;
import reviewme.reviewgroup.service.dto.CheckValidAccessRequest;
import reviewme.reviewgroup.service.dto.CheckValidAccessResponse;
import reviewme.reviewgroup.repository.ReviewGroupRepository;
import reviewme.reviewgroup.service.dto.ReviewGroupCreationRequest;
import reviewme.reviewgroup.service.dto.ReviewGroupCreationResponse;

Expand All @@ -16,31 +15,27 @@
public class ReviewGroupService {

private static final int REVIEW_REQUEST_CODE_LENGTH = 8;
private static final int GROUP_ACCESS_CODE_LENGTH = 8;

private final ReviewGroupRepository reviewGroupRepository;
private final RandomCodeGenerator randomCodeGenerator;

@Transactional
public ReviewGroupCreationResponse createReviewGroup(ReviewGroupCreationRequest request) {
String reviewRequestCode;
String groupAccessCode;
do {
reviewRequestCode = randomCodeGenerator.generate(REVIEW_REQUEST_CODE_LENGTH);
} while (reviewGroupRepository.existsByReviewRequestCode(reviewRequestCode));
do {
groupAccessCode = randomCodeGenerator.generate(GROUP_ACCESS_CODE_LENGTH);
} while (reviewGroupRepository.existsByGroupAccessCode(groupAccessCode));


ReviewGroup reviewGroup = reviewGroupRepository.save(
new ReviewGroup(request.revieweeName(), request.projectName(), reviewRequestCode, groupAccessCode)
new ReviewGroup(request.revieweeName(), request.projectName(), reviewRequestCode, request.groupAccessCode())
);
return new ReviewGroupCreationResponse(reviewGroup.getReviewRequestCode(), reviewGroup.getGroupAccessCode());
return new ReviewGroupCreationResponse(reviewGroup.getReviewRequestCode());
}

@Transactional(readOnly = true)
public CheckValidAccessResponse checkGroupAccessCode(CheckValidAccessRequest request) {
boolean hasAccess = reviewGroupRepository.existsByReviewRequestCodeAndGroupAccessCode(
boolean hasAccess = reviewGroupRepository.existsByReviewRequestCodeAndGroupAccessCode_Code(
request.reviewRequestCode(), request.groupAccessCode()
);
return new CheckValidAccessResponse(hasAccess);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import jakarta.validation.constraints.NotBlank;

public record ReviewGroupCreationRequest(
@NotBlank(message = "리뷰이 이름은 공백일 수 없어요.")

@NotBlank(message = "리뷰이 이름을 입력해주세요.")
String revieweeName,

@NotBlank(message = "프로젝트 이름은 공백일 수 없어요.")
String projectName
@NotBlank(message = "프로젝트 이름을 입력해주세요.")
String projectName,

@NotBlank(message = "비밀번호를 입력해주세요.")
String groupAccessCode
) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package reviewme.reviewgroup.service.dto;

public record ReviewGroupCreationResponse(
String reviewRequestCode,
String groupAccessCode
String reviewRequestCode
) {
}
Loading

0 comments on commit ff2b7cc

Please sign in to comment.