-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: dto 이름 변경 AnswerContentResponse -> TextResponse * feat: 질문ID에 해당하는 Answer 반환 함수 추가 * feat: 질문ID에 해당하는 OptionItem들 반환 함수 추가 * feat: 리뷰 요청 코드와 섹션ID에 해당하는 질문 반환 함수 추가 * feat: 리뷰 모이보기 API 구현 * refactor: 테스트에서 검증하고자 하는 것을 분명히 * refactor: 패키지 의존 방향 통일을 위한 레포지토리 함수 이동 * refactor: 테스트 목적에 해당하는 것만 남기기 * refactor: 함수 이름 변경 - 인자가 List<Long> 이므로, ids 로 끝나게 변경함 * refactor: 가동성을 위한 함수 분리 * refactor: 다른 서비스 클래스들과 네이밍 통일 * feat: 리뷰 요청 코드 검증, 섹션 아이디 검증 추가 * refactor: 섹션에 해당하는 질문 가져오는 함수 수정 AS-IS: 내 리뷰그룹 중 특정 세션에 대한 질문 가져오기 TO-BE: 리뷰그룹 검증 완료되었으므로 특정 세션에 대해서만 가져오도록 수정 * refactor: 답변 가져오는 함수 수정 AS-IS: 특정 질문에 대해서 답변된 것 다 받아오기 TO-BE: 내 리뷰 그룹에 해당한다는 조건 추가 * feat: 답변하지 않은 내용은 빈 배열로 받아오도록 하는 기능 추가 * fix: 깨지는 테스트 코드 봉합 * refactor: Mapper 분리 * refactor: 섹션 검증 방법 변경 AS-IS: boolean 으로 검증, sectionId 인자 그대로 사용 TO-BE: Optional<Section>으로 검증, section.getId() 사용 * refactor: 필요없는 JOIN 제거 * test: 테스트 코드 목적별로 분리 * feat: 질문 목록을 position 순서대로 정렬 * refactor: 테스트 코드 extracting 사용 변경 AS-IS: attribute 값을 문자열로 하드코딩 TO-BE: dtp 의 필드명으로 가져오기 e.g. VoteResponse::content * chore: 오타 수정 * test: 다른 리뷰 그룹이 있는 상황에 대한 테스트 * refactor: 접근제어자 수정 * feat: 하이라이트 응답 추가 * test: 추가된 속성 반환 테스트 * refactor: 유연한 레포지토리 함수로 변경 * refactor: 변수명 변경 * refactor: 가독성 개선 함수 분리, 변수명 변경, 함수 인자 변경 * refactor: Answer -> 구체Answer 캐스팅 예외 추가 * refactor: 서술형 답변 가져오는 함수 수정 * refactor: 선택지 목록 가져오는 함수 수정 * test: reviewGatherMapper에 대한 테스트 작성 * style: 개행 - 가독성 개선와 컨벤션 유지를 위함 * chore: 로그 메세지 수정 - 컨벤션 유지를 위함 * refactor: 컨트롤러 인자 타입 변경 - Long -> long * feat: 최대로 내려주는 응답 수 제한 기능 구현 * refactor: 테스트 코드 필드 접근제한자 추가 * refactor: 변수명 변경 * chore: 사용하지 않는 메서드 제거
- Loading branch information
Showing
24 changed files
with
954 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 0 additions & 14 deletions
14
backend/src/main/java/reviewme/review/service/GatheredReviewLookupService.java
This file was deleted.
Oops, something went wrong.
73 changes: 73 additions & 0 deletions
73
backend/src/main/java/reviewme/review/service/ReviewGatheredLookupService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package reviewme.review.service; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import reviewme.question.domain.Question; | ||
import reviewme.question.repository.QuestionRepository; | ||
import reviewme.review.domain.Answer; | ||
import reviewme.review.repository.AnswerRepository; | ||
import reviewme.review.service.dto.response.gathered.ReviewsGatheredBySectionResponse; | ||
import reviewme.review.service.exception.ReviewGroupNotFoundByReviewRequestCodeException; | ||
import reviewme.review.service.exception.SectionNotFoundInTemplateException; | ||
import reviewme.review.service.mapper.ReviewGatherMapper; | ||
import reviewme.reviewgroup.domain.ReviewGroup; | ||
import reviewme.reviewgroup.repository.ReviewGroupRepository; | ||
import reviewme.template.domain.Section; | ||
import reviewme.template.repository.SectionRepository; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class ReviewGatheredLookupService { | ||
|
||
private static final int ANSWER_RESPONSE_LIMIT = 100; | ||
|
||
private final QuestionRepository questionRepository; | ||
private final AnswerRepository answerRepository; | ||
private final ReviewGroupRepository reviewGroupRepository; | ||
private final SectionRepository sectionRepository; | ||
|
||
private final ReviewGatherMapper reviewGatherMapper; | ||
|
||
@Transactional(readOnly = true) | ||
public ReviewsGatheredBySectionResponse getReceivedReviewsBySectionId(String reviewRequestCode, long sectionId) { | ||
ReviewGroup reviewGroup = getReviewGroupOrThrow(reviewRequestCode); | ||
Section section = getSectionOrThrow(sectionId, reviewGroup); | ||
Map<Question, List<Answer>> questionAnswers = getQuestionAnswers(section, reviewGroup); | ||
|
||
return reviewGatherMapper.mapToReviewsGatheredBySection(questionAnswers); | ||
} | ||
|
||
private ReviewGroup getReviewGroupOrThrow(String reviewRequestCode) { | ||
return reviewGroupRepository.findByReviewRequestCode(reviewRequestCode) | ||
.orElseThrow(() -> new ReviewGroupNotFoundByReviewRequestCodeException(reviewRequestCode)); | ||
} | ||
|
||
private Section getSectionOrThrow(long sectionId, ReviewGroup reviewGroup) { | ||
return sectionRepository.findByIdAndTemplateId(sectionId, reviewGroup.getTemplateId()) | ||
.orElseThrow(() -> new SectionNotFoundInTemplateException(sectionId, reviewGroup.getTemplateId())); | ||
} | ||
|
||
private Map<Question, List<Answer>> getQuestionAnswers(Section section, ReviewGroup reviewGroup) { | ||
Map<Long, Question> questionIdQuestion = questionRepository | ||
.findAllBySectionIdOrderByPosition(section.getId()) | ||
.stream() | ||
.collect(Collectors.toMap(Question::getId, Function.identity())); | ||
|
||
Map<Long, List<Answer>> questionIdAnswers = answerRepository | ||
.findReceivedAnswersByQuestionIds(reviewGroup.getId(), questionIdQuestion.keySet(), | ||
ANSWER_RESPONSE_LIMIT) | ||
.stream() | ||
.collect(Collectors.groupingBy(Answer::getQuestionId)); | ||
|
||
return questionIdQuestion.values().stream() | ||
.collect(Collectors.toMap( | ||
Function.identity(), | ||
question -> questionIdAnswers.getOrDefault(question.getId(), List.of()) | ||
)); | ||
} | ||
} |
6 changes: 0 additions & 6 deletions
6
...nd/src/main/java/reviewme/review/service/dto/response/gathered/AnswerContentResponse.java
This file was deleted.
Oops, something went wrong.
9 changes: 9 additions & 0 deletions
9
backend/src/main/java/reviewme/review/service/dto/response/gathered/HighlightResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package reviewme.review.service.dto.response.gathered; | ||
|
||
import java.util.List; | ||
|
||
public record HighlightResponse( | ||
long lineIndex, | ||
List<RangeResponse> ranges | ||
) { | ||
} |
7 changes: 7 additions & 0 deletions
7
backend/src/main/java/reviewme/review/service/dto/response/gathered/RangeResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package reviewme.review.service.dto.response.gathered; | ||
|
||
public record RangeResponse( | ||
long startIndex, | ||
long endIndex | ||
) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
backend/src/main/java/reviewme/review/service/dto/response/gathered/TextResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package reviewme.review.service.dto.response.gathered; | ||
|
||
import java.util.List; | ||
|
||
public record TextResponse( | ||
long id, | ||
String content, | ||
List<HighlightResponse> highlights | ||
) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,6 @@ | |
|
||
public record VoteResponse( | ||
String content, | ||
int count | ||
long count | ||
) { | ||
} |
13 changes: 13 additions & 0 deletions
13
...c/main/java/reviewme/review/service/exception/GatheredAnswersTypeNonUniformException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 GatheredAnswersTypeNonUniformException extends DataInconsistencyException { | ||
|
||
public GatheredAnswersTypeNonUniformException(Throwable cause) { | ||
super("서버 내부 오류가 발생했습니다."); | ||
log.error("The types of answers to questions are not uniform.", cause); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...d/src/main/java/reviewme/review/service/exception/SectionNotFoundInTemplateException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.NotFoundException; | ||
|
||
@Slf4j | ||
public class SectionNotFoundInTemplateException extends NotFoundException { | ||
|
||
public SectionNotFoundInTemplateException(long sectionId, long templateId) { | ||
super("섹션 정보를 찾을 수 없습니다."); | ||
log.info("Section not found in template - sectionId: {}, templateId: {}", sectionId, templateId, this); | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
backend/src/main/java/reviewme/review/service/mapper/ReviewGatherMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package reviewme.review.service.mapper; | ||
|
||
import jakarta.annotation.Nullable; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Component; | ||
import reviewme.question.domain.OptionItem; | ||
import reviewme.question.domain.Question; | ||
import reviewme.question.repository.QuestionRepository; | ||
import reviewme.review.domain.Answer; | ||
import reviewme.review.domain.CheckboxAnswer; | ||
import reviewme.review.domain.CheckboxAnswerSelectedOption; | ||
import reviewme.review.domain.TextAnswer; | ||
import reviewme.review.service.dto.response.gathered.ReviewsGatheredByQuestionResponse; | ||
import reviewme.review.service.dto.response.gathered.ReviewsGatheredBySectionResponse; | ||
import reviewme.review.service.dto.response.gathered.SimpleQuestionResponse; | ||
import reviewme.review.service.dto.response.gathered.TextResponse; | ||
import reviewme.review.service.dto.response.gathered.VoteResponse; | ||
import reviewme.review.service.exception.GatheredAnswersTypeNonUniformException; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class ReviewGatherMapper { | ||
|
||
private final QuestionRepository questionRepository; | ||
|
||
public ReviewsGatheredBySectionResponse mapToReviewsGatheredBySection(Map<Question, List<Answer>> questionAnswers) { | ||
List<ReviewsGatheredByQuestionResponse> reviews = questionAnswers.entrySet() | ||
.stream() | ||
.map(entry -> mapToReviewsGatheredByQuestion(entry.getKey(), entry.getValue())) | ||
.toList(); | ||
|
||
return new ReviewsGatheredBySectionResponse(reviews); | ||
} | ||
|
||
private ReviewsGatheredByQuestionResponse mapToReviewsGatheredByQuestion(Question question, List<Answer> answers) { | ||
return new ReviewsGatheredByQuestionResponse( | ||
new SimpleQuestionResponse(question.getId(), question.getContent(), question.getQuestionType()), | ||
mapToTextResponse(question, answers), | ||
mapToVoteResponse(question, answers) | ||
); | ||
} | ||
|
||
@Nullable | ||
private List<TextResponse> mapToTextResponse(Question question, List<Answer> answers) { | ||
if (question.isSelectable()) { | ||
return null; | ||
} | ||
|
||
List<TextAnswer> textAnswers = castAllOrThrow(answers, TextAnswer.class); | ||
return textAnswers.stream() | ||
.map(textAnswer -> new TextResponse(textAnswer.getId(), textAnswer.getContent(), List.of())) | ||
.toList(); | ||
} | ||
|
||
@Nullable | ||
private List<VoteResponse> mapToVoteResponse(Question question, List<Answer> answers) { | ||
if (!question.isSelectable()) { | ||
return null; | ||
} | ||
|
||
List<CheckboxAnswer> checkboxAnswers = castAllOrThrow(answers, CheckboxAnswer.class); | ||
Map<Long, Long> optionItemIdVoteCount = checkboxAnswers.stream() | ||
.flatMap(checkboxAnswer -> checkboxAnswer.getSelectedOptionIds().stream()) | ||
.collect(Collectors.groupingBy(CheckboxAnswerSelectedOption::getSelectedOptionId, | ||
Collectors.counting())); | ||
|
||
List<OptionItem> allOptionItem = questionRepository.findAllOptionItemsByIdOrderByPosition(question.getId()); | ||
return allOptionItem.stream() | ||
.map(optionItem -> new VoteResponse( | ||
optionItem.getContent(), | ||
optionItemIdVoteCount.getOrDefault(optionItem.getId(), 0L))) | ||
.toList(); | ||
} | ||
|
||
private <T extends Answer> List<T> castAllOrThrow(List<Answer> answers, Class<T> clazz) { | ||
try { | ||
return answers.stream().map(clazz::cast).toList(); | ||
} catch (Exception ex) { | ||
throw new GatheredAnswersTypeNonUniformException(ex); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.