From 3f1fca61d492be692e0663eab1e818dc12272c21 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Tue, 15 Jul 2025 15:05:26 +0900 Subject: [PATCH 1/7] =?UTF-8?q?:sparkles:=20feat=20:=20=EB=AC=B8=EC=A0=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20=EC=82=AD=EC=A0=9C=20API=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20+=20TrimmedSize=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question/api/QuestionController.java | 35 +++++++++++++++ .../domain/question/app/QuestionService.java | 44 +++++++++++++++++++ .../domain/question/dto/QuestionRequest.java | 3 ++ .../question/dto/QuestionUpdateRequest.java | 5 +++ .../domain/question/entity/Question.java | 4 ++ .../domain/question/entity/TextQuestion.java | 4 ++ .../backend/domain/quiz/app/QuizService.java | 14 ++++++ .../domain/quiz/dto/QuizCreateRequest.java | 3 ++ .../backend/global/config/SecurityConfig.java | 2 +- .../global/validation/TrimmedSize.java | 21 +++++++++ .../validation/TrimmedSizeValidator.java | 26 +++++++++++ 11 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java create mode 100644 backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java create mode 100644 backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java create mode 100644 backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java diff --git a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java new file mode 100644 index 00000000..cdaa8ffe --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java @@ -0,0 +1,35 @@ +package io.f1.backend.domain.question.api; + +import io.f1.backend.domain.question.app.QuestionService; +import io.f1.backend.domain.question.dto.QuestionUpdateRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +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.RestController; + +@RestController +@RequestMapping("/questions") +@RequiredArgsConstructor +public class QuestionController { + + private final QuestionService questionService; + + @PutMapping("/{questionId}") + public ResponseEntity updateQuestion(@PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { + questionService.updateQuestion(questionId, request); + + return ResponseEntity.noContent().build(); + } + + @DeleteMapping("/{questionId}") + public ResponseEntity deleteQuestion(@PathVariable Long questionId) { + questionService.deleteQuestion(questionId); + + return ResponseEntity.noContent().build(); + } + +} diff --git a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java index 87a0e222..d9f11d7b 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java +++ b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java @@ -6,10 +6,12 @@ import io.f1.backend.domain.question.dao.QuestionRepository; import io.f1.backend.domain.question.dao.TextQuestionRepository; import io.f1.backend.domain.question.dto.QuestionRequest; +import io.f1.backend.domain.question.dto.QuestionUpdateRequest; import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.question.entity.TextQuestion; import io.f1.backend.domain.quiz.entity.Quiz; +import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -33,4 +35,46 @@ public void saveQuestion(Quiz quiz, QuestionRequest request) { textQuestionRepository.save(textQuestion); question.addTextQuestion(textQuestion); } + + @Transactional + public void updateQuestion(Long questionId, QuestionUpdateRequest request) { + + Question question = questionRepository.findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + + TextQuestion textQuestion = question.getTextQuestion(); + + if(request.content() != null) { + validateContent(request.content()); + textQuestion.changeContent(request.content()); + } + + if(request.answer() != null) { + validateAnswer(request.answer()); + question.changeAnswer(request.answer()); + } + + } + + @Transactional + public void deleteQuestion(Long questionId) { + + Question question = questionRepository.findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + + questionRepository.delete(question); + + } + + private void validateAnswer(String answer) { + if(answer.trim().length() < 5 || answer.trim().length() > 30) { + throw new IllegalArgumentException("정답은 1자 이상 30자 이하로 입력해주세요."); + } + } + + private void validateContent(String content) { + if(content.trim().length() < 5 || content.trim().length() > 30) { + throw new IllegalArgumentException("문제는 5자 이상 30자 이하로 입력해주세요."); + } + } } diff --git a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java index 9374a9b9..c7cca216 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java @@ -1,5 +1,6 @@ package io.f1.backend.domain.question.dto; +import io.f1.backend.global.validation.TrimmedSize; import jakarta.validation.constraints.NotBlank; import lombok.AccessLevel; @@ -10,9 +11,11 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class QuestionRequest { + @TrimmedSize(min=5, max=30) @NotBlank(message = "문제를 입력해주세요.") private String content; + @TrimmedSize(min=1, max=30) @NotBlank(message = "정답을 입력해주세요.") private String answer; } diff --git a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java new file mode 100644 index 00000000..5a428414 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java @@ -0,0 +1,5 @@ +package io.f1.backend.domain.question.dto; + +public record QuestionUpdateRequest(String content, String answer) { + +} diff --git a/backend/src/main/java/io/f1/backend/domain/question/entity/Question.java b/backend/src/main/java/io/f1/backend/domain/question/entity/Question.java index b197ac6e..fe6d0783 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/entity/Question.java +++ b/backend/src/main/java/io/f1/backend/domain/question/entity/Question.java @@ -45,4 +45,8 @@ public Question(Quiz quiz, String answer) { public void addTextQuestion(TextQuestion textQuestion) { this.textQuestion = textQuestion; } + + public void changeAnswer(String answer) { + this.answer = answer; + } } diff --git a/backend/src/main/java/io/f1/backend/domain/question/entity/TextQuestion.java b/backend/src/main/java/io/f1/backend/domain/question/entity/TextQuestion.java index 7adf05c1..b10be109 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/entity/TextQuestion.java +++ b/backend/src/main/java/io/f1/backend/domain/question/entity/TextQuestion.java @@ -32,4 +32,8 @@ public TextQuestion(Question question, String content) { this.question = question; this.content = content; } + + public void changeContent(String content) { + this.content = content; + } } 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 37c0585b..95313859 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 @@ -132,10 +132,12 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); if (request.title() != null) { + validateTitle(request.title()); quiz.changeTitle(request.title()); } if (request.description() != null) { + validateDesc(request.description()); quiz.changeDescription(request.description()); } @@ -148,6 +150,18 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque } } + private void validateDesc(String desc) { + if( desc.trim().length() < 10 || desc.trim().length() > 50) { + throw new IllegalArgumentException("설명은 10자 이상 50자 이하로 입력해주세요."); + } + } + + private void validateTitle(String title) { + if (title.trim().length() < 2 || title.trim().length() > 30) { + throw new IllegalArgumentException("제목은 2자 이상 30자 이하로 입력해주세요."); + } + } + private void deleteThumbnailFile(String oldFilename) { if (oldFilename.contains(DEFAULT)) { return; diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java index 418477fb..19899a69 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java @@ -3,6 +3,7 @@ import io.f1.backend.domain.question.dto.QuestionRequest; import io.f1.backend.domain.quiz.entity.QuizType; +import io.f1.backend.global.validation.TrimmedSize; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -17,12 +18,14 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class QuizCreateRequest { + @TrimmedSize(min = 2, max = 30) @NotBlank(message = "퀴즈 제목을 설정해주세요.") private String title; @NotNull(message = "퀴즈 종류를 선택해주세요.") private QuizType quizType; + @TrimmedSize(min = 10, max = 50) @NotBlank(message = "퀴즈 설명을 적어주세요.") private String description; diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index ebcfc42e..114320b5 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -38,7 +38,7 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/oauth2/**", "/signup", "/css/**", - "/js/**") + "/js/**", "/**") .permitAll() .requestMatchers("/ws/**") .authenticated() diff --git a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java new file mode 100644 index 00000000..d91eeb57 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java @@ -0,0 +1,21 @@ +package io.f1.backend.global.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = TrimmedSizeValidator.class) +@Target({ ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface TrimmedSize { + + String message() default "공백 제외 길이가 {min}자 이상 {min}자 이하여야 합니다."; + + int min() default 0; + int max() default 50; + + Class[] groups() default {}; + Class[] payload() default {}; + +} diff --git a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java new file mode 100644 index 00000000..4dc2d944 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java @@ -0,0 +1,26 @@ +package io.f1.backend.global.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class TrimmedSizeValidator implements ConstraintValidator { + + private int min; + private int max; + + @Override + public void initialize(TrimmedSize constraintAnnotation) { + this.min = constraintAnnotation.min(); + this.max = constraintAnnotation.max(); + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if( value == null ) return true; + + String trimmed = value.trim(); + int length = trimmed.length(); + + return length >= min && length <= max; + } +} From ade451714433d0b4b40ee0f6e3e1f00d6e294757 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Tue, 15 Jul 2025 15:07:42 +0900 Subject: [PATCH 2/7] =?UTF-8?q?:wrench:=20chore=20:=20=EC=8B=9C=ED=81=90?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20=EC=9E=84=EC=8B=9C=20=ED=97=88=EC=9A=A9?= =?UTF-8?q?=ED=95=B4=EC=A4=AC=EB=8D=98=20=EA=B1=B0=20=EB=8B=A4=EC=8B=9C=20?= =?UTF-8?q?=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/global/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index 114320b5..ebcfc42e 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -38,7 +38,7 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/oauth2/**", "/signup", "/css/**", - "/js/**", "/**") + "/js/**") .permitAll() .requestMatchers("/ws/**") .authenticated() From 180d751ed4612a0fc35b2f39e7299ebf626afff8 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Tue, 15 Jul 2025 06:28:33 +0000 Subject: [PATCH 3/7] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80=EC=9D=BC?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question/api/QuestionController.java | 6 +++-- .../domain/question/app/QuestionService.java | 25 +++++++++++-------- .../domain/question/dto/QuestionRequest.java | 5 ++-- .../question/dto/QuestionUpdateRequest.java | 4 +-- .../backend/domain/quiz/app/QuizService.java | 2 +- .../domain/quiz/dto/QuizCreateRequest.java | 2 +- .../global/validation/TrimmedSize.java | 6 +++-- .../validation/TrimmedSizeValidator.java | 2 +- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java index cdaa8ffe..521783ce 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java +++ b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java @@ -2,7 +2,9 @@ import io.f1.backend.domain.question.app.QuestionService; import io.f1.backend.domain.question.dto.QuestionUpdateRequest; + import lombok.RequiredArgsConstructor; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -19,7 +21,8 @@ public class QuestionController { private final QuestionService questionService; @PutMapping("/{questionId}") - public ResponseEntity updateQuestion(@PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { + public ResponseEntity updateQuestion( + @PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { questionService.updateQuestion(questionId, request); return ResponseEntity.noContent().build(); @@ -31,5 +34,4 @@ public ResponseEntity deleteQuestion(@PathVariable Long questionId) { return ResponseEntity.noContent().build(); } - } diff --git a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java index d9f11d7b..0380d5d6 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java +++ b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java @@ -11,12 +11,13 @@ import io.f1.backend.domain.question.entity.TextQuestion; import io.f1.backend.domain.quiz.entity.Quiz; -import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.NoSuchElementException; + @Service @RequiredArgsConstructor public class QuestionService { @@ -39,41 +40,43 @@ public void saveQuestion(Quiz quiz, QuestionRequest request) { @Transactional public void updateQuestion(Long questionId, QuestionUpdateRequest request) { - Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + Question question = + questionRepository + .findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); TextQuestion textQuestion = question.getTextQuestion(); - if(request.content() != null) { + if (request.content() != null) { validateContent(request.content()); textQuestion.changeContent(request.content()); } - if(request.answer() != null) { + if (request.answer() != null) { validateAnswer(request.answer()); question.changeAnswer(request.answer()); } - } @Transactional public void deleteQuestion(Long questionId) { - Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + Question question = + questionRepository + .findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); questionRepository.delete(question); - } private void validateAnswer(String answer) { - if(answer.trim().length() < 5 || answer.trim().length() > 30) { + if (answer.trim().length() < 5 || answer.trim().length() > 30) { throw new IllegalArgumentException("정답은 1자 이상 30자 이하로 입력해주세요."); } } private void validateContent(String content) { - if(content.trim().length() < 5 || content.trim().length() > 30) { + if (content.trim().length() < 5 || content.trim().length() > 30) { throw new IllegalArgumentException("문제는 5자 이상 30자 이하로 입력해주세요."); } } diff --git a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java index c7cca216..4cdce5ff 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionRequest.java @@ -1,6 +1,7 @@ package io.f1.backend.domain.question.dto; import io.f1.backend.global.validation.TrimmedSize; + import jakarta.validation.constraints.NotBlank; import lombok.AccessLevel; @@ -11,11 +12,11 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class QuestionRequest { - @TrimmedSize(min=5, max=30) + @TrimmedSize(min = 5, max = 30) @NotBlank(message = "문제를 입력해주세요.") private String content; - @TrimmedSize(min=1, max=30) + @TrimmedSize(min = 1, max = 30) @NotBlank(message = "정답을 입력해주세요.") private String answer; } diff --git a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java index 5a428414..e77a3dea 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/question/dto/QuestionUpdateRequest.java @@ -1,5 +1,3 @@ package io.f1.backend.domain.question.dto; -public record QuestionUpdateRequest(String content, String answer) { - -} +public record QuestionUpdateRequest(String content, String answer) {} 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 95313859..39595093 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 @@ -151,7 +151,7 @@ public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateReque } private void validateDesc(String desc) { - if( desc.trim().length() < 10 || desc.trim().length() > 50) { + if (desc.trim().length() < 10 || desc.trim().length() > 50) { throw new IllegalArgumentException("설명은 10자 이상 50자 이하로 입력해주세요."); } } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java index 19899a69..313a519a 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/QuizCreateRequest.java @@ -2,8 +2,8 @@ import io.f1.backend.domain.question.dto.QuestionRequest; import io.f1.backend.domain.quiz.entity.QuizType; - import io.f1.backend.global.validation.TrimmedSize; + import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; diff --git a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java index d91eeb57..9b0d9fa9 100644 --- a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java +++ b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSize.java @@ -2,20 +2,22 @@ import jakarta.validation.Constraint; import jakarta.validation.Payload; + import java.lang.annotation.*; @Documented @Constraint(validatedBy = TrimmedSizeValidator.class) -@Target({ ElementType.FIELD, ElementType.PARAMETER }) +@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface TrimmedSize { String message() default "공백 제외 길이가 {min}자 이상 {min}자 이하여야 합니다."; int min() default 0; + int max() default 50; Class[] groups() default {}; - Class[] payload() default {}; + Class[] payload() default {}; } diff --git a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java index 4dc2d944..f3c32e99 100644 --- a/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java +++ b/backend/src/main/java/io/f1/backend/global/validation/TrimmedSizeValidator.java @@ -16,7 +16,7 @@ public void initialize(TrimmedSize constraintAnnotation) { @Override public boolean isValid(String value, ConstraintValidatorContext context) { - if( value == null ) return true; + if (value == null) return true; String trimmed = value.trim(); int length = trimmed.length(); From 668b2a790e45f59439657f2c8553f19159f3a6e9 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 11:24:37 +0900 Subject: [PATCH 4/7] =?UTF-8?q?:wrench:=20chore=20:=20=EC=B6=A9=EB=8F=8C?= =?UTF-8?q?=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question/api/QuestionController.java | 12 +++++++--- .../domain/question/app/QuestionService.java | 23 +++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java index 521783ce..556e1673 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java +++ b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java @@ -21,9 +21,15 @@ public class QuestionController { private final QuestionService questionService; @PutMapping("/{questionId}") - public ResponseEntity updateQuestion( - @PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { - questionService.updateQuestion(questionId, request); + public ResponseEntity updateQuestion(@PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { + + if(request.content()!=null) { + questionService.updateQuestionContent(questionId, request.content()); + } + + if(request.content()!=null) { + questionService.updateQuestionAnswer(questionId, request.answer()); + } return ResponseEntity.noContent().build(); } diff --git a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java index 0380d5d6..151c1900 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java +++ b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java @@ -38,7 +38,9 @@ public void saveQuestion(Quiz quiz, QuestionRequest request) { } @Transactional - public void updateQuestion(Long questionId, QuestionUpdateRequest request) { + public void updateQuestionContent(Long questionId, String content) { + + validateContent(content); Question question = questionRepository @@ -46,16 +48,19 @@ public void updateQuestion(Long questionId, QuestionUpdateRequest request) { .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); TextQuestion textQuestion = question.getTextQuestion(); + textQuestion.changeContent(content); + } - if (request.content() != null) { - validateContent(request.content()); - textQuestion.changeContent(request.content()); - } + @Transactional + public void updateQuestionAnswer(Long questionId, String answer) { + + validateAnswer(answer); + + Question question = questionRepository.findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + + question.changeAnswer(answer); - if (request.answer() != null) { - validateAnswer(request.answer()); - question.changeAnswer(request.answer()); - } } @Transactional From d9c5bc1825ea85aae17a647c098ba406b4aa8083 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 02:25:00 +0000 Subject: [PATCH 5/7] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80=EC=9D=BC?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/question/api/QuestionController.java | 7 ++++--- .../f1/backend/domain/question/app/QuestionService.java | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java index 556e1673..328ba7d9 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java +++ b/backend/src/main/java/io/f1/backend/domain/question/api/QuestionController.java @@ -21,13 +21,14 @@ public class QuestionController { private final QuestionService questionService; @PutMapping("/{questionId}") - public ResponseEntity updateQuestion(@PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { + public ResponseEntity updateQuestion( + @PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) { - if(request.content()!=null) { + if (request.content() != null) { questionService.updateQuestionContent(questionId, request.content()); } - if(request.content()!=null) { + if (request.content() != null) { questionService.updateQuestionAnswer(questionId, request.answer()); } diff --git a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java index 151c1900..6fc7c954 100644 --- a/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java +++ b/backend/src/main/java/io/f1/backend/domain/question/app/QuestionService.java @@ -6,7 +6,6 @@ import io.f1.backend.domain.question.dao.QuestionRepository; import io.f1.backend.domain.question.dao.TextQuestionRepository; import io.f1.backend.domain.question.dto.QuestionRequest; -import io.f1.backend.domain.question.dto.QuestionUpdateRequest; import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.question.entity.TextQuestion; import io.f1.backend.domain.quiz.entity.Quiz; @@ -56,11 +55,12 @@ public void updateQuestionAnswer(Long questionId, String answer) { validateAnswer(answer); - Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); + Question question = + questionRepository + .findById(questionId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 문제입니다.")); question.changeAnswer(answer); - } @Transactional From 648f970796f16fa44d6ab390d79d2324ce90eecb Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 12:04:14 +0900 Subject: [PATCH 6/7] =?UTF-8?q?:recycle:=20refactor=20:=20Quiz=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=8B=9C=EC=97=90=EB=8F=84=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC,=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=97=AD?= =?UTF-8?q?=ED=95=A0=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/api/QuizController.java | 12 ++++- .../backend/domain/quiz/app/QuizService.java | 49 ++++++++++++------- 2 files changed, 41 insertions(+), 20 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 64b4846e..16ff67b4 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 @@ -61,7 +61,17 @@ public ResponseEntity updateQuiz( @RequestPart QuizUpdateRequest request) throws IOException { - quizService.updateQuiz(quizId, thumbnailFile, request); + if (request.title() != null) { + quizService.updateQuizTitle(quizId, request.title()); + } + + if(request.description()!=null) { + quizService.updateQuizDesc(quizId, request.description()); + } + + if (thumbnailFile != null && !thumbnailFile.isEmpty()) { + quizService.updateThumbnail(quizId, thumbnailFile); + } return ResponseEntity.noContent().build(); } 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 39595093..1027757e 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 @@ -123,31 +123,42 @@ public void deleteQuiz(Long quizId) { } @Transactional - public void updateQuiz(Long quizId, MultipartFile thumbnailFile, QuizUpdateRequest request) - throws IOException { + public void updateQuizTitle(Long quizId, String title) { + Quiz quiz = + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + + validateTitle(title); + quiz.changeTitle(title); + } + + @Transactional + public void updateQuizDesc(Long quizId, String description) { Quiz quiz = - quizRepository - .findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); - if (request.title() != null) { - validateTitle(request.title()); - quiz.changeTitle(request.title()); - } + validateDesc(description); + quiz.changeDescription(description); - if (request.description() != null) { - validateDesc(request.description()); - quiz.changeDescription(request.description()); - } + } - if (thumbnailFile != null && !thumbnailFile.isEmpty()) { - validateImageFile(thumbnailFile); - String newThumbnailPath = convertToThumbnailPath(thumbnailFile); + @Transactional + public void updateThumbnail(Long quizId, MultipartFile thumbnailFile) throws IOException { - deleteThumbnailFile(quiz.getThumbnailUrl()); - quiz.changeThumbnailUrl(newThumbnailPath); - } + Quiz quiz = + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + + validateImageFile(thumbnailFile); + String newThumbnailPath = convertToThumbnailPath(thumbnailFile); + + deleteThumbnailFile(quiz.getThumbnailUrl()); + quiz.changeThumbnailUrl(newThumbnailPath); } private void validateDesc(String desc) { From 852c13af18e3bb4145123983a76d4660146dbd61 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 03:04:41 +0000 Subject: [PATCH 7/7] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80=EC=9D=BC?= =?UTF-8?q?=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 | 2 +- .../backend/domain/quiz/app/QuizService.java | 20 +++++++++---------- 2 files changed, 10 insertions(+), 12 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 16ff67b4..ee8d03a6 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 @@ -65,7 +65,7 @@ public ResponseEntity updateQuiz( quizService.updateQuizTitle(quizId, request.title()); } - if(request.description()!=null) { + if (request.description() != null) { quizService.updateQuizDesc(quizId, request.description()); } 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 1027757e..a74f0658 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 @@ -12,7 +12,6 @@ import io.f1.backend.domain.quiz.dto.QuizListPageResponse; import io.f1.backend.domain.quiz.dto.QuizListResponse; import io.f1.backend.domain.quiz.dto.QuizQuestionListResponse; -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; @@ -125,9 +124,9 @@ public void deleteQuiz(Long quizId) { @Transactional public void updateQuizTitle(Long quizId, String title) { Quiz quiz = - quizRepository - .findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); validateTitle(title); quiz.changeTitle(title); @@ -137,22 +136,21 @@ public void updateQuizTitle(Long quizId, String title) { public void updateQuizDesc(Long quizId, String description) { Quiz quiz = - quizRepository - .findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); validateDesc(description); quiz.changeDescription(description); - } @Transactional public void updateThumbnail(Long quizId, MultipartFile thumbnailFile) throws IOException { Quiz quiz = - quizRepository - .findById(quizId) - .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); validateImageFile(thumbnailFile); String newThumbnailPath = convertToThumbnailPath(thumbnailFile);