From dd9be634ca5540ee4ea308765a0758c058fb8838 Mon Sep 17 00:00:00 2001 From: haeun Date: Sun, 19 Jan 2025 01:38:32 +0900 Subject: [PATCH 1/4] fixed untracked files --- gradlew | 0 .../quiz/controller/QuizController.java | 2 +- .../team_24/domain/quiz/domain/Quiz.java | 4 + .../quiz/repository/QuizRepository.java | 21 +++- .../domain/quiz/service/QuizService.java | 54 +++++---- .../user/controller/UserController.java | 104 ++++++++-------- .../domain/user/dto/UserLoginReqDto.java | 14 +-- .../domain/user/dto/UserRequestDto.java | 20 +-- .../domain/user/dto/UserResponseDto.java | 52 ++++---- .../domain/user/service/UserService.java | 114 +++++++++--------- src/main/resources/application.yml | 19 --- 11 files changed, 208 insertions(+), 196 deletions(-) mode change 100755 => 100644 gradlew delete mode 100644 src/main/resources/application.yml diff --git a/gradlew b/gradlew old mode 100755 new mode 100644 diff --git a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java index a2fa08a..f35dddb 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java @@ -54,7 +54,7 @@ public ApiResponse noAnswerQuiz (@PathVariable Long userId){ return ApiResponse.onSuccess(quizService.noAnswerQuiz(userId)); } - @Operation(summary = "안푼 퀴즈 조회 API", description = "지금까지 안푼 퀴즈를 페이지네이션으로 조회합니다.") + @Operation(summary = "안 푼 퀴즈 조회 API", description = "다시 풀 수 있는 퀴즈만 반환합니다.") @GetMapping("/{userId}/noanswerlist") public ApiResponse> listNoQuiz( @PathVariable Long userId, diff --git a/src/main/java/GDGoC/team_24/domain/quiz/domain/Quiz.java b/src/main/java/GDGoC/team_24/domain/quiz/domain/Quiz.java index 4a3f914..ec0e8f5 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/domain/Quiz.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/domain/Quiz.java @@ -7,6 +7,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.time.LocalDateTime; + @Entity @Getter @Setter @@ -27,6 +29,8 @@ public class Quiz extends BaseEntity { private Long quizAnswer; //퀴즈 답변 + private LocalDateTime nextRetryTime; + @ManyToOne(fetch = FetchType.LAZY) private User user; diff --git a/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java b/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java index e4034b6..118a5e0 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java @@ -5,8 +5,11 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; import java.util.Optional; import java.util.List; @@ -14,5 +17,21 @@ public interface QuizRepository extends JpaRepository { Page findByUserAndIsCompleted(User user, Boolean isCompleted, Pageable pageable); List findByUser (User user); - boolean existsByUserAndIsCompleted(User user, Boolean isCompleted); + @Query("SELECT q FROM Quiz q " + + "WHERE q.user = :user AND q.isCompleted = true") + Page findSolvedQuizzes(@Param("user") User user, Pageable pageable); + @Query("SELECT q FROM Quiz q " + + "WHERE q.user = :user " + + "AND q.isCompleted = false " + + "AND (q.nextRetryTime IS NULL OR q.nextRetryTime <= CURRENT_TIMESTAMP)") + Page findUnsolvedQuizzes(@Param("user") User user, Pageable pageable); + @Query("SELECT CASE WHEN COUNT(q) > 0 THEN TRUE ELSE FALSE END " + + "FROM Quiz q WHERE q.user = :user AND q.isCompleted = :isCompleted " + + "AND (q.nextRetryTime IS NULL OR q.nextRetryTime <= CURRENT_TIMESTAMP)") + boolean existsByUserAndIsCompletedAndNextRetryTimeBefore( + @Param("user") User user, + @Param("isCompleted") Boolean isCompleted); + + + } diff --git a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java index 63306f7..3547192 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java @@ -17,6 +17,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -30,20 +31,17 @@ public class QuizService { private final UserRepository userRepository; public Quiz makeQuiz(QuizRequestDto.createQuiz request, Long familyId) { - // 퀴즈 생성 + Family family = familyRepository.findById(familyId) + .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); + + User user = family.getUser(); // 중복 조회 제거 + Quiz newQuiz = new Quiz(); newQuiz.setQuestion(request.getQuestion()); newQuiz.setAnswer(request.getAnswer()); newQuiz.setCompleted(false); + newQuiz.setUser(user); // User 설정 - // Family 및 User 조회 - Family family = familyRepository.findById(familyId) - .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - User user = userRepository.findById(family.getUser().getId()) - .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - newQuiz.setUser(user); - - // 퀴즈 저장 Quiz savedQuiz = quizRepository.save(newQuiz); // 선택지 저장 @@ -60,39 +58,48 @@ public Quiz makeQuiz(QuizRequestDto.createQuiz request, Long familyId) { return savedQuiz; } + public Boolean answerQuiz(QuizRequestDto.answerQuiz request) { Quiz quiz = quizRepository.findById(request.getQuizId()) .orElseThrow(() -> new GeneralException(ErrorStatus.QUIZ_NOT_FOUND)); - // 정답 비교 + // 객관식 정답 비교 boolean isCorrect = quiz.getAnswer().equals(request.getAnswer()); quiz.setCorrect(isCorrect); - quiz.setCompleted(true); // 퀴즈 완료 상태로 변경 - quiz.setQuizAnswer(request.getAnswer()); // 사용자 답변 저장 - quizRepository.save(quiz); + quiz.setCompleted(true); // 퀴즈 완료 처리 + quiz.setQuizAnswer(request.getAnswer()); // 사용자 입력 저장 + + if (!isCorrect) { + // 틀린 경우: 하루 뒤에 다시 풀 수 있도록 설정 + quiz.setNextRetryTime(LocalDateTime.now().plusDays(1)); + } else { + // 맞은 경우: 7일 뒤에 다시 풀 수 있도록 설정 + quiz.setNextRetryTime(LocalDateTime.now().plusDays(7)); + } + quizRepository.save(quiz); return isCorrect; } + public Page readAllQuizzes(Long userId, Boolean solve, Pageable pageable) { - // User 조회 User user = userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - // User가 푼/안 푼 퀴즈를 페이지네이션으로 조회 - Page quizzes = quizRepository.findByUserAndIsCompleted(user, solve, pageable); + // solve 값에 따라 풀었던 퀴즈/풀지 않은 퀴즈 조회 + Page quizzes = solve + ? quizRepository.findSolvedQuizzes(user, pageable) // 풀었던 퀴즈 조회 + : quizRepository.findUnsolvedQuizzes(user, pageable); // 풀지 않은 퀴즈 조회 (nextRetryTime 조건 포함) if (quizzes.isEmpty()) { throw new GeneralException(ErrorStatus.QUIZ_NOT_FOUND); } - // 각 퀴즈와 해당 선택지 정보를 DTO로 변환 + // DTO 변환 return quizzes.map(quiz -> { - // 선택지 조회 List options = quizOptionRepository.findByQuiz(quiz); - // 선택지를 DTO로 변환 List optionDtos = options.stream() .map(option -> QuizResponseDto.QuizOptionDto.builder() .number(option.getNumber()) @@ -100,7 +107,6 @@ public Page readAllQuizzes(Long userId, Boolean solve, .build()) .toList(); - // 퀴즈와 선택지 정보를 DTO로 변환 return QuizResponseDto.quizList.builder() .id(quiz.getId()) .question(quiz.getQuestion()) @@ -113,13 +119,15 @@ public Page readAllQuizzes(Long userId, Boolean solve, } + + public Boolean noAnswerQuiz(Long userId) { - // User 조회 User user = userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - // 안 푼 퀴즈 존재 여부 확인 - return quizRepository.existsByUserAndIsCompleted(user, false); + // 다음 풀 수 있는 퀴즈 존재 여부 확인 + return quizRepository.existsByUserAndIsCompletedAndNextRetryTimeBefore(user, false); } + } diff --git a/src/main/java/GDGoC/team_24/domain/user/controller/UserController.java b/src/main/java/GDGoC/team_24/domain/user/controller/UserController.java index c9ba7cf..3425477 100644 --- a/src/main/java/GDGoC/team_24/domain/user/controller/UserController.java +++ b/src/main/java/GDGoC/team_24/domain/user/controller/UserController.java @@ -1,52 +1,52 @@ -package GDGoC.team_24.domain.user.controller; - -import GDGoC.team_24.global.ApiResponse; -import GDGoC.team_24.domain.user.dto.UserLoginReqDto; -import GDGoC.team_24.domain.user.dto.UserRequestDto; -import GDGoC.team_24.domain.user.dto.UserResponseDto; -import GDGoC.team_24.domain.user.service.UserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/user") -@Tag(name="user", description = "유저 관리하는 api입니다.") - -public class UserController { - - private final UserService userService; - - - @PostMapping - @Operation(summary = "유저 회원가입 API", description = "유저 계정을 생성하는 API입니다.") - public ApiResponse userSignUp(@RequestBody UserRequestDto userRequestDto) { - - return ApiResponse.onSuccess(userService.userSignUp(userRequestDto)); - - } - - @GetMapping - @Operation(summary = "유저 로그인 API", description = "로그인 생성하는 API입니다.") - public ApiResponse userLogin(@RequestBody UserLoginReqDto userLoginReqDto) { - - return ApiResponse.onSuccess(userService.userLogin(userLoginReqDto)); - - } - - @GetMapping("/{userId}") - @Operation(summary = "내 정보 조회 API", description = "정보 조회하는 생성하는 API입니다.") - public ApiResponse userGet(@PathVariable("userId") Long userId) { - - return ApiResponse.onSuccess(userService.userGet(userId)); - - } - - - - - - -} +package GDGoC.team_24.domain.user.controller; + +import GDGoC.team_24.global.ApiResponse; +import GDGoC.team_24.domain.user.dto.UserLoginReqDto; +import GDGoC.team_24.domain.user.dto.UserRequestDto; +import GDGoC.team_24.domain.user.dto.UserResponseDto; +import GDGoC.team_24.domain.user.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/user") +@Tag(name="user", description = "유저 관리하는 api입니다.") + +public class UserController { + + private final UserService userService; + + + @PostMapping + @Operation(summary = "유저 회원가입 API", description = "유저 계정을 생성하는 API입니다.") + public ApiResponse userSignUp(@RequestBody UserRequestDto userRequestDto) { + + return ApiResponse.onSuccess(userService.userSignUp(userRequestDto)); + + } + + @GetMapping + @Operation(summary = "유저 로그인 API", description = "로그인 생성하는 API입니다.") + public ApiResponse userLogin(@RequestBody UserLoginReqDto userLoginReqDto) { + + return ApiResponse.onSuccess(userService.userLogin(userLoginReqDto)); + + } + + @GetMapping("/{userId}") + @Operation(summary = "내 정보 조회 API", description = "정보 조회하는 생성하는 API입니다.") + public ApiResponse userGet(@PathVariable("userId") Long userId) { + + return ApiResponse.onSuccess(userService.userGet(userId)); + + } + + + + + + +} diff --git a/src/main/java/GDGoC/team_24/domain/user/dto/UserLoginReqDto.java b/src/main/java/GDGoC/team_24/domain/user/dto/UserLoginReqDto.java index 1dcf772..1300d7d 100644 --- a/src/main/java/GDGoC/team_24/domain/user/dto/UserLoginReqDto.java +++ b/src/main/java/GDGoC/team_24/domain/user/dto/UserLoginReqDto.java @@ -1,7 +1,7 @@ -package GDGoC.team_24.domain.user.dto; - -public record UserLoginReqDto( - String name, - String phoneNumber -) { -} +package GDGoC.team_24.domain.user.dto; + +public record UserLoginReqDto( + String name, + String phoneNumber +) { +} diff --git a/src/main/java/GDGoC/team_24/domain/user/dto/UserRequestDto.java b/src/main/java/GDGoC/team_24/domain/user/dto/UserRequestDto.java index 867c3ef..614d8d6 100644 --- a/src/main/java/GDGoC/team_24/domain/user/dto/UserRequestDto.java +++ b/src/main/java/GDGoC/team_24/domain/user/dto/UserRequestDto.java @@ -1,10 +1,10 @@ -package GDGoC.team_24.domain.user.dto; - -public record UserRequestDto( - String birthDate, - String gender, - String name, - String emoji, - String phoneNumber -) { -} +package GDGoC.team_24.domain.user.dto; + +public record UserRequestDto( + String birthDate, + String gender, + String name, + String emoji, + String phoneNumber +) { +} diff --git a/src/main/java/GDGoC/team_24/domain/user/dto/UserResponseDto.java b/src/main/java/GDGoC/team_24/domain/user/dto/UserResponseDto.java index a76a6de..edd289a 100644 --- a/src/main/java/GDGoC/team_24/domain/user/dto/UserResponseDto.java +++ b/src/main/java/GDGoC/team_24/domain/user/dto/UserResponseDto.java @@ -1,26 +1,26 @@ -package GDGoC.team_24.domain.user.dto; - -import GDGoC.team_24.domain.family.domain.Family; -import GDGoC.team_24.domain.user.domain.User; - -public record UserResponseDto( - Long id, - String birthDate, - String gender, - String name, - String emoji, - String phoneNumber, - Family family -) { - public UserResponseDto(User user) { - this( - user.getId(), - user.getBirthaDate(), - user.getGender().toString(), - user.getName(), - user.getEmoji().toString(), - user.getPhoneNumber(), - user.getFamily() - ); - } -} +package GDGoC.team_24.domain.user.dto; + +import GDGoC.team_24.domain.family.domain.Family; +import GDGoC.team_24.domain.user.domain.User; + +public record UserResponseDto( + Long id, + String birthDate, + String gender, + String name, + String emoji, + String phoneNumber, + Family family +) { + public UserResponseDto(User user) { + this( + user.getId(), + user.getBirthaDate(), + user.getGender().toString(), + user.getName(), + user.getEmoji().toString(), + user.getPhoneNumber(), + user.getFamily() + ); + } +} diff --git a/src/main/java/GDGoC/team_24/domain/user/service/UserService.java b/src/main/java/GDGoC/team_24/domain/user/service/UserService.java index 221dd4f..4d6c6f8 100644 --- a/src/main/java/GDGoC/team_24/domain/user/service/UserService.java +++ b/src/main/java/GDGoC/team_24/domain/user/service/UserService.java @@ -1,57 +1,57 @@ -package GDGoC.team_24.domain.user.service; - -import GDGoC.team_24.domain.user.domain.EMOJI; -import GDGoC.team_24.domain.user.domain.GENDER; -import GDGoC.team_24.domain.user.domain.User; -import GDGoC.team_24.domain.user.dto.UserLoginReqDto; -import GDGoC.team_24.domain.user.dto.UserRequestDto; -import GDGoC.team_24.domain.user.dto.UserResponseDto; -import GDGoC.team_24.domain.user.repository.UserRepository; -import GDGoC.team_24.global.code.status.ErrorStatus; -import GDGoC.team_24.global.exception.GeneralException; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class UserService { - - private final UserRepository userRepository; - - public UserResponseDto userSignUp(UserRequestDto userRequestDto) { - - - - EMOJI emoji = EMOJI.valueOf(userRequestDto.emoji().toUpperCase()); - GENDER gender = GENDER.valueOf(userRequestDto.gender().toUpperCase()); - User user = User.builder() - .name(userRequestDto.name()) - .gender(gender) - .birthaDate(userRequestDto.birthDate()) - .phoneNumber(String.valueOf(userRequestDto.phoneNumber())) - .emoji(emoji) - .build(); - - userRepository.save(user); - - return new UserResponseDto(user); - } - - public UserResponseDto userLogin(UserLoginReqDto userLoginReqDto) { - - User user = userRepository.findByPhoneNumber(userLoginReqDto.phoneNumber()) - .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - - return new UserResponseDto(user); - - - } - - public UserResponseDto userGet(Long userId) { - - User user = userRepository.findById(userId) - .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - - return new UserResponseDto(user); - } -} +package GDGoC.team_24.domain.user.service; + +import GDGoC.team_24.domain.user.domain.EMOJI; +import GDGoC.team_24.domain.user.domain.GENDER; +import GDGoC.team_24.domain.user.domain.User; +import GDGoC.team_24.domain.user.dto.UserLoginReqDto; +import GDGoC.team_24.domain.user.dto.UserRequestDto; +import GDGoC.team_24.domain.user.dto.UserResponseDto; +import GDGoC.team_24.domain.user.repository.UserRepository; +import GDGoC.team_24.global.code.status.ErrorStatus; +import GDGoC.team_24.global.exception.GeneralException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository userRepository; + + public UserResponseDto userSignUp(UserRequestDto userRequestDto) { + + + + EMOJI emoji = EMOJI.valueOf(userRequestDto.emoji().toUpperCase()); + GENDER gender = GENDER.valueOf(userRequestDto.gender().toUpperCase()); + User user = User.builder() + .name(userRequestDto.name()) + .gender(gender) + .birthaDate(userRequestDto.birthDate()) + .phoneNumber(String.valueOf(userRequestDto.phoneNumber())) + .emoji(emoji) + .build(); + + userRepository.save(user); + + return new UserResponseDto(user); + } + + public UserResponseDto userLogin(UserLoginReqDto userLoginReqDto) { + + User user = userRepository.findByPhoneNumber(userLoginReqDto.phoneNumber()) + .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); + + return new UserResponseDto(user); + + + } + + public UserResponseDto userGet(Long userId) { + + User user = userRepository.findById(userId) + .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); + + return new UserResponseDto(user); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 35e4f90..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,19 +0,0 @@ -spring: - datasource: - url: jdbc:mysql://localhost:3306/team24 - username: root - password: ${SPRING_DATASOURCE_PASSWORD} - driver-class-name: com.mysql.cj.jdbc.Driver - sql: - init: - mode: never - jpa: - properties: - hibernate: - dialect: org.hibernate.dialect.MySQL8Dialect - show_sql: true - format_sql: true - use_sql_comments: true - hbm2ddl: - auto: update - default_batch_fetch_size: 1000 \ No newline at end of file From 1f6fbac284433b7d891d0b40d2fba6a4cb754d28 Mon Sep 17 00:00:00 2001 From: haeun Date: Sun, 19 Jan 2025 02:08:54 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Refactor:=20=ED=80=B4=EC=A6=88=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=EC=8B=9C=EA=B0=84=20=EC=9D=B4=ED=9B=84=EC=97=90=20?= =?UTF-8?q?=EB=8B=A4=EC=8B=9C=20=ED=92=80=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/controller/QuizController.java | 5 +- .../team_24/domain/quiz/dto/CustomPage.java | 19 ++++++ .../domain/quiz/dto/QuizResponseDto.java | 16 +++-- .../quiz/repository/QuizRepository.java | 2 - .../domain/quiz/service/QuizService.java | 62 +++++++++++-------- 5 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 src/main/java/GDGoC/team_24/domain/quiz/dto/CustomPage.java diff --git a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java index f35dddb..60bd0a6 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java @@ -2,6 +2,7 @@ import GDGoC.team_24.domain.quiz.converter.QuizConverter; import GDGoC.team_24.domain.quiz.domain.Quiz; +import GDGoC.team_24.domain.quiz.dto.CustomPage; import GDGoC.team_24.domain.quiz.dto.QuizRequestDto; import GDGoC.team_24.domain.quiz.dto.QuizResponseDto; import GDGoC.team_24.domain.quiz.service.QuizService; @@ -40,7 +41,7 @@ public ApiResponse answerQuiz(@RequestBody QuizRequestDto.answerQuiz re @Operation(summary = "퀴즈 조회 API", description = "지금까지 푼 퀴즈를 페이지네이션으로 조회합니다.") @GetMapping("/{userId}/answerlist") - public ApiResponse> listQuiz( + public ApiResponse> listQuiz( @PathVariable Long userId, Pageable pageable ) { @@ -56,7 +57,7 @@ public ApiResponse noAnswerQuiz (@PathVariable Long userId){ @Operation(summary = "안 푼 퀴즈 조회 API", description = "다시 풀 수 있는 퀴즈만 반환합니다.") @GetMapping("/{userId}/noanswerlist") - public ApiResponse> listNoQuiz( + public ApiResponse> listNoQuiz( @PathVariable Long userId, Pageable pageable ) { diff --git a/src/main/java/GDGoC/team_24/domain/quiz/dto/CustomPage.java b/src/main/java/GDGoC/team_24/domain/quiz/dto/CustomPage.java new file mode 100644 index 0000000..af86ef6 --- /dev/null +++ b/src/main/java/GDGoC/team_24/domain/quiz/dto/CustomPage.java @@ -0,0 +1,19 @@ +package GDGoC.team_24.domain.quiz.dto; + +import lombok.*; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CustomPage { + private List content; // 페이징된 실제 데이터 + private int pageNumber; // 현재 페이지 번호 + private int pageSize; // 페이지 크기 + private long totalElements; // 전체 요소 수 + private int totalPages; // 전체 페이지 수 + private boolean isLast; // 마지막 페이지 여부 + private boolean isFirst; // 첫 번째 페이지 여부 +} diff --git a/src/main/java/GDGoC/team_24/domain/quiz/dto/QuizResponseDto.java b/src/main/java/GDGoC/team_24/domain/quiz/dto/QuizResponseDto.java index 827e16d..f105d20 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/dto/QuizResponseDto.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/dto/QuizResponseDto.java @@ -18,18 +18,16 @@ public static class QuizResponseDTO{ private LocalDateTime createdAt; } - @Builder @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor + @Builder public static class quizList { private Long id; - private String question; // 퀴즈 - private List options; // 선택지 목록 - private Long answer; // 정답 번호 - private Long quizAnswer; // 유저의 답변 번호 - private boolean isCorrect; // 맞/틀 여부 + private String question; + private List options; + private Long answer; + private Long quizAnswer; + private boolean isCorrect; + private LocalDateTime solvedAt; // 푼 날짜 추가 } // 선택지 DTO diff --git a/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java b/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java index 118a5e0..8d3a501 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/repository/QuizRepository.java @@ -32,6 +32,4 @@ boolean existsByUserAndIsCompletedAndNextRetryTimeBefore( @Param("user") User user, @Param("isCompleted") Boolean isCompleted); - - } diff --git a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java index 3547192..5b2467a 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java @@ -4,6 +4,7 @@ import GDGoC.team_24.domain.family.repository.FamilyRepository; import GDGoC.team_24.domain.quiz.domain.Quiz; import GDGoC.team_24.domain.quiz.domain.QuizOption; +import GDGoC.team_24.domain.quiz.dto.CustomPage; import GDGoC.team_24.domain.quiz.dto.QuizRequestDto; import GDGoC.team_24.domain.quiz.dto.QuizResponseDto; import GDGoC.team_24.domain.quiz.repository.QuizOptionRepository; @@ -83,44 +84,55 @@ public Boolean answerQuiz(QuizRequestDto.answerQuiz request) { - public Page readAllQuizzes(Long userId, Boolean solve, Pageable pageable) { + public CustomPage readAllQuizzes(Long userId, Boolean solve, Pageable pageable) { User user = userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - // solve 값에 따라 풀었던 퀴즈/풀지 않은 퀴즈 조회 Page quizzes = solve - ? quizRepository.findSolvedQuizzes(user, pageable) // 풀었던 퀴즈 조회 - : quizRepository.findUnsolvedQuizzes(user, pageable); // 풀지 않은 퀴즈 조회 (nextRetryTime 조건 포함) + ? quizRepository.findSolvedQuizzes(user, pageable) + : quizRepository.findUnsolvedQuizzes(user, pageable); if (quizzes.isEmpty()) { throw new GeneralException(ErrorStatus.QUIZ_NOT_FOUND); } - // DTO 변환 - return quizzes.map(quiz -> { - List options = quizOptionRepository.findByQuiz(quiz); - - List optionDtos = options.stream() - .map(option -> QuizResponseDto.QuizOptionDto.builder() - .number(option.getNumber()) - .text(option.getText()) - .build()) - .toList(); - - return QuizResponseDto.quizList.builder() - .id(quiz.getId()) - .question(quiz.getQuestion()) - .options(optionDtos) - .answer(quiz.getAnswer()) - .quizAnswer(quiz.getQuizAnswer()) - .isCorrect(quiz.isCorrect()) - .build(); - }); + // `Page` 객체를 `CustomPage`로 변환 + List quizList = quizzes.getContent().stream() + .map(quiz -> { + List options = quizOptionRepository.findByQuiz(quiz); + + List optionDtos = options.stream() + .map(option -> QuizResponseDto.QuizOptionDto.builder() + .number(option.getNumber()) + .text(option.getText()) + .build()) + .toList(); + + return QuizResponseDto.quizList.builder() + .id(quiz.getId()) + .question(quiz.getQuestion()) + .options(optionDtos) + .answer(quiz.getAnswer()) + .quizAnswer(quiz.getQuizAnswer()) + .isCorrect(quiz.isCorrect()) + .solvedAt(quiz.getUpdatedAt()) + .build(); + }) + .toList(); + + return CustomPage.builder() + .content(quizList) + .pageNumber(quizzes.getNumber()) + .pageSize(quizzes.getSize()) + .totalElements(quizzes.getTotalElements()) + .totalPages(quizzes.getTotalPages()) + .isLast(quizzes.isLast()) + .isFirst(quizzes.isFirst()) + .build(); } - public Boolean noAnswerQuiz(Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); From f7fda6bebb61d9a407251b1c0a4e49115ef854b3 Mon Sep 17 00:00:00 2001 From: haeun Date: Sun, 19 Jan 2025 02:18:33 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Refactor:=20=EC=95=88=ED=91=BC=20=ED=80=B4?= =?UTF-8?q?=EC=A6=88=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=ED=92=80=EC=97=88?= =?UTF-8?q?=EB=8D=98=20=EB=82=A0=EC=A7=9C=EA=B0=80=20null=EC=9D=B4=20?= =?UTF-8?q?=EB=82=98=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/controller/QuizController.java | 2 +- .../team_24/domain/quiz/service/QuizService.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java index 60bd0a6..151ddf4 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/controller/QuizController.java @@ -39,7 +39,7 @@ public ApiResponse answerQuiz(@RequestBody QuizRequestDto.answerQuiz re } - @Operation(summary = "퀴즈 조회 API", description = "지금까지 푼 퀴즈를 페이지네이션으로 조회합니다.") + @Operation(summary = "풀었던 퀴즈 조회 API", description = "지금까지 푼 퀴즈를 페이지네이션으로 조회합니다.") @GetMapping("/{userId}/answerlist") public ApiResponse> listQuiz( @PathVariable Long userId, diff --git a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java index 5b2467a..1c8151b 100644 --- a/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java +++ b/src/main/java/GDGoC/team_24/domain/quiz/service/QuizService.java @@ -81,16 +81,15 @@ public Boolean answerQuiz(QuizRequestDto.answerQuiz request) { quizRepository.save(quiz); return isCorrect; } - - + public CustomPage readAllQuizzes(Long userId, Boolean solve, Pageable pageable) { User user = userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); Page quizzes = solve - ? quizRepository.findSolvedQuizzes(user, pageable) - : quizRepository.findUnsolvedQuizzes(user, pageable); + ? quizRepository.findSolvedQuizzes(user, pageable) // 풀었던 퀴즈 조회 + : quizRepository.findUnsolvedQuizzes(user, pageable); // 안 푼 퀴즈 조회 if (quizzes.isEmpty()) { throw new GeneralException(ErrorStatus.QUIZ_NOT_FOUND); @@ -99,8 +98,10 @@ public CustomPage readAllQuizzes(Long userId, Boolean // `Page` 객체를 `CustomPage`로 변환 List quizList = quizzes.getContent().stream() .map(quiz -> { + // 각 퀴즈의 선택지만 조회 List options = quizOptionRepository.findByQuiz(quiz); + // 선택지 DTO로 변환 List optionDtos = options.stream() .map(option -> QuizResponseDto.QuizOptionDto.builder() .number(option.getNumber()) @@ -108,6 +109,10 @@ public CustomPage readAllQuizzes(Long userId, Boolean .build()) .toList(); + // `solvedAt` 값을 퀴즈 상태에 따라 설정 + LocalDateTime solvedAt = quiz.isCompleted() ? quiz.getUpdatedAt() : null; + + // 퀴즈 DTO로 변환 return QuizResponseDto.quizList.builder() .id(quiz.getId()) .question(quiz.getQuestion()) @@ -115,7 +120,7 @@ public CustomPage readAllQuizzes(Long userId, Boolean .answer(quiz.getAnswer()) .quizAnswer(quiz.getQuizAnswer()) .isCorrect(quiz.isCorrect()) - .solvedAt(quiz.getUpdatedAt()) + .solvedAt(solvedAt) // 상태에 따라 `solvedAt` 값 설정 .build(); }) .toList(); From 98ee652df9cf7a954a32b1fd45e268bddbefaa8c Mon Sep 17 00:00:00 2001 From: haeun Date: Sun, 19 Jan 2025 03:06:26 +0900 Subject: [PATCH 4/4] Refactor: --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755