diff --git a/src/main/java/com/goldbalance/dive/domain/article/controller/ArticleController.java b/src/main/java/com/goldbalance/dive/domain/article/controller/ArticleController.java index 0082dd9..05becf3 100644 --- a/src/main/java/com/goldbalance/dive/domain/article/controller/ArticleController.java +++ b/src/main/java/com/goldbalance/dive/domain/article/controller/ArticleController.java @@ -4,6 +4,8 @@ import com.goldbalance.dive.domain.article.domain.Quiz; import com.goldbalance.dive.domain.article.dto.ArticleDto; import com.goldbalance.dive.domain.article.dto.request.ArticleQueryOption; +import com.goldbalance.dive.domain.article.dto.request.QuizRequest; +import com.goldbalance.dive.domain.article.dto.response.QuizResult; import com.goldbalance.dive.domain.article.service.ArticleService; import java.util.List; import lombok.RequiredArgsConstructor; @@ -33,4 +35,10 @@ public ResponseEntity getArticleContents(@PathVariable Long articleI ArticleDto response = articleService.getArticleContents(nickname, articleId); return ResponseEntity.ok(response); } + + @PostMapping("/quizzes/{articleId}") + public ResponseEntity gradeQuizzes(@PathVariable Long articleId, @RequestBody QuizRequest request) { + QuizResult response = articleService.gradeQuizzes(articleId, request); + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/com/goldbalance/dive/domain/article/domain/ArticleContent.java b/src/main/java/com/goldbalance/dive/domain/article/domain/ArticleContent.java index ad3b060..4e217b5 100644 --- a/src/main/java/com/goldbalance/dive/domain/article/domain/ArticleContent.java +++ b/src/main/java/com/goldbalance/dive/domain/article/domain/ArticleContent.java @@ -3,27 +3,6 @@ import jakarta.persistence.*; import lombok.*; -/** - *
package name : com.goldbalance.dive.domain.article.domain - *
file name : ArticleContent - *
date : 2024-07-27 - *
- * [description]
- *
- * 
- *
- * usage:
- * {@code
- *
- * } 
- *
- * modified log :
- * =======================================================
- * DATE           AUTHOR               NOTE
- * -------------------------------------------------------
- * 2024-07-27        SeungHoon              init create
- * 
- */ @Entity @Getter @RequiredArgsConstructor diff --git a/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRecordRequest.java b/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRecordRequest.java new file mode 100644 index 0000000..a594583 --- /dev/null +++ b/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRecordRequest.java @@ -0,0 +1,5 @@ +package com.goldbalance.dive.domain.article.dto.request; + +import com.goldbalance.dive.domain.article.domain.OptionType; + +public record QuizRecordRequest(Long quizId, int number, OptionType answer) {} diff --git a/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRequest.java b/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRequest.java new file mode 100644 index 0000000..82faf10 --- /dev/null +++ b/src/main/java/com/goldbalance/dive/domain/article/dto/request/QuizRequest.java @@ -0,0 +1,5 @@ +package com.goldbalance.dive.domain.article.dto.request; + +import java.util.List; + +public record QuizRequest(String nickname, int totalQuizzes, List quizzes) {} diff --git a/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizRecordResponse.java b/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizRecordResponse.java new file mode 100644 index 0000000..3b81827 --- /dev/null +++ b/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizRecordResponse.java @@ -0,0 +1,3 @@ +package com.goldbalance.dive.domain.article.dto.response; + +public record QuizRecordResponse(Long quizId, int number, String submittedAnswer, String correctAnswer) {} diff --git a/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizResult.java b/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizResult.java new file mode 100644 index 0000000..6d002bc --- /dev/null +++ b/src/main/java/com/goldbalance/dive/domain/article/dto/response/QuizResult.java @@ -0,0 +1,31 @@ +package com.goldbalance.dive.domain.article.dto.response; + +import com.goldbalance.dive.domain.member.domain.Member; +import java.util.List; + +public record QuizResult( + String nickname, + long earnedMileages, + long totalMileages, + int totalQuizzes, + int correctQuizzes, + String title, + List response) { + + public static QuizResult of( + Member member, + long earnedMileages, + int totalQuizzes, + int correctQuizzes, + String title, + List response) { + return new QuizResult( + member.getNickname(), + earnedMileages, + member.getTotalMileage(), + totalQuizzes, + correctQuizzes, + title, + response); + } +} diff --git a/src/main/java/com/goldbalance/dive/domain/article/repository/AnswerRepository.java b/src/main/java/com/goldbalance/dive/domain/article/repository/AnswerRepository.java new file mode 100644 index 0000000..1faeb16 --- /dev/null +++ b/src/main/java/com/goldbalance/dive/domain/article/repository/AnswerRepository.java @@ -0,0 +1,10 @@ +package com.goldbalance.dive.domain.article.repository; + +import com.goldbalance.dive.domain.article.domain.Answer; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AnswerRepository extends JpaRepository { + + Optional findByQuizId(Long quizId); +} diff --git a/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepository.java b/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepository.java index ccb0b83..e9c8377 100644 --- a/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepository.java +++ b/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepository.java @@ -1,8 +1,12 @@ package com.goldbalance.dive.domain.article.repository.quiz; +import com.goldbalance.dive.domain.article.domain.Answer; import com.goldbalance.dive.domain.article.domain.Quiz; +import com.goldbalance.dive.domain.article.dto.request.QuizRequest; import java.util.List; public interface QuizCustomRepository { List searchQuiz(Long articleId); + + List getAnswers(QuizRequest quizRequest); } diff --git a/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepositoryImpl.java b/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepositoryImpl.java index c1f364a..db42fc9 100644 --- a/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepositoryImpl.java +++ b/src/main/java/com/goldbalance/dive/domain/article/repository/quiz/QuizCustomRepositoryImpl.java @@ -1,10 +1,15 @@ package com.goldbalance.dive.domain.article.repository.quiz; +import static com.goldbalance.dive.domain.article.domain.QAnswer.answer; import static com.goldbalance.dive.domain.article.domain.QQuiz.quiz; +import com.goldbalance.dive.domain.article.domain.Answer; import com.goldbalance.dive.domain.article.domain.Quiz; +import com.goldbalance.dive.domain.article.dto.request.QuizRecordRequest; +import com.goldbalance.dive.domain.article.dto.request.QuizRequest; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @@ -19,4 +24,15 @@ public List searchQuiz(Long articleId) { .where(quiz.article.id.eq(articleId)) .fetch(); } + + @Override + public List getAnswers(QuizRequest quizRequest) { + List quizzes = quizRequest.quizzes(); + return quizzes.stream() + .map(quizRecord -> queryFactory + .selectFrom(answer) + .where(answer.quiz.id.eq(quizRecord.quizId())) + .fetchOne()) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/goldbalance/dive/domain/article/service/ArticleService.java b/src/main/java/com/goldbalance/dive/domain/article/service/ArticleService.java index 368164b..79b26c9 100644 --- a/src/main/java/com/goldbalance/dive/domain/article/service/ArticleService.java +++ b/src/main/java/com/goldbalance/dive/domain/article/service/ArticleService.java @@ -1,15 +1,28 @@ package com.goldbalance.dive.domain.article.service; +import static com.goldbalance.dive.domain.member.domain.MileageType.*; +import static com.goldbalance.dive.global.exception.ErrorCode.*; + +import com.goldbalance.dive.domain.article.domain.Answer; import com.goldbalance.dive.domain.article.domain.Article; import com.goldbalance.dive.domain.article.domain.ArticleContent; import com.goldbalance.dive.domain.article.domain.Quiz; import com.goldbalance.dive.domain.article.dto.ArticleDto; import com.goldbalance.dive.domain.article.dto.request.ArticleQueryOption; +import com.goldbalance.dive.domain.article.dto.request.QuizRecordRequest; +import com.goldbalance.dive.domain.article.dto.request.QuizRequest; +import com.goldbalance.dive.domain.article.dto.response.QuizRecordResponse; +import com.goldbalance.dive.domain.article.dto.response.QuizResult; +import com.goldbalance.dive.domain.article.repository.AnswerRepository; import com.goldbalance.dive.domain.article.repository.ArticleContentRepository; import com.goldbalance.dive.domain.article.repository.article.ArticleRepository; import com.goldbalance.dive.domain.article.repository.quiz.QuizRepository; +import com.goldbalance.dive.domain.member.domain.Member; +import com.goldbalance.dive.domain.member.domain.Mileage; +import com.goldbalance.dive.domain.member.repository.MemberRepository; +import com.goldbalance.dive.domain.member.repository.MileageRepository; import com.goldbalance.dive.global.exception.CustomException; -import com.goldbalance.dive.global.exception.ErrorCode; +import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -23,6 +36,9 @@ public class ArticleService { private final ArticleRepository articleRepository; private final ArticleContentRepository articleContentRepository; private final QuizRepository quizRepository; + private final AnswerRepository answerRepository; + private final MemberRepository memberRepository; + private final MileageRepository mileageRepository; public List
findArticles(ArticleQueryOption queryOption) { return articleRepository.searchArticle(queryOption); @@ -35,8 +51,47 @@ public List findQuizzes(Long articleId) { public ArticleDto getArticleContents(String nickname, Long articleId) { List articleContents = articleContentRepository.findAllByArticleId(articleId); if (articleContents.isEmpty()) { - throw new CustomException(ErrorCode.ARTICLE_NOT_FOUND); + throw new CustomException(ARTICLE_NOT_FOUND); } return ArticleDto.of(nickname, articleContents); } + + public QuizResult gradeQuizzes(Long articleId, QuizRequest quizRequest) { + Article article = + articleRepository.findById(articleId).orElseThrow(() -> new CustomException(ARTICLE_NOT_FOUND)); + Member member = memberRepository + .findByNickname(quizRequest.nickname()) + .orElseThrow(() -> new CustomException(MEMBER_NOT_FOUND)); + + List quizzes = quizRequest.quizzes(); + long earnedMileages = 0; + int correctQuizzes = 0; + + List quizRecordResponses = new ArrayList<>(); + for (QuizRecordRequest q : quizzes) { + Answer answer = + answerRepository.findByQuizId(q.quizId()).orElseThrow(() -> new CustomException(ANSWER_NOT_FOUND)); + if (q.answer().equals(answer.getOptionType())) { + earnedMileages += QUIZ_CORRECT.getMileage(); + correctQuizzes += 1; + } + quizRecordResponses.add(new QuizRecordResponse( + q.quizId(), + q.number(), + q.answer().getNumber(), + answer.getOptionType().getNumber())); + } + + member.addMileages(earnedMileages); + Mileage mileage = Mileage.create(member, earnedMileages, QUIZ_CORRECT); + mileageRepository.save(mileage); + + return QuizResult.of( + member, + earnedMileages, + quizRecordResponses.size(), + correctQuizzes, + article.getTitle(), + quizRecordResponses); + } } diff --git a/src/main/java/com/goldbalance/dive/domain/member/domain/Member.java b/src/main/java/com/goldbalance/dive/domain/member/domain/Member.java index 19b17bd..1857fa3 100644 --- a/src/main/java/com/goldbalance/dive/domain/member/domain/Member.java +++ b/src/main/java/com/goldbalance/dive/domain/member/domain/Member.java @@ -48,4 +48,9 @@ public static Member create(String nickname) { .monthlyMileage(0) .build(); } + + public void addMileages(long amount) { + totalMileage += amount; + monthlyMileage += amount; + } } diff --git a/src/main/java/com/goldbalance/dive/global/exception/ErrorCode.java b/src/main/java/com/goldbalance/dive/global/exception/ErrorCode.java index b8ea028..e009d90 100644 --- a/src/main/java/com/goldbalance/dive/global/exception/ErrorCode.java +++ b/src/main/java/com/goldbalance/dive/global/exception/ErrorCode.java @@ -14,7 +14,8 @@ public enum ErrorCode { MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 멤버입니다."), // Article - ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 글입니다."); + ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 글입니다."), + ANSWER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 답안입니다."); private final HttpStatus status; private final String message;