Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Feature - Quiz 생성하기 API 구현 #45

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 71 additions & 2 deletions http/roadmap/RoadmapControllerHttpRequest.http
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Authorization: Bearer {{access_token}}

### 퀴즈 리스트 조회하기
//@no-log
GET {{host_url}}/v1/subtopics/1/check-points/quizzes/choices/summaries
GET {{host_url}}/v1/subtopics/11/check-points/quizzes/choices/summaries
Authorization: Bearer {{access_token}}


Expand All @@ -50,7 +50,7 @@ Authorization: Bearer {{access_token}}
Content-Disposition: form-data; name="file"; filename="pdf1.pdf"
Content-Type: application/pdf

< /Users/jjuuuunnii/Desktop/Lecture4_AI.pdf
< /Users/jjuuuunnii/Developments/on_road/dummy_data/10.pdf

--boundary

Expand Down Expand Up @@ -78,7 +78,76 @@ Content-Type: application/json
]
}


### 퀴즈 생성하기
//@no-log
POST {{host_url}}/v1/quizzes
Authorization: Bearer {{access_token}}
Content-Type: application/json

{
"quiz_list": [
{
"id": 1,
"content": "다음 중 REST API의 특징이 아닌 것은 무엇인가?",
"choice_list": [
{
"content": "무상태성",
"is_answer": false
},
{
"content": "클라이언트-서버 구조",
"is_answer": false
},
{
"content": "상태 저장성",
"is_answer": true
}
]
},
{
"id": 2,
"content": "Java의 메모리 영역 중 힙(heap) 영역에 저장되지 않는 것은?",
"choice_list": [
{
"content": "객체 인스턴스",
"is_answer": false
},
{
"content": "정적(static) 변수",
"is_answer": true
},
{
"content": "배열",
"is_answer": false
}
]
},
{
"id": 3,
"content": "HTTP 메서드 중 데이터를 생성하기 위한 메서드는?",
"choice_list": [
{
"content": "GET",
"is_answer": false
},
{
"content": "POST",
"is_answer": true
},
{
"content": "DELETE",
"is_answer": false
}
]
}
]
}


### 최근 추가된 로드맵 조회하기
//@no-log
GET {{host_url}}/v1/roadmaps/created-at
Authorization: Bearer {{access_token}}


Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import lombok.RequiredArgsConstructor;
import org.dongguk.onroad.core.annotation.security.UserID;
import org.dongguk.onroad.core.dto.ResponseDto;
import org.dongguk.onroad.roadmap.application.dto.request.CreateQuizRequestDto;
import org.dongguk.onroad.roadmap.application.dto.request.CreateUserChoiceRequestDto;
import org.dongguk.onroad.roadmap.application.usecase.CreateQuizUseCase;
import org.dongguk.onroad.roadmap.application.usecase.CreateUserChoiceUseCase;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -26,6 +28,7 @@ public class RoadmapCommandV1Controller {
private final CreateLectureUseCase createLectureUseCase;
private final CreateRoadmapUseCase createRoadmapUseCase;
private final CreateUserChoiceUseCase createUserChoiceUseCase;
private final CreateQuizUseCase createQuizUseCase;

@PostMapping("/lectures")
public ResponseDto<?> createLecture(
Expand Down Expand Up @@ -63,4 +66,17 @@ public ResponseDto<Void> createUserChoice(
createUserChoiceUseCase.execute(userId, requestDto);
return ResponseDto.created(null);
}

@PostMapping("/quizzes")
public ResponseDto<Void> createQuiz(
@UserID UUID userId,
@RequestBody @Valid CreateQuizRequestDto requestDto
) {
createQuizUseCase.execute(
userId,
requestDto
);
return ResponseDto.created(null);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.dongguk.onroad.roadmap.application.dto.request;

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.util.List;

public record CreateQuizRequestDto(

@NotNull(message = "퀴즈 목록은 필수 입력 값입니다.")
@JsonProperty("quiz_list")
List<Quiz> quizList

) {
public record Quiz(

@NotNull(message = "check Point id는 필수 입력 값입니다.")
@JsonProperty("id")
Long id,

@NotNull(message = "퀴즈 내용은 필수 입력 값입니다.")
@JsonProperty("content")
String content,

@NotNull(message = "선택지 목록은 필수 입력 값입니다.")
@Size(min = 3, max = 3, message = "선택지는 반드시 3개여야 합니다.")
@JsonProperty("choice_list")
List<Choice> choiceList

) {}

public record Choice(

@NotNull(message = "선택지 내용은 필수 입력 값입니다.")
@JsonProperty("content")
String content,

@NotNull(message = "정답 여부는 필수 입력 값입니다.")
@JsonProperty("is_answer")
Boolean isAnswer

) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.dongguk.onroad.roadmap.application.service;

import lombok.RequiredArgsConstructor;
import org.dongguk.onroad.core.exception.error.ErrorCode;
import org.dongguk.onroad.core.exception.type.CommonException;
import org.dongguk.onroad.roadmap.application.dto.request.CreateQuizRequestDto;
import org.dongguk.onroad.roadmap.application.usecase.CreateQuizUseCase;
import org.dongguk.onroad.roadmap.domain.CheckPoint;
import org.dongguk.onroad.roadmap.domain.Choice;
import org.dongguk.onroad.roadmap.domain.Quiz;
import org.dongguk.onroad.roadmap.domain.service.ChoiceService;
import org.dongguk.onroad.roadmap.domain.service.QuizService;
import org.dongguk.onroad.roadmap.domain.type.EQuizType;
import org.dongguk.onroad.roadmap.repository.CheckPointRepository;
import org.dongguk.onroad.roadmap.repository.QuizRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
public class CreateQuizService implements CreateQuizUseCase {

private final CheckPointRepository checkPointRepository;

private final QuizService quizService;
private final ChoiceService choiceService;
private final QuizRepository quizRepository;

@Override
@Transactional
public void execute(UUID userId, CreateQuizRequestDto requestDto) {

List<Quiz> quizList = requestDto.quizList().stream()
.map(quizRequestDto -> {
CheckPoint checkPoint = checkPointRepository.findById(quizRequestDto.id())
.orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE));

Quiz quiz = quizService.createQuiz(
EQuizType.MULTIPLE_CHOICE,
quizRequestDto.content(),
checkPoint
);

quizRequestDto.choiceList().forEach(
choiceRequestDto -> choiceService.createChoice(
choiceRequestDto.content(),
choiceRequestDto.isAnswer(),
quiz
));

return quiz;
}).toList();

quizRepository.saveAll(quizList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.dongguk.onroad.roadmap.application.usecase;

import org.dongguk.onroad.core.annotation.bean.UseCase;
import org.dongguk.onroad.roadmap.application.dto.request.CreateQuizRequestDto;

import java.util.UUID;

@UseCase
public interface CreateQuizUseCase {

void execute(
UUID userId,
CreateQuizRequestDto requestDto
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,9 @@ public CheckPoint(String content, Subtopic subtopic) {
this.subtopic = subtopic;
this.createdAt = LocalDateTime.now();
}

public void updateQuiz(Quiz quiz) {
this.quiz = quiz;
}
}

9 changes: 9 additions & 0 deletions src/main/java/org/dongguk/onroad/roadmap/domain/Quiz.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import lombok.NoArgsConstructor;
import org.dongguk.onroad.roadmap.domain.type.EQuizType;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "quizzes")
@Getter
Expand All @@ -30,6 +33,12 @@ public class Quiz {
@Column(name = "content" ,length = 500, nullable = false)
private String content;

/* -------------------------------------------- */
/* One To Many Mapping ------------------------ */
/* -------------------------------------------- */
@OneToMany(mappedBy = "quiz", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Choice> choices = new ArrayList<>();

/* -------------------------------------------- */
/* One To One Mapping ------------------------- */
/* -------------------------------------------- */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.dongguk.onroad.roadmap.domain.service;

import org.dongguk.onroad.roadmap.domain.Choice;
import org.dongguk.onroad.roadmap.domain.Quiz;
import org.springframework.stereotype.Service;

@Service
public class ChoiceService {

public Choice createChoice(String content, boolean isAnswer, Quiz quiz) {

Choice choice = Choice.builder()
.content(content)
.isAnswer(isAnswer)
.quiz(quiz)
.build();

quiz.getChoices().add(choice);

return choice;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.dongguk.onroad.roadmap.domain.service;

import org.dongguk.onroad.roadmap.domain.CheckPoint;
import org.dongguk.onroad.roadmap.domain.Quiz;
import org.dongguk.onroad.roadmap.domain.type.EQuizType;
import org.springframework.stereotype.Service;

@Service
public class QuizService {

public Quiz createQuiz(EQuizType quizType, String content, CheckPoint checkPoint) {
Quiz quiz = Quiz.builder()
.type(quizType)
.content(content)
.checkPoint(checkPoint)
.build();

checkPoint.updateQuiz(quiz);

return quiz;
}
}
Loading