Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

import com._1.spring_rest_api.api.dto.QuestionDto;
import com._1.spring_rest_api.entity.Question;
import com._1.spring_rest_api.entity.Week;
import com._1.spring_rest_api.repository.WeekRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* AI 생성 질문 DTO와 Question 엔티티 간의 변환을 담당하는 컨버터
*/
Expand Down Expand Up @@ -39,13 +45,16 @@ public Question toEntity(QuestionDto dto) {
.build();
}

/**
* AI가 생성한 질문 DTO를 특정 주차의 Question 엔티티로 변환
*
* @param dto 질문 DTO
* @param weekId 주차 ID
* @return 주차에 연결된 Question 엔티티
*/
public List<Question> createQuestionsForWeek(List<QuestionDto> dtos, Long weekId) {
if (dtos == null || dtos.isEmpty()) {
return new ArrayList<>();
}

return dtos.stream()
.map(dto -> createQuestionForWeek(dto, weekId))
.collect(Collectors.toList());
}

public Question createQuestionForWeek(QuestionDto dto, Long weekId) {
if (dto == null) {
return null;
Expand All @@ -54,9 +63,14 @@ public Question createQuestionForWeek(QuestionDto dto, Long weekId) {
Question question = toEntity(dto);

if (weekId != null) {
weekRepository.findById(weekId).ifPresent(question::changeWeek);
Week week = weekRepository.findById(weekId)
.orElseThrow(() -> new EntityNotFoundException("Week not found with id: " + weekId));

week.addQuestion(question);
}

return question;
}


}
8 changes: 0 additions & 8 deletions src/main/java/com/_1/spring_rest_api/entity/Course.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,6 @@ public void changeCreator(User creator) {
}
}


public Course(User creator, String title, String description) {
this.creator = creator;
this.title = title;
this.description = description;
this.weeks = new ArrayList<>();
}

public Course(Long id, User creator, String title, String description) {
this.id = id;
this.creator = creator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void addQuestion(Question question) {
}

// 정적 팩토리 메서드를 통해 매핑 생성 및 양방향 연관관계 설정
QuizQuestionMapping mapping = QuizQuestionMapping.create(this, question);
QuizQuestionMapping.create(this, question);

// 질문 수 증가
this.updateTotalQuestions(this.totalQuestions + 1);
Expand Down
73 changes: 39 additions & 34 deletions src/main/java/com/_1/spring_rest_api/entity/QuizSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ public class QuizSession extends BaseTimeEntity {

private LocalDateTime completedAt;

// User와 QuizSession 간의 양방향 연관관계 메서드
public void changUser(User user) {
this.user = user;
if (user != null && !user.getQuizSessions().contains(this)) {
user.getQuizSessions().add(this);
}
}

// CustomQuiz와 QuizSession 간의 양방향 연관관계 메서드
public void changeQuiz(CustomQuiz quiz) {
this.quiz = quiz;
if (quiz != null && !quiz.getQuizSessions().contains(this)) {
quiz.getQuizSessions().add(this);
}
}

public static QuizSession create(User user, CustomQuiz quiz) {
if (user == null) {
throw new IllegalArgumentException("사용자는 null이 될 수 없습니다");
Expand All @@ -53,6 +69,29 @@ public static QuizSession create(User user, CustomQuiz quiz) {
.build();
}

public UserAnswer createAnswer(String userAnswerText) {
Question currentQuestion = getCurrentQuestion();
if (currentQuestion == null) {
throw new IllegalStateException("세션에 현재 질문이 없습니다");
}

boolean isCorrect = currentQuestion.isCorrectAnswer(userAnswerText);

UserAnswer userAnswer = UserAnswer.builder()
.user(this.user)
.question(currentQuestion)
.userAnswer(userAnswerText)
.isCorrect(isCorrect)
.attemptCount(1)
.answeredAt(LocalDateTime.now())
.build();

currentQuestion.addUserAnswer(userAnswer);
this.user.addUserAnswer(userAnswer);

return userAnswer;
}

public void moveToNextQuestion() {
this.currentQuestionIndex++;
}
Expand Down Expand Up @@ -86,38 +125,4 @@ public Question getNextQuestion() {
public boolean isComplete() {
return this.currentQuestionIndex >= this.quiz.getQuizQuestionMappings().size();
}

public UserAnswer createAnswer(String userAnswerText) {
Question currentQuestion = getCurrentQuestion();
if (currentQuestion == null) {
throw new IllegalStateException("세션에 현재 질문이 없습니다");
}

boolean isCorrect = currentQuestion.isCorrectAnswer(userAnswerText);

return UserAnswer.builder()
.user(this.user)
.question(currentQuestion)
.userAnswer(userAnswerText)
.isCorrect(isCorrect)
.attemptCount(1)
.answeredAt(LocalDateTime.now())
.build();
}

// User와 QuizSession 간의 양방향 연관관계 메서드
public void changeUser(User user) {
this.user = user;
if (user != null && !user.getQuizSessions().contains(this)) {
user.getQuizSessions().add(this);
}
}

// CustomQuiz와 QuizSession 간의 양방향 연관관계 메서드
public void changeQuiz(CustomQuiz quiz) {
this.quiz = quiz;
if (quiz != null && !quiz.getQuizSessions().contains(this)) {
quiz.getQuizSessions().add(this);
}
}
}
12 changes: 4 additions & 8 deletions src/main/java/com/_1/spring_rest_api/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ public class User extends BaseTimeEntity {
private List<UserAnswer> userAnswers = new ArrayList<>();

// User와 UserKakao 간의 양방향 연관관계 메서드
public void linkWithKakao(UserKakao userKakao) {
public void changeUserKakao(UserKakao userKakao) {
this.userKakao = userKakao;
// userKakao의 user 필드가 this가 아닌 경우에만 설정
if (userKakao.getUser() != this) {
userKakao.linkWithUser(this);
userKakao.changeUser(this);
}
}

Expand Down Expand Up @@ -87,14 +87,14 @@ public void removeCourse(Course course) {
public void addQuizSession(QuizSession session) {
this.quizSessions.add(session);
if (session.getUser() != this) {
session.changeUser(this);
session.changUser(this);
}
}

public void removeQuizSession(QuizSession session) {
this.quizSessions.remove(session);
if (session.getUser() == this) {
session.changeUser(null);
session.changUser(null);
}
}

Expand All @@ -121,10 +121,6 @@ public void updateName(String name) {
this.name = name;
}

public void updateUserKakao(UserKakao userKakao) {
this.userKakao = userKakao;
}

public static User createKakaoUser(String email, String name) {
if (email == null || email.isEmpty()) {
throw new IllegalArgumentException("이메일은 필수 값입니다.");
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/com/_1/spring_rest_api/entity/UserKakao.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public class UserKakao extends BaseTimeEntity {
private LocalDateTime tokenExpiresAt;

// User와 UserKakao 간의 양방향 연관관계 메서드
public void linkWithUser(User user) {
public void changeUser(User user) {
this.user = user;
// user의 userKakao 필드가 this가 아닌 경우에만 설정
if (user.getUserKakao() != this) {
user.linkWithKakao(this);
user.changeUserKakao(this);
}
}

Expand All @@ -65,12 +65,11 @@ public static UserKakao createKakaoAccountLink(User user, String kakaoId) {
}

UserKakao userKakao = UserKakao.builder()
.user(user)
.kakaoAccountId(kakaoId)
.build();

// 양방향 연관관계 설정
user.updateUserKakao(userKakao);
userKakao.changeUser(user);

return userKakao;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,26 @@
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;


public interface CustomQuizRepository extends JpaRepository<CustomQuiz, Long> {

@Query("SELECT q FROM CustomQuiz q WHERE q.creator.id = :creatorId ORDER BY q.createAt DESC")
List<CustomQuiz> findAllByCreatorId(@Param("creatorId") Long creatorId);

@Query("SELECT DISTINCT q FROM CustomQuiz q " +
"LEFT JOIN FETCH q.creator " +
"LEFT JOIN FETCH q.quizQuestionMappings qm " +
"LEFT JOIN FETCH qm.question " +
"WHERE q.id = :quizId")
Optional<CustomQuiz> findByIdWithQuestions(@Param("quizId") Long quizId);

@Query("SELECT DISTINCT q FROM CustomQuiz q " +
"LEFT JOIN FETCH q.quizWeekMappings wm " +
"LEFT JOIN FETCH wm.week w " +
"LEFT JOIN FETCH w.course " +
"WHERE q.id = :quizId")
Optional<CustomQuiz> findByIdWithWeeks(@Param("quizId") Long quizId);

}
19 changes: 15 additions & 4 deletions src/main/java/com/_1/spring_rest_api/service/CourseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com._1.spring_rest_api.entity.User;
import com._1.spring_rest_api.entity.Week;
import com._1.spring_rest_api.repository.CourseRepository;
import com._1.spring_rest_api.repository.UserRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -17,11 +18,21 @@
public class CourseService {

private final CourseRepository courseRepository;
private final UserRepository userRepository;

public Long createCourse(
Long userId, String title, String description) {
// User entity 조회 후 넣어야 함. - 임시로 User() 사용
Course course = courseRepository.save(new Course(new User(userId), title, description));
public Long createCourse(Long userId, String title, String description) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException("User not found with id: " + userId));

Course course = Course.builder()
.creator(user)
.title(title)
.description(description)
.build();

user.addCourse(course);

Course savedCourse = courseRepository.save(course);
return course.getId();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,13 @@ public List<Long> generateAndSaveQuestions(Long weekId, int minQuestionCount) {
List<QuestionDto> generatedQuestions =
claudeService.generateQuestionsFromWeekTexts(weekId, minQuestionCount);

// 생성된 질문을 저장 (컨버터 활용)
List<Long> savedQuestionIds = generatedQuestions.stream()
.map(dto -> questionGenerationConverter.createQuestionForWeek(dto, weekId))
List<Question> questions = questionGenerationConverter.createQuestionsForWeek(
generatedQuestions, weekId);

return questions.stream()
.map(questionRepository::save)
.map(Question::getId)
.collect(Collectors.toList());

return savedQuestionIds;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,11 @@ public Long startQuizSession(Long quizId, Long userId) {
.orElseThrow(() -> new EntityNotFoundException("User not found with id: " + userId));

// 새 퀴즈 세션 생성
QuizSession session = QuizSession.builder()
.user(user)
.quiz(quiz)
.currentQuestionIndex(0) // 첫 번째 질문부터 시작
.build();
QuizSession session = QuizSession.create(user, quiz);

// 양방향 연관관계 설정
session.changeUser(user);
session.changeQuiz(quiz);
user.addQuizSession(session);
quiz.addQuizSession(session);

// 저장 및 ID 반환
QuizSession savedSession = quizSessionRepository.save(session);
Expand All @@ -97,10 +93,7 @@ private void connectWeeksToQuiz(List<Long> weekIds, CustomQuiz quiz) {
.build();

// 양방향 연관관계 설정
mapping.changeQuiz(quiz);
mapping.changeWeek(week);

quizWeekMappingRepository.save(mapping);
quiz.addQuizWeekMapping(mapping);
}
}

Expand All @@ -124,8 +117,6 @@ private void processQuestions(CreateQuizRequest request, CustomQuiz quiz) {
quiz.addQuestion(question);
}

// 총 질문 수 업데이트 및 저장
quiz.updateTotalQuestions(questions.size());
customQuizRepository.save(quiz);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ public List<QuizSummaryResponse> getQuizzesByUserId(Long userId) {

@Override
public QuizDetailResponse getQuizDetail(Long quizId) {
CustomQuiz quiz = customQuizRepository.findById(quizId)
CustomQuiz quiz = customQuizRepository.findByIdWithQuestions(quizId)
.orElseThrow(() -> new EntityNotFoundException("Quiz not found with id: " + quizId));

customQuizRepository.findByIdWithWeeks(quizId);

return convertToDetailResponse(quiz);
}

Expand Down
Loading