Skip to content

Commit

Permalink
feature: 퀴즈 정답 제출 API 구현 (#47)
Browse files Browse the repository at this point in the history
* feature: 퀴즈 정답 제출 구현

* refactor: 퀴즈 정답 제출 api 수정

---------

Co-authored-by: sleepyhoon <[email protected]>
  • Loading branch information
Sangwook02 and sleepyhoon authored Jul 27, 2024
1 parent 0922875 commit dca0cd4
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -33,4 +35,10 @@ public ResponseEntity<ArticleDto> getArticleContents(@PathVariable Long articleI
ArticleDto response = articleService.getArticleContents(nickname, articleId);
return ResponseEntity.ok(response);
}

@PostMapping("/quizzes/{articleId}")
public ResponseEntity<QuizResult> gradeQuizzes(@PathVariable Long articleId, @RequestBody QuizRequest request) {
QuizResult response = articleService.gradeQuizzes(articleId, request);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,6 @@
import jakarta.persistence.*;
import lombok.*;

/**
* <br>package name : com.goldbalance.dive.domain.article.domain
* <br>file name : ArticleContent
* <br>date : 2024-07-27
* <pre>
* <span style="color: white;">[description]</span>
*
* </pre>
* <pre>
* <span style="color: white;">usage:</span>
* {@code
*
* } </pre>
* <pre>
* modified log :
* =======================================================
* DATE AUTHOR NOTE
* -------------------------------------------------------
* 2024-07-27 SeungHoon init create
* </pre>
*/
@Entity
@Getter
@RequiredArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.goldbalance.dive.domain.article.dto.request;

import java.util.List;

public record QuizRequest(String nickname, int totalQuizzes, List<QuizRecordRequest> quizzes) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.goldbalance.dive.domain.article.dto.response;

public record QuizRecordResponse(Long quizId, int number, String submittedAnswer, String correctAnswer) {}
Original file line number Diff line number Diff line change
@@ -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<QuizRecordResponse> response) {

public static QuizResult of(
Member member,
long earnedMileages,
int totalQuizzes,
int correctQuizzes,
String title,
List<QuizRecordResponse> response) {
return new QuizResult(
member.getNickname(),
earnedMileages,
member.getTotalMileage(),
totalQuizzes,
correctQuizzes,
title,
response);
}
}
Original file line number Diff line number Diff line change
@@ -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<Answer, Long> {

Optional<Answer> findByQuizId(Long quizId);
}
Original file line number Diff line number Diff line change
@@ -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<Quiz> searchQuiz(Long articleId);

List<Answer> getAnswers(QuizRequest quizRequest);
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,4 +24,15 @@ public List<Quiz> searchQuiz(Long articleId) {
.where(quiz.article.id.eq(articleId))
.fetch();
}

@Override
public List<Answer> getAnswers(QuizRequest quizRequest) {
List<QuizRecordRequest> quizzes = quizRequest.quizzes();
return quizzes.stream()
.map(quizRecord -> queryFactory
.selectFrom(answer)
.where(answer.quiz.id.eq(quizRecord.quizId()))
.fetchOne())
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Article> findArticles(ArticleQueryOption queryOption) {
return articleRepository.searchArticle(queryOption);
Expand All @@ -35,8 +51,47 @@ public List<Quiz> findQuizzes(Long articleId) {
public ArticleDto getArticleContents(String nickname, Long articleId) {
List<ArticleContent> 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<QuizRecordRequest> quizzes = quizRequest.quizzes();
long earnedMileages = 0;
int correctQuizzes = 0;

List<QuizRecordResponse> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ public static Member create(String nickname) {
.monthlyMileage(0)
.build();
}

public void addMileages(long amount) {
totalMileage += amount;
monthlyMileage += amount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit dca0cd4

Please sign in to comment.