From 098dc1ded9d9cc4ce81d2a62111502b8ee9e6fd7 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Mon, 14 Jul 2025 16:52:14 +0900 Subject: [PATCH 01/10] =?UTF-8?q?:sparkles:=20=ED=80=B4=EC=A6=88=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C,=20=EC=88=98=EC=A0=95,=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/api/QuizController.java | 42 +++++++++ .../backend/domain/quiz/app/QuizService.java | 91 ++++++++++++++++++- .../domain/quiz/dao/QuizRepository.java | 9 +- .../domain/quiz/dto/QuizListPageResponse.java | 5 + .../domain/quiz/dto/QuizListResponse.java | 3 + .../domain/quiz/dto/QuizUpdateRequest.java | 3 + .../f1/backend/domain/quiz/entity/Quiz.java | 12 +++ .../domain/quiz/mapper/QuizMapper.java | 28 ++++++ 8 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java create mode 100644 backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java create mode 100644 backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java index b25897c2..3991eafc 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java @@ -4,15 +4,25 @@ import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; +import io.f1.backend.domain.quiz.dto.QuizListPageResponse; +import io.f1.backend.domain.quiz.dto.QuizUpdateRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -35,4 +45,36 @@ public ResponseEntity saveQuiz( return ResponseEntity.status(HttpStatus.CREATED).body(response); } + + @DeleteMapping("/{quizId}") + public ResponseEntity deleteQuiz(@PathVariable Long quizId) { + + quizService.deleteQuiz(quizId); + return ResponseEntity.noContent().build(); + } + + @PutMapping("/{quizId}") + public ResponseEntity updateQuiz( + @PathVariable Long quizId, + @RequestPart(required = false) MultipartFile thumbnailFile, + @RequestPart QuizUpdateRequest request) + throws IOException { + + quizService.updateQuiz(quizId, thumbnailFile, request); + + return ResponseEntity.noContent().build(); + } + + @GetMapping + public ResponseEntity getQuizzes( + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size, + @RequestParam(required = false) String title, + @RequestParam(required = false) String creator) { + + Pageable pageable = PageRequest.of(page - 1, size); + QuizListPageResponse quizzes = quizService.getQuizzes(title, creator, pageable); + + return ResponseEntity.ok().body(quizzes); + } } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index ffe46c50..510505e3 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -1,20 +1,29 @@ package io.f1.backend.domain.quiz.app; +import static io.f1.backend.domain.quiz.mapper.QuizMapper.pageQuizToPageQuizListResponse; import static io.f1.backend.domain.quiz.mapper.QuizMapper.quizCreateRequestToQuiz; import static io.f1.backend.domain.quiz.mapper.QuizMapper.quizToQuizCreateResponse; +import static io.f1.backend.domain.quiz.mapper.QuizMapper.toQuizListPageResponse; +import static java.nio.file.Files.deleteIfExists; import io.f1.backend.domain.question.app.QuestionService; import io.f1.backend.domain.question.dto.QuestionRequest; import io.f1.backend.domain.quiz.dao.QuizRepository; import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; +import io.f1.backend.domain.quiz.dto.QuizListPageResponse; +import io.f1.backend.domain.quiz.dto.QuizListResponse; +import io.f1.backend.domain.quiz.dto.QuizUpdateRequest; import io.f1.backend.domain.quiz.entity.Quiz; import io.f1.backend.domain.user.dao.UserRepository; import io.f1.backend.domain.user.entity.User; +import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -91,4 +100,84 @@ private String convertToThumbnailPath(MultipartFile thumbnailFile) throws IOExce private String getExtension(String filename) { return filename.substring(filename.lastIndexOf(".") + 1); } -} + + @Transactional + public void deleteQuiz(Long quizId) { + + Quiz quiz = quizRepository.findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + + if(1L != quiz.getCreator().getId()) { + throw new RuntimeException("권한이 없습니다."); + } + + deleteOldThumbnailFileIfNeeded(quiz.getThumbnailUrl()); + quizRepository.deleteById(quizId); + } + + @Transactional + public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateRequest request) + throws IOException { + + Quiz quiz = quizRepository.findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + + if(request.title() != null) { + quiz.changeTitle(request.title()); + } + + if(request.description() != null) { + quiz.changeDescription(request.description()); + } + + if(thumbnailFile !=null && !thumbnailFile.isEmpty()) { + validateImageFile(thumbnailFile); + String newThumbnailPath = convertToThumbnailPath(thumbnailFile); + + deleteOldThumbnailFileIfNeeded(quiz.getThumbnailUrl()); + quiz.changeThumbnailUrl(newThumbnailPath); + } + } + + private void deleteOldThumbnailFileIfNeeded(String oldFilename) { + if(oldFilename.contains("default")) { + return; + } + + // oldFilename : /images/thumbnail/123asd.jpg + // filename : 123asd.jpg + String filename = oldFilename.substring(oldFilename.lastIndexOf("/") + 1); + Path filePath = Paths.get(uploadPath, filename).toAbsolutePath(); + + try { + boolean deleted = deleteIfExists(filePath); + if( deleted ) { + System.out.println("기존 썸네일 삭제 완료 : " + filePath); + } else { + System.out.println("기존 썸네일 존재 X : " + filePath); + } + } catch (IOException e) { + System.err.println("기존 썸네일 삭제 중 오류 : " + filePath); + throw new RuntimeException(e); + } + } + + @Transactional(readOnly=true) + public QuizListPageResponse getQuizzes(String title, String creator, Pageable pageable) { + + Page quizzes; + + // 검색어가 있을 때 + if(title != null && !title.isBlank()) { + quizzes = quizRepository.findQuizzesByTitleContaining(title, pageable); + } else if(creator !=null && !creator.isBlank()) { + quizzes = quizRepository.findQuizzesByCreator_NicknameContaining(creator, pageable); + } else { // 검색어가 없을 때 혹은 빈 문자열일 때 + quizzes = quizRepository.findAll(pageable); + } + + Page quizListResponses = pageQuizToPageQuizListResponse(quizzes); + + return toQuizListPageResponse(quizListResponses); + } +} \ No newline at end of file diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index a88c98e7..ab0555e8 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -2,6 +2,13 @@ import io.f1.backend.domain.quiz.entity.Quiz; +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; -public interface QuizRepository extends JpaRepository {} +public interface QuizRepository extends JpaRepository { + + Page findQuizzesByTitleContaining(String title, Pageable pageable); + Page findQuizzesByCreator_NicknameContaining(String creator, Pageable pageable); +} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java new file mode 100644 index 00000000..11639650 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java @@ -0,0 +1,5 @@ +package io.f1.backend.domain.quiz.dto; + +import java.util.List; + +public record QuizListPageResponse(int totalPages, int currentPage, long totalElements, List quiz) { } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java new file mode 100644 index 00000000..b8d77a9d --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.quiz.dto; + +public record QuizListResponse(Long quizId, String title, String description, String creatorNickname, int numberOfQuestion, String thumbnailUrl) { } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java new file mode 100644 index 00000000..5a820c8a --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.quiz.dto; + +public record QuizUpdateRequest(String title, String description) {} \ No newline at end of file diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/entity/Quiz.java b/backend/src/main/java/io/f1/backend/domain/quiz/entity/Quiz.java index 5168a1e1..fde07c7e 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/entity/Quiz.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/entity/Quiz.java @@ -69,4 +69,16 @@ public Quiz( public void addQuestion(Question question) { this.questions.add(question); } + + public void changeTitle(String title) { + this.title = title; + } + + public void changeDescription(String description) { + this.description = description; + } + + public void changeThumbnailUrl(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java index 762c6ead..d786af0c 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java @@ -2,8 +2,12 @@ import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; +import io.f1.backend.domain.quiz.dto.QuizListPageResponse; +import io.f1.backend.domain.quiz.dto.QuizListResponse; import io.f1.backend.domain.quiz.entity.Quiz; import io.f1.backend.domain.user.entity.User; +import java.util.List; +import org.springframework.data.domain.Page; public class QuizMapper { @@ -30,4 +34,28 @@ public static QuizCreateResponse quizToQuizCreateResponse(Quiz quiz) { quiz.getThumbnailUrl(), quiz.getCreator().getId()); } + + public static QuizListResponse quizToQuizListResponse(Quiz quiz) { + return new QuizListResponse( + quiz.getId(), + quiz.getTitle(), + quiz.getDescription(), + quiz.getCreator().getNickname(), + quiz.getQuestions().size(), + quiz.getThumbnailUrl() + ); + } + + public static QuizListPageResponse toQuizListPageResponse(Page quizzes) { + return new QuizListPageResponse( + quizzes.getTotalPages(), + quizzes.getNumber() + 1, + quizzes.getTotalElements(), + quizzes.getContent() + ); + } + + public static Page pageQuizToPageQuizListResponse(Page quizzes) { + return quizzes.map(QuizMapper::quizToQuizListResponse); + } } From c26c4891fd23a48d8a49d9782ece485275089fa7 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Mon, 14 Jul 2025 07:52:35 +0000 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/api/QuizController.java | 3 +- .../backend/domain/quiz/app/QuizService.java | 37 +++++++++++-------- .../domain/quiz/dao/QuizRepository.java | 2 +- .../domain/quiz/dto/QuizListPageResponse.java | 3 +- .../domain/quiz/dto/QuizListResponse.java | 8 +++- .../domain/quiz/dto/QuizUpdateRequest.java | 2 +- .../domain/quiz/mapper/QuizMapper.java | 24 ++++++------ 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java index 3991eafc..3fd411ff 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java @@ -3,9 +3,9 @@ import io.f1.backend.domain.quiz.app.QuizService; import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; - import io.f1.backend.domain.quiz.dto.QuizListPageResponse; import io.f1.backend.domain.quiz.dto.QuizUpdateRequest; + import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -20,7 +20,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index 510505e3..8a6391af 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -4,6 +4,7 @@ import static io.f1.backend.domain.quiz.mapper.QuizMapper.quizCreateRequestToQuiz; import static io.f1.backend.domain.quiz.mapper.QuizMapper.quizToQuizCreateResponse; import static io.f1.backend.domain.quiz.mapper.QuizMapper.toQuizListPageResponse; + import static java.nio.file.Files.deleteIfExists; import io.f1.backend.domain.question.app.QuestionService; @@ -18,7 +19,6 @@ import io.f1.backend.domain.user.dao.UserRepository; import io.f1.backend.domain.user.entity.User; -import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -32,6 +32,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +import java.util.NoSuchElementException; import java.util.UUID; @Service @@ -104,10 +105,12 @@ private String getExtension(String filename) { @Transactional public void deleteQuiz(Long quizId) { - Quiz quiz = quizRepository.findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + Quiz quiz = + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); - if(1L != quiz.getCreator().getId()) { + if (1L != quiz.getCreator().getId()) { throw new RuntimeException("권한이 없습니다."); } @@ -117,20 +120,22 @@ public void deleteQuiz(Long quizId) { @Transactional public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateRequest request) - throws IOException { + throws IOException { - Quiz quiz = quizRepository.findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + Quiz quiz = + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); - if(request.title() != null) { + if (request.title() != null) { quiz.changeTitle(request.title()); } - if(request.description() != null) { + if (request.description() != null) { quiz.changeDescription(request.description()); } - if(thumbnailFile !=null && !thumbnailFile.isEmpty()) { + if (thumbnailFile != null && !thumbnailFile.isEmpty()) { validateImageFile(thumbnailFile); String newThumbnailPath = convertToThumbnailPath(thumbnailFile); @@ -140,7 +145,7 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque } private void deleteOldThumbnailFileIfNeeded(String oldFilename) { - if(oldFilename.contains("default")) { + if (oldFilename.contains("default")) { return; } @@ -151,7 +156,7 @@ private void deleteOldThumbnailFileIfNeeded(String oldFilename) { try { boolean deleted = deleteIfExists(filePath); - if( deleted ) { + if (deleted) { System.out.println("기존 썸네일 삭제 완료 : " + filePath); } else { System.out.println("기존 썸네일 존재 X : " + filePath); @@ -162,15 +167,15 @@ private void deleteOldThumbnailFileIfNeeded(String oldFilename) { } } - @Transactional(readOnly=true) + @Transactional(readOnly = true) public QuizListPageResponse getQuizzes(String title, String creator, Pageable pageable) { Page quizzes; // 검색어가 있을 때 - if(title != null && !title.isBlank()) { + if (title != null && !title.isBlank()) { quizzes = quizRepository.findQuizzesByTitleContaining(title, pageable); - } else if(creator !=null && !creator.isBlank()) { + } else if (creator != null && !creator.isBlank()) { quizzes = quizRepository.findQuizzesByCreator_NicknameContaining(creator, pageable); } else { // 검색어가 없을 때 혹은 빈 문자열일 때 quizzes = quizRepository.findAll(pageable); @@ -180,4 +185,4 @@ public QuizListPageResponse getQuizzes(String title, String creator, Pageable pa return toQuizListPageResponse(quizListResponses); } -} \ No newline at end of file +} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index ab0555e8..82b6bd16 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -5,10 +5,10 @@ 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; public interface QuizRepository extends JpaRepository { Page findQuizzesByTitleContaining(String title, Pageable pageable); + Page findQuizzesByCreator_NicknameContaining(String creator, Pageable pageable); } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java index 11639650..f10457f2 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListPageResponse.java @@ -2,4 +2,5 @@ import java.util.List; -public record QuizListPageResponse(int totalPages, int currentPage, long totalElements, List quiz) { } +public record QuizListPageResponse( + int totalPages, int currentPage, long totalElements, List quiz) {} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java index b8d77a9d..8a443fab 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizListResponse.java @@ -1,3 +1,9 @@ package io.f1.backend.domain.quiz.dto; -public record QuizListResponse(Long quizId, String title, String description, String creatorNickname, int numberOfQuestion, String thumbnailUrl) { } +public record QuizListResponse( + Long quizId, + String title, + String description, + String creatorNickname, + int numberOfQuestion, + String thumbnailUrl) {} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java index 5a820c8a..30065d4f 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizUpdateRequest.java @@ -1,3 +1,3 @@ package io.f1.backend.domain.quiz.dto; -public record QuizUpdateRequest(String title, String description) {} \ No newline at end of file +public record QuizUpdateRequest(String title, String description) {} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java index d786af0c..e6bf88e8 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java @@ -6,7 +6,7 @@ import io.f1.backend.domain.quiz.dto.QuizListResponse; import io.f1.backend.domain.quiz.entity.Quiz; import io.f1.backend.domain.user.entity.User; -import java.util.List; + import org.springframework.data.domain.Page; public class QuizMapper { @@ -37,22 +37,20 @@ public static QuizCreateResponse quizToQuizCreateResponse(Quiz quiz) { public static QuizListResponse quizToQuizListResponse(Quiz quiz) { return new QuizListResponse( - quiz.getId(), - quiz.getTitle(), - quiz.getDescription(), - quiz.getCreator().getNickname(), - quiz.getQuestions().size(), - quiz.getThumbnailUrl() - ); + quiz.getId(), + quiz.getTitle(), + quiz.getDescription(), + quiz.getCreator().getNickname(), + quiz.getQuestions().size(), + quiz.getThumbnailUrl()); } public static QuizListPageResponse toQuizListPageResponse(Page quizzes) { return new QuizListPageResponse( - quizzes.getTotalPages(), - quizzes.getNumber() + 1, - quizzes.getTotalElements(), - quizzes.getContent() - ); + quizzes.getTotalPages(), + quizzes.getNumber() + 1, + quizzes.getTotalElements(), + quizzes.getContent()); } public static Page pageQuizToPageQuizListResponse(Page quizzes) { From a0fd2f994013051b2b5efc9de07d2bb2ed494d5a Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Mon, 14 Jul 2025 17:36:47 +0900 Subject: [PATCH 03/10] =?UTF-8?q?:recycle:=20refactor=20:=20StringUtils.is?= =?UTF-8?q?Blank=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/quiz/app/QuizService.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index 8a6391af..b0042b1f 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -19,8 +19,11 @@ import io.f1.backend.domain.user.dao.UserRepository; import io.f1.backend.domain.user.entity.User; +import io.micrometer.common.util.StringUtils; +import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -35,6 +38,7 @@ import java.util.NoSuchElementException; import java.util.UUID; +@Slf4j @Service @RequiredArgsConstructor public class QuizService { @@ -110,7 +114,8 @@ public void deleteQuiz(Long quizId) { .findById(quizId) .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); - if (1L != quiz.getCreator().getId()) { + // TODO : util 메서드에서 사용자 ID 꺼내쓰는 식으로 수정하기 + if(1L != quiz.getCreator().getId()) { throw new RuntimeException("권한이 없습니다."); } @@ -156,13 +161,13 @@ private void deleteOldThumbnailFileIfNeeded(String oldFilename) { try { boolean deleted = deleteIfExists(filePath); - if (deleted) { - System.out.println("기존 썸네일 삭제 완료 : " + filePath); + if( deleted ) { + log.info("기존 썸네일 삭제 완료 : {}", filePath); } else { - System.out.println("기존 썸네일 존재 X : " + filePath); + log.info("기존 썸네일 존재 X : {}", filePath); } } catch (IOException e) { - System.err.println("기존 썸네일 삭제 중 오류 : " + filePath); + log.error("기존 썸네일 삭제 중 오류 : {}", filePath); throw new RuntimeException(e); } } @@ -173,9 +178,9 @@ public QuizListPageResponse getQuizzes(String title, String creator, Pageable pa Page quizzes; // 검색어가 있을 때 - if (title != null && !title.isBlank()) { + if(StringUtils.isBlank(title)) { quizzes = quizRepository.findQuizzesByTitleContaining(title, pageable); - } else if (creator != null && !creator.isBlank()) { + } else if(StringUtils.isBlank(creator)) { quizzes = quizRepository.findQuizzesByCreator_NicknameContaining(creator, pageable); } else { // 검색어가 없을 때 혹은 빈 문자열일 때 quizzes = quizRepository.findAll(pageable); From 0147325a9c9d3ac5b2f8ec1f0ed98d6e4ede8834 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Mon, 14 Jul 2025 08:39:26 +0000 Subject: [PATCH 04/10] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/f1/backend/domain/quiz/app/QuizService.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index b0042b1f..dcb67958 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -18,12 +18,11 @@ import io.f1.backend.domain.quiz.entity.Quiz; import io.f1.backend.domain.user.dao.UserRepository; import io.f1.backend.domain.user.entity.User; - import io.micrometer.common.util.StringUtils; -import java.util.NoSuchElementException; -import lombok.RequiredArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -115,7 +114,7 @@ public void deleteQuiz(Long quizId) { .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); // TODO : util 메서드에서 사용자 ID 꺼내쓰는 식으로 수정하기 - if(1L != quiz.getCreator().getId()) { + if (1L != quiz.getCreator().getId()) { throw new RuntimeException("권한이 없습니다."); } @@ -161,7 +160,7 @@ private void deleteOldThumbnailFileIfNeeded(String oldFilename) { try { boolean deleted = deleteIfExists(filePath); - if( deleted ) { + if (deleted) { log.info("기존 썸네일 삭제 완료 : {}", filePath); } else { log.info("기존 썸네일 존재 X : {}", filePath); @@ -178,9 +177,9 @@ public QuizListPageResponse getQuizzes(String title, String creator, Pageable pa Page quizzes; // 검색어가 있을 때 - if(StringUtils.isBlank(title)) { + if (StringUtils.isBlank(title)) { quizzes = quizRepository.findQuizzesByTitleContaining(title, pageable); - } else if(StringUtils.isBlank(creator)) { + } else if (StringUtils.isBlank(creator)) { quizzes = quizRepository.findQuizzesByCreator_NicknameContaining(creator, pageable); } else { // 검색어가 없을 때 혹은 빈 문자열일 때 quizzes = quizRepository.findAll(pageable); From e7ddc83923a687923ed01c9b9fb70f8d63f81b0b Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Mon, 14 Jul 2025 17:41:11 +0900 Subject: [PATCH 05/10] =?UTF-8?q?:sparkles:=20feat:=20=ED=80=B4=EC=A6=88?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=B5=9C=EC=8B=A0?= =?UTF-8?q?=EC=88=9C=EC=9C=BC=EB=A1=9C=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/f1/backend/domain/quiz/api/QuizController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java index 3fd411ff..e8520640 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java @@ -12,6 +12,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -71,7 +72,7 @@ public ResponseEntity getQuizzes( @RequestParam(required = false) String title, @RequestParam(required = false) String creator) { - Pageable pageable = PageRequest.of(page - 1, size); + Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt")); QuizListPageResponse quizzes = quizService.getQuizzes(title, creator, pageable); return ResponseEntity.ok().body(quizzes); From 9ed7545ce374bea82cefa4ed94739501a89a7c2e Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Mon, 14 Jul 2025 08:41:40 +0000 Subject: [PATCH 06/10] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/f1/backend/domain/quiz/api/QuizController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java index e8520640..8439f4e3 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/api/QuizController.java @@ -72,7 +72,8 @@ public ResponseEntity getQuizzes( @RequestParam(required = false) String title, @RequestParam(required = false) String creator) { - Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt")); + Pageable pageable = + PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt")); QuizListPageResponse quizzes = quizService.getQuizzes(title, creator, pageable); return ResponseEntity.ok().body(quizzes); From db0e8ff8eaded02fc123ae4fef4545a56846f9c3 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Mon, 14 Jul 2025 08:43:47 +0000 Subject: [PATCH 07/10] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/domain/quiz/app/QuizService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index 50915535..11ae36cf 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -189,12 +189,11 @@ public QuizListPageResponse getQuizzes(String title, String creator, Pageable pa return toQuizListPageResponse(quizListResponses); } - + @Transactional(readOnly = true) public Quiz getQuizById(Long quizId) { return quizRepository .findById(quizId) .orElseThrow(() -> new RuntimeException("E404002: 존재하지 않는 퀴즈입니다.")); - } } From 5885b66f9f03bc6de4b77050e239ab6fba966271 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Mon, 14 Jul 2025 17:56:15 +0900 Subject: [PATCH 08/10] =?UTF-8?q?:recycle:=20refactor=20:=20default=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=83=81=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EB=B9=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/domain/quiz/app/QuizService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index 11ae36cf..a341c8be 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -48,6 +48,8 @@ public class QuizService { @Value("${file.default-thumbnail-url}") private String defaultThumbnailPath; + private final String DEFAULT = "default"; + // TODO : 시큐리티 구현 이후 삭제해도 되는 의존성 주입 private final UserRepository userRepository; private final QuestionService questionService; @@ -149,7 +151,7 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque } private void deleteOldThumbnailFileIfNeeded(String oldFilename) { - if (oldFilename.contains("default")) { + if (oldFilename.contains(DEFAULT)) { return; } From 780f03b8cc034f15a175437dd7047834c574a85d Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Tue, 15 Jul 2025 08:48:01 +0900 Subject: [PATCH 09/10] =?UTF-8?q?:recycle:=20refactor=20:=20StringUtils=20?= =?UTF-8?q?import=EB=AC=B8=20=EC=88=98=EC=A0=95,=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/build.gradle | 1 + .../java/io/f1/backend/domain/quiz/app/QuizService.java | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 1b77cc8b..caf92a70 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -44,6 +44,7 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' /* ETC */ + implementation 'org.apache.commons:commons-lang3:3.12.0' annotationProcessor 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok' diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index a341c8be..c0368176 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -18,7 +18,6 @@ import io.f1.backend.domain.quiz.entity.Quiz; import io.f1.backend.domain.user.dao.UserRepository; import io.f1.backend.domain.user.entity.User; -import io.micrometer.common.util.StringUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -29,6 +28,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.nio.file.Path; @@ -120,7 +120,7 @@ public void deleteQuiz(Long quizId) { throw new RuntimeException("권한이 없습니다."); } - deleteOldThumbnailFileIfNeeded(quiz.getThumbnailUrl()); + deleteThumbnailFile(quiz.getThumbnailUrl()); quizRepository.deleteById(quizId); } @@ -145,12 +145,12 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque validateImageFile(thumbnailFile); String newThumbnailPath = convertToThumbnailPath(thumbnailFile); - deleteOldThumbnailFileIfNeeded(quiz.getThumbnailUrl()); + deleteThumbnailFile(quiz.getThumbnailUrl()); quiz.changeThumbnailUrl(newThumbnailPath); } } - private void deleteOldThumbnailFileIfNeeded(String oldFilename) { + private void deleteThumbnailFile(String oldFilename) { if (oldFilename.contains(DEFAULT)) { return; } From 6d9483cc9494a19a97cd4847ec5a49e5e5d0fe6f Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Tue, 15 Jul 2025 00:18:38 +0000 Subject: [PATCH 10/10] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/domain/quiz/app/QuizService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index c0368176..94a8dba4 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -22,13 +22,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.nio.file.Path;