From bbbf81d94e420cb5f568b1d02f1ffaee94d04afd Mon Sep 17 00:00:00 2001 From: wonyangs Date: Fri, 26 Jul 2024 15:29:27 +0900 Subject: [PATCH 01/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=81=B4=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=EC=9E=A5=20=EC=83=9D=EC=84=B1=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=9D=B8=EC=9E=90=EA=B0=92=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 요청 형식에 맞지 않은 경우 400을 반환 --- build.gradle | 61 ++++++++++--------- .../dto/ClimbingGymCreateRequestDto.java | 11 +++- .../climbing/gym/domian/vo/Difficulty.java | 4 ++ .../ClimbingGymExceptionHandler.java | 18 ++++++ .../gym/ui/ClimbingGymController.java | 8 ++- 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/build.gradle b/build.gradle index 073f31b9..3022af19 100644 --- a/build.gradle +++ b/build.gradle @@ -1,48 +1,49 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.3.1' - id 'io.spring.dependency-management' version '1.1.5' + id 'java' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' } group = 'com.first' version = '0.0.1-SNAPSHOT' java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - - // db - runtimeOnly 'com.h2database:h2' - runtimeOnly 'com.mysql:mysql-connector-j' - - // QueryDSL Implementation - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" - annotationProcessor "jakarta.annotation:jakarta.annotation-api" - annotationProcessor "jakarta.persistence:jakarta.persistence-api" - - // generate UUID - implementation 'com.fasterxml.uuid:java-uuid-generator:5.1.0' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // db + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + + // QueryDSL Implementation + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + + // generate UUID + implementation 'com.fasterxml.uuid:java-uuid-generator:5.1.0' // db runtimeOnly 'com.h2database:h2' @@ -53,5 +54,5 @@ dependencies { } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } diff --git a/src/main/java/com/first/flash/climbing/gym/application/dto/ClimbingGymCreateRequestDto.java b/src/main/java/com/first/flash/climbing/gym/application/dto/ClimbingGymCreateRequestDto.java index 1103956f..e11f5b99 100644 --- a/src/main/java/com/first/flash/climbing/gym/application/dto/ClimbingGymCreateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/gym/application/dto/ClimbingGymCreateRequestDto.java @@ -2,10 +2,17 @@ import com.first.flash.climbing.gym.domian.ClimbingGym; import com.first.flash.climbing.gym.domian.vo.Difficulty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import java.util.List; -public record ClimbingGymCreateRequestDto(String gymName, String thumbnailUrl, String mapImageUrl, - List difficulties) { +public record ClimbingGymCreateRequestDto( + @NotEmpty(message = "클라이밍장 이름은 필수입니다.") String gymName, + @NotEmpty(message = "썸네일 URL은 필수입니다.") String thumbnailUrl, + @NotEmpty(message = "지도 이미지 URL은 필수입니다.") String mapImageUrl, + @NotEmpty(message = "난이도 정보는 최소 하나 이상이어야 합니다.") + List<@Valid @NotNull(message = "난이도 정보는 비어있을 수 없습니다.") Difficulty> difficulties) { public ClimbingGym toEntity() { return new ClimbingGym(gymName, thumbnailUrl, mapImageUrl, difficulties); diff --git a/src/main/java/com/first/flash/climbing/gym/domian/vo/Difficulty.java b/src/main/java/com/first/flash/climbing/gym/domian/vo/Difficulty.java index 74a1dfe2..92195570 100644 --- a/src/main/java/com/first/flash/climbing/gym/domian/vo/Difficulty.java +++ b/src/main/java/com/first/flash/climbing/gym/domian/vo/Difficulty.java @@ -1,6 +1,8 @@ package com.first.flash.climbing.gym.domian.vo; import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,7 +13,9 @@ @Getter public class Difficulty { + @NotEmpty(message = "난이도 이름은 필수입니다.") private String name; + @NotNull(message = "난이도 레벨은 필수입니다.") private Integer level; public Difficulty(final String name, final Integer level) { diff --git a/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java b/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java index 8a7627d5..bd4f64aa 100644 --- a/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java +++ b/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java @@ -3,8 +3,12 @@ import com.first.flash.climbing.gym.exception.exceptions.ClimbingGymNotFoundException; import com.first.flash.climbing.gym.exception.exceptions.DifficultyNotFoundException; import com.first.flash.climbing.gym.exception.exceptions.NoSectorGymException; +import java.util.HashMap; +import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -29,6 +33,20 @@ public ResponseEntity handleNoSectorGymException( return getResponseWithStatus(HttpStatus.NOT_FOUND, exception); } + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationExceptions( + MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + + ex.getBindingResult().getAllErrors().forEach(error -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errors); + } + private ResponseEntity getResponseWithStatus(final HttpStatus httpStatus, final RuntimeException exception) { return ResponseEntity.status(httpStatus) diff --git a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java index bb2b7841..77d27625 100644 --- a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java +++ b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java @@ -3,16 +3,18 @@ import com.first.flash.climbing.gym.application.ClimbingGymService; import com.first.flash.climbing.gym.application.dto.ClimbingGymCreateRequestDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymCreateResponseDto; -import com.first.flash.climbing.gym.application.dto.ClimbingGymResponseDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymDetailResponseDto; +import com.first.flash.climbing.gym.application.dto.ClimbingGymResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -24,6 +26,7 @@ @RestController @RequestMapping("/gyms") @RequiredArgsConstructor +@Validated public class ClimbingGymController { private final ClimbingGymService climbingGymService; @@ -41,10 +44,11 @@ public List getGyms() { @Operation(summary = "클라이밍장 생성", description = "새로운 클라이밍장 생성") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "성공적으로 클라이밍장을 생성함"), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식"), }) @PostMapping public ResponseEntity createGym( - @RequestBody final ClimbingGymCreateRequestDto gymCreateRequestDto) { + @Valid @RequestBody final ClimbingGymCreateRequestDto gymCreateRequestDto) { return ResponseEntity.status(HttpStatus.CREATED) .body(climbingGymService.save(gymCreateRequestDto)); } From 0fd199e76a51c260fd29690f4e53b2f6104dae2e Mon Sep 17 00:00:00 2001 From: wonyangs Date: Fri, 26 Jul 2024 17:21:07 +0900 Subject: [PATCH 02/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=81=B4=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=EC=9E=A5=20=EC=83=9D=EC=84=B1=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=82=9C=EC=9D=B4=EB=8F=84=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 난이도의 이름이나 값이 중복된 경우 400 반환 --- .../ClimbingGymExceptionHandler.java | 18 ++++++++++++-- .../DuplicateDifficultyLevelException.java | 8 +++++++ .../DuplicateDifficultyNameException.java | 8 +++++++ .../gym/ui/ClimbingGymController.java | 24 +++++++++++++++++-- 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyLevelException.java create mode 100644 src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyNameException.java diff --git a/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java b/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java index bd4f64aa..731cb3fd 100644 --- a/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java +++ b/src/main/java/com/first/flash/climbing/gym/exception/ClimbingGymExceptionHandler.java @@ -2,6 +2,8 @@ import com.first.flash.climbing.gym.exception.exceptions.ClimbingGymNotFoundException; import com.first.flash.climbing.gym.exception.exceptions.DifficultyNotFoundException; +import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyLevelException; +import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyNameException; import com.first.flash.climbing.gym.exception.exceptions.NoSectorGymException; import java.util.HashMap; import java.util.Map; @@ -35,10 +37,10 @@ public ResponseEntity handleNoSectorGymException( @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity> handleValidationExceptions( - MethodArgumentNotValidException ex) { + final MethodArgumentNotValidException exception) { Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach(error -> { + exception.getBindingResult().getAllErrors().forEach(error -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); @@ -47,6 +49,18 @@ public ResponseEntity> handleValidationExceptions( .body(errors); } + @ExceptionHandler(DuplicateDifficultyLevelException.class) + public ResponseEntity handleDuplicateDifficultyLevelException( + final DuplicateDifficultyLevelException exception) { + return getResponseWithStatus(HttpStatus.BAD_REQUEST, exception); + } + + @ExceptionHandler(DuplicateDifficultyNameException.class) + public ResponseEntity handleDuplicateDifficultyNameException( + final DuplicateDifficultyNameException exception) { + return getResponseWithStatus(HttpStatus.BAD_REQUEST, exception); + } + private ResponseEntity getResponseWithStatus(final HttpStatus httpStatus, final RuntimeException exception) { return ResponseEntity.status(httpStatus) diff --git a/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyLevelException.java b/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyLevelException.java new file mode 100644 index 00000000..877fe094 --- /dev/null +++ b/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyLevelException.java @@ -0,0 +1,8 @@ +package com.first.flash.climbing.gym.exception.exceptions; + +public class DuplicateDifficultyLevelException extends RuntimeException { + + public DuplicateDifficultyLevelException(final Integer difficultyLevel) { + super(String.format("난이도 레벨이 중복되었습니다: %d", difficultyLevel)); + } +} diff --git a/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyNameException.java b/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyNameException.java new file mode 100644 index 00000000..9d98d59b --- /dev/null +++ b/src/main/java/com/first/flash/climbing/gym/exception/exceptions/DuplicateDifficultyNameException.java @@ -0,0 +1,8 @@ +package com.first.flash.climbing.gym.exception.exceptions; + +public class DuplicateDifficultyNameException extends RuntimeException { + + public DuplicateDifficultyNameException(final String difficultyName) { + super(String.format("난이도 이름이 중복되었습니다: %s", difficultyName)); + } +} diff --git a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java index 77d27625..988f571b 100644 --- a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java +++ b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java @@ -5,16 +5,20 @@ import com.first.flash.climbing.gym.application.dto.ClimbingGymCreateResponseDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymDetailResponseDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymResponseDto; +import com.first.flash.climbing.gym.domian.vo.Difficulty; +import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyLevelException; +import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyNameException; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import java.util.HashSet; import java.util.List; +import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -26,7 +30,6 @@ @RestController @RequestMapping("/gyms") @RequiredArgsConstructor -@Validated public class ClimbingGymController { private final ClimbingGymService climbingGymService; @@ -49,10 +52,27 @@ public List getGyms() { @PostMapping public ResponseEntity createGym( @Valid @RequestBody final ClimbingGymCreateRequestDto gymCreateRequestDto) { + + validateDifficulties(gymCreateRequestDto.difficulties()); + return ResponseEntity.status(HttpStatus.CREATED) .body(climbingGymService.save(gymCreateRequestDto)); } + private void validateDifficulties(final List difficulties) { + Set names = new HashSet<>(); + Set levels = new HashSet<>(); + + for (Difficulty difficulty : difficulties) { + if (!names.add(difficulty.getName())) { + throw new DuplicateDifficultyNameException(difficulty.getName()); + } + if (!levels.add(difficulty.getLevel())) { + throw new DuplicateDifficultyLevelException(difficulty.getLevel()); + } + } + } + @Operation(summary = "클라이밍장 정보 조회", description = "특정 클라이밍장의 정보 조회") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공적으로 클라이밍장 정보를 조회함"), From 6229188a438e5b356b754ff27d5d4dfd6a76b92f Mon Sep 17 00:00:00 2001 From: wonyangs Date: Fri, 26 Jul 2024 18:14:38 +0900 Subject: [PATCH 03/22] =?UTF-8?q?FLASH-221=20chore:=20swagger=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../climbing/gym/ui/ClimbingGymController.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java index 988f571b..ddc81456 100644 --- a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java +++ b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java @@ -9,6 +9,9 @@ import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyLevelException; import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyNameException; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -46,8 +49,14 @@ public List getGyms() { @Operation(summary = "클라이밍장 생성", description = "새로운 클라이밍장 생성") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 클라이밍장을 생성함"), - @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식"), + @ApiResponse(responseCode = "201", description = "성공적으로 클라이밍장을 생성함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ClimbingGymCreateResponseDto.class))), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"gymName\": \"클라이밍장 이름은 필수입니다.\"}"), + @ExampleObject(name = "난이도 이름 중복", value = "{\"error\": \"난이도 이름이 중복되었습니다: 파랑\"}"), + @ExampleObject(name = "난이도 레벨 중복", value = "{\"error\": \"난이도 레벨이 중복되었습니다: 2\"}"), + })), }) @PostMapping public ResponseEntity createGym( From dc8b55095d66d0392bacb89e55206ff2fa6acfe8 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 15:18:01 +0900 Subject: [PATCH 04/22] =?UTF-8?q?FLASH-221=20chore:=20swagger=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 클라이밍장 조회 예시 추가 - 단일 클라이밍장 조회 예외 설명 추가 --- .../gym/ui/ClimbingGymController.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java index ddc81456..a98053a1 100644 --- a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java +++ b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java @@ -9,6 +9,7 @@ import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyLevelException; import com.first.flash.climbing.gym.exception.exceptions.DuplicateDifficultyNameException; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; @@ -39,7 +40,22 @@ public class ClimbingGymController { @Operation(summary = "모든 클라이밍장 조회", description = "모든 클라이밍장을 리스트로 반환") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "클라이밍장 리스트 조회 성공함") + @ApiResponse(responseCode = "200", description = "클라이밍장 리스트 조회 성공함", + content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ClimbingGymResponseDto.class)), + examples = @ExampleObject(value = """ + [ + { + "id": 1, + "gymName": "더클라임 논현", + "thumbnailUrl": "example_map_image1.jpeg" + }, + { + "id": 2, + "gymName": "더클라임 양재", + "thumbnailUrl": "example_map_image2.jpeg" + } + ] + """))), }) @GetMapping public List getGyms() { @@ -84,9 +100,16 @@ private void validateDifficulties(final List difficulties) { @Operation(summary = "클라이밍장 정보 조회", description = "특정 클라이밍장의 정보 조회") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 클라이밍장 정보를 조회함"), - @ApiResponse(responseCode = "404", description = "클라이밍장을 찾을 수 없음"), - @ApiResponse(responseCode = "404", description = "클라이밍장에 섹터가 없음") + @ApiResponse(responseCode = "200", description = "성공적으로 클라이밍장 정보를 조회함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ClimbingGymDetailResponseDto.class))), + @ApiResponse(responseCode = "404", description = "클라이밍장을 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}") + })), + @ApiResponse(responseCode = "404", description = "클라이밍장에 섹터가 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "섹터 없음", value = "{\"error\": \"아이디가 1인 클라이밍장엔 섹터가 존재하지 않습니다.\"}") + })) }) @GetMapping("/{gymId}") public ResponseEntity getGymDetails( From 262b9c83ad86548097bb409df897e37025c38685 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 15:53:56 +0900 Subject: [PATCH 05/22] =?UTF-8?q?FLASH-221=20feat:=20=EC=84=B9=ED=84=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=9A=94=EC=B2=AD=EA=B0=92=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gymId를 제외한 요청값 검증 추가 --- .../application/dto/SectorCreateRequestDto.java | 11 ++++++++--- .../climbing/sector/ui/SectorController.java | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorCreateRequestDto.java b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorCreateRequestDto.java index 05612c6f..7472783c 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorCreateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorCreateRequestDto.java @@ -1,8 +1,13 @@ package com.first.flash.climbing.sector.application.dto; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import java.time.LocalDate; -public record SectorCreateRequestDto(String name, String adminName, - LocalDate settingDate, LocalDate removalDate) { +public record SectorCreateRequestDto( + @NotEmpty(message = "섹터 이름은 필수입니다.") String name, + @NotEmpty(message = "섹터 관리 이름은 필수입니다.") String adminName, + @NotNull(message = "세팅일 정보는 비어있을 수 없습니다.") LocalDate settingDate, + LocalDate removalDate) { -} +} \ No newline at end of file diff --git a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java index 9faef744..d882cb9d 100644 --- a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java +++ b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java @@ -2,14 +2,18 @@ import com.first.flash.climbing.sector.application.SectorService; import com.first.flash.climbing.sector.application.dto.SectorCreateRequestDto; +import com.first.flash.climbing.sector.application.dto.SectorDetailResponseDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRemovalDateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRequestDto; -import com.first.flash.climbing.sector.application.dto.SectorDetailResponseDto; import com.first.flash.climbing.sector.application.dto.SectorsDetailResponseDto; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -41,12 +45,17 @@ public ResponseEntity findAllSectors() { @Operation(summary = "섹터 갱신(생성)", description = "특정 클라이밍장에 새로운 섹터 생성") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 섹터를 생성함"), - @ApiResponse(responseCode = "400", description = "탈거일이 세팅일보다 빠름") + @ApiResponse(responseCode = "201", description = "성공적으로 섹터를 생성함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SectorDetailResponseDto.class))), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"name\": \"섹터 이름은 필수입니다.\"}"), + @ExampleObject(name = "탈거일이 세팅일보다 빠름", value = "{\"error\": \"탈거일이 세팅일보다 빠를 수 없습니다.\"}") + })), }) @PostMapping("gyms/{gymId}/sectors") public ResponseEntity createSector(@PathVariable final Long gymId, - @RequestBody final SectorCreateRequestDto sectorCreateRequestDto) { + @Valid @RequestBody final SectorCreateRequestDto sectorCreateRequestDto) { return ResponseEntity.status(HttpStatus.CREATED) .body(sectorService.saveSector(gymId, sectorCreateRequestDto)); } From 151979ca935ec1b3627feff88b6b6792940c263d Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 16:30:41 +0900 Subject: [PATCH 06/22] =?UTF-8?q?FLASH-221=20feat:=20=EC=84=B9=ED=84=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20gymId=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Event를 이용하여 해당 클라이밍장 id가 있는지 검증 - 없을 시 404 반환 - swagger 설명 추가 --- .../application/ClimbingGymEventHandler.java | 19 +++++++++++++++++++ .../sector/application/SectorService.java | 6 +++++- .../sector/domain/SectorCreatedEvent.java | 15 +++++++++++++++ .../climbing/sector/ui/SectorController.java | 4 ++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java create mode 100644 src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java diff --git a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java new file mode 100644 index 00000000..8b95e5a2 --- /dev/null +++ b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java @@ -0,0 +1,19 @@ +package com.first.flash.climbing.gym.application; + +import com.first.flash.climbing.sector.domain.SectorCreatedEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ClimbingGymEventHandler { + + private final ClimbingGymService gymService; + + @EventListener + public void validGymId(final SectorCreatedEvent event) { + gymService.findClimbingGymById(event.getGymId()); + } + +} diff --git a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java index 527ff9b5..e46d32b3 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java +++ b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java @@ -1,11 +1,12 @@ package com.first.flash.climbing.sector.application; import com.first.flash.climbing.sector.application.dto.SectorCreateRequestDto; -import com.first.flash.climbing.sector.application.dto.SectorUpdateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorDetailResponseDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRemovalDateRequestDto; +import com.first.flash.climbing.sector.application.dto.SectorUpdateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorsDetailResponseDto; import com.first.flash.climbing.sector.domain.Sector; +import com.first.flash.climbing.sector.domain.SectorCreatedEvent; import com.first.flash.climbing.sector.domain.SectorExpiredEvent; import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; import com.first.flash.climbing.sector.domain.SectorRemovalDateUpdatedEvent; @@ -29,7 +30,10 @@ public class SectorService { @Transactional public SectorDetailResponseDto saveSector(final Long gymId, final SectorCreateRequestDto createRequestDto) { + Sector sector = createSectorByDto(gymId, createRequestDto); + Events.raise(new SectorCreatedEvent(gymId)); + return SectorDetailResponseDto.toDto(sectorRepository.save(sector)); } diff --git a/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java b/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java new file mode 100644 index 00000000..2e649b08 --- /dev/null +++ b/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java @@ -0,0 +1,15 @@ +package com.first.flash.climbing.sector.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class SectorCreatedEvent { + + private Long gymId; + + public static SectorCreatedEvent of(final Long gymId) { + return new SectorCreatedEvent(gymId); + } +} diff --git a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java index d882cb9d..00282d59 100644 --- a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java +++ b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java @@ -52,6 +52,10 @@ public ResponseEntity findAllSectors() { @ExampleObject(name = "요청값 누락", value = "{\"name\": \"섹터 이름은 필수입니다.\"}"), @ExampleObject(name = "탈거일이 세팅일보다 빠름", value = "{\"error\": \"탈거일이 세팅일보다 빠를 수 없습니다.\"}") })), + @ApiResponse(responseCode = "404", description = "클라이밍장을 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}") + })) }) @PostMapping("gyms/{gymId}/sectors") public ResponseEntity createSector(@PathVariable final Long gymId, From 5a30da3967b61be0609d36278319c80f5ff6716e Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 17:04:48 +0900 Subject: [PATCH 07/22] =?UTF-8?q?FLASH-221=20feat:=20=EC=84=B9=ED=84=B0=20?= =?UTF-8?q?=ED=83=88=EA=B1=B0=EC=9D=BC=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B0=92=20=EB=88=84=EB=9D=BD=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SectorUpdateRemovalDateRequestDto.java | 4 +++- .../climbing/sector/ui/SectorController.java | 22 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRemovalDateRequestDto.java b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRemovalDateRequestDto.java index 3517f4ff..9b200edf 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRemovalDateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRemovalDateRequestDto.java @@ -1,7 +1,9 @@ package com.first.flash.climbing.sector.application.dto; +import jakarta.validation.constraints.NotNull; import java.time.LocalDate; -public record SectorUpdateRemovalDateRequestDto(LocalDate removalDate) { +public record SectorUpdateRemovalDateRequestDto( + @NotNull(message = "탈거일 수정 시 탈거일 정보는 비어있을 수 없습니다.") LocalDate removalDate) { } diff --git a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java index 00282d59..68619bab 100644 --- a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java +++ b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java @@ -34,9 +34,10 @@ public class SectorController { private final SectorService sectorService; - @Operation(summary = "섹터 전체 조회", description = "모든 섹터의 정보를 반환") + @Operation(summary = "모든 섹터 조회", description = "모든 섹터 정보를 리스트로 반환") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 섹터를 조회"), + @ApiResponse(responseCode = "200", description = "성공적으로 섹터를 조회", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SectorsDetailResponseDto.class))), }) @GetMapping("sectors") public ResponseEntity findAllSectors() { @@ -64,16 +65,23 @@ public ResponseEntity createSector(@PathVariable final .body(sectorService.saveSector(gymId, sectorCreateRequestDto)); } - @Operation(summary = "섹터 탈거일 수정", description = "특정 섹터의 탈거일 수정") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 섹터 탈거일을 수정함"), - @ApiResponse(responseCode = "400", description = "탈거일이 세팅일보다 빠름"), - @ApiResponse(responseCode = "404", description = "섹터를 찾을 수 없음") + @ApiResponse(responseCode = "200", description = "성공적으로 섹터 탈거일을 수정함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SectorDetailResponseDto.class))), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"name\": \"탈거일 수정 시 탈거일 정보는 비어있을 수 없습니다.\"}"), + @ExampleObject(name = "탈거일이 세팅일보다 빠름", value = "{\"error\": \"탈거일이 세팅일보다 빠를 수 없습니다.\"}") + })), + @ApiResponse(responseCode = "404", description = "섹터를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "섹터 없음", value = "{\"error\": \"아이디가 1인 섹터를 찾을 수 없습니다.\"}") + })) }) @PatchMapping("sectors/{sectorId}") public ResponseEntity updateSectorRemovalDate( @PathVariable final Long sectorId, - @RequestBody final SectorUpdateRemovalDateRequestDto sectorUpdateRemovalDateRequestDto) { + @Valid @RequestBody final SectorUpdateRemovalDateRequestDto sectorUpdateRemovalDateRequestDto) { SectorDetailResponseDto response = sectorService.updateSectorRemovalDate( sectorId, sectorUpdateRemovalDateRequestDto); return ResponseEntity.ok(response); From f7e463cfb7103400687f93bacb39bfc05dd3afc8 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 17:44:10 +0900 Subject: [PATCH 08/22] =?UTF-8?q?FLASH-221=20feat:=20=EC=84=B9=ED=84=B0=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/dto/SectorUpdateRequestDto.java | 12 +++++++++--- .../climbing/sector/ui/SectorController.java | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRequestDto.java b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRequestDto.java index 415ee569..ec0a810d 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/sector/application/dto/SectorUpdateRequestDto.java @@ -1,13 +1,19 @@ package com.first.flash.climbing.sector.application.dto; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import java.time.LocalDate; -public record SectorUpdateRequestDto(String sectorName, String adminSectorName, LocalDate settingDate, - LocalDate removalDate, Long gymId) { +public record SectorUpdateRequestDto( + @NotEmpty(message = "섹터 이름은 필수입니다.") String sectorName, + @NotEmpty(message = "섹터 관리 이름은 필수입니다.") String adminSectorName, + @NotNull(message = "세팅일 정보는 비어있을 수 없습니다.") LocalDate settingDate, + @NotNull(message = "탈거일 정보는 비어있을 수 없습니다.") LocalDate removalDate, + @NotNull(message = "클라이밍장 ID는 비어있을 수 없습니다.") Long gymId) { public static SectorUpdateRequestDto of(final String sectorName, final String adminSectorName, final LocalDate settingDate, final LocalDate removalDate, final Long gymId) { return new SectorUpdateRequestDto(sectorName, adminSectorName, settingDate, removalDate, gymId); } -} +} \ No newline at end of file diff --git a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java index 68619bab..bd5a7eb7 100644 --- a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java +++ b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java @@ -89,12 +89,23 @@ public ResponseEntity updateSectorRemovalDate( @Operation(summary = "섹터 전체 수정", description = "특정 섹터의 정보 수정") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 섹터 정보 수정함"), + @ApiResponse(responseCode = "200", description = "성공적으로 섹터 정보 수정함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SectorDetailResponseDto.class))), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"name\": \"섹터 이름은 필수입니다.\"}"), + @ExampleObject(name = "탈거일이 세팅일보다 빠름", value = "{\"error\": \"탈거일이 세팅일보다 빠를 수 없습니다.\"}") + })), + @ApiResponse(responseCode = "404", description = "리소스를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "섹터 없음", value = "{\"error\": \"아이디가 1인 섹터를 찾을 수 없습니다.\"}"), + @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}") + })) }) @PutMapping("sectors/{sectorId}") public ResponseEntity updateSector( @PathVariable final Long sectorId, - @RequestBody final SectorUpdateRequestDto updateRequestDto) { + @Valid @RequestBody final SectorUpdateRequestDto updateRequestDto) { return ResponseEntity.ok(sectorService.updateSector(sectorId, updateRequestDto)); } } From b4acc5756e8b8c2421e3692b8073089d124a74ea Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 18:06:09 +0900 Subject: [PATCH 09/22] =?UTF-8?q?FLASH-221=20feat:=20=EC=84=B9=ED=84=B0=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20=ED=81=B4?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B0=8D=EC=9E=A5=20id=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gym/application/ClimbingGymEventHandler.java | 13 +++++++++++-- .../climbing/sector/application/SectorService.java | 2 +- .../sector/domain/SectorInfoUpdatedEvent.java | 5 +++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java index 8b95e5a2..805a27c7 100644 --- a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java +++ b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java @@ -1,6 +1,7 @@ package com.first.flash.climbing.gym.application; import com.first.flash.climbing.sector.domain.SectorCreatedEvent; +import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -12,8 +13,16 @@ public class ClimbingGymEventHandler { private final ClimbingGymService gymService; @EventListener - public void validGymId(final SectorCreatedEvent event) { - gymService.findClimbingGymById(event.getGymId()); + public void handleSectorCreatedEvent(final SectorCreatedEvent event) { + validateGymId(event.getGymId()); } + @EventListener + public void handleSectorInfoUpdatedEvent(final SectorInfoUpdatedEvent event) { + validateGymId(event.getGymId()); + } + + private void validateGymId(Long gymId) { + gymService.findClimbingGymById(gymId); + } } diff --git a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java index e46d32b3..14476d98 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java +++ b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java @@ -62,7 +62,7 @@ public SectorDetailResponseDto updateSector( updateRequestDto.settingDate(), updateRequestDto.removalDate(), updateRequestDto.gymId()); Events.raise(SectorInfoUpdatedEvent.of(foundSector.getId(), updateRequestDto.sectorName(), - updateRequestDto.settingDate())); + updateRequestDto.settingDate(), updateRequestDto.gymId())); return SectorDetailResponseDto.toDto(foundSector); } diff --git a/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java b/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java index cdcf1dc2..f6ad914b 100644 --- a/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java +++ b/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java @@ -11,9 +11,10 @@ public class SectorInfoUpdatedEvent { private Long id; private String sectorName; private LocalDate settingDate; + private Long gymId; public static SectorInfoUpdatedEvent of(final Long id, final String sectorName, - final LocalDate settingDate) { - return new SectorInfoUpdatedEvent(id, sectorName, settingDate); + final LocalDate settingDate, final Long gymId) { + return new SectorInfoUpdatedEvent(id, sectorName, settingDate, gymId); } } From a7abe57d48a7e7693ac04119b894e25961e17e2b Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 18:08:33 +0900 Subject: [PATCH 10/22] =?UTF-8?q?FLASH-221=20chore:=20swagger=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/first/flash/climbing/sector/ui/SectorController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java index bd5a7eb7..a61f88cd 100644 --- a/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java +++ b/src/main/java/com/first/flash/climbing/sector/ui/SectorController.java @@ -65,6 +65,7 @@ public ResponseEntity createSector(@PathVariable final .body(sectorService.saveSector(gymId, sectorCreateRequestDto)); } + @Operation(summary = "섹터 탈거일 수정", description = "특정 섹터의 탈거일 정보 수정") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공적으로 섹터 탈거일을 수정함", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SectorDetailResponseDto.class))), From 9908b853e70ce3f716e7e9aa8922bed5bb3665e7 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Tue, 30 Jul 2024 18:55:03 +0900 Subject: [PATCH 11/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=81=B4=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=EC=9E=A5=EC=97=90=20=EC=84=B9=ED=84=B0?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20404=20?= =?UTF-8?q?=EB=8C=80=EC=8B=A0=20=EB=B9=88=20=EB=B0=B0=EC=97=B4=EC=9D=84=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../climbing/gym/application/ClimbingGymService.java | 9 ++------- .../flash/climbing/gym/ui/ClimbingGymController.java | 4 ---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymService.java b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymService.java index 3101f7ea..fef2a0c6 100644 --- a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymService.java +++ b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymService.java @@ -2,13 +2,12 @@ import com.first.flash.climbing.gym.application.dto.ClimbingGymCreateRequestDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymCreateResponseDto; -import com.first.flash.climbing.gym.application.dto.ClimbingGymResponseDto; import com.first.flash.climbing.gym.application.dto.ClimbingGymDetailResponseDto; +import com.first.flash.climbing.gym.application.dto.ClimbingGymResponseDto; import com.first.flash.climbing.gym.domian.ClimbingGym; import com.first.flash.climbing.gym.domian.ClimbingGymRepository; import com.first.flash.climbing.gym.domian.vo.Difficulty; import com.first.flash.climbing.gym.exception.exceptions.ClimbingGymNotFoundException; -import com.first.flash.climbing.gym.exception.exceptions.NoSectorGymException; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -47,11 +46,7 @@ public ClimbingGymDetailResponseDto findClimbingGymDetail(final Long id) { } private List findSectorNamesById(final Long id) { - List sectorNames = climbingGymRepository.findGymSectorNamesById(id); - if (sectorNames.isEmpty()) { - throw new NoSectorGymException(id); - } - return sectorNames; + return climbingGymRepository.findGymSectorNamesById(id); } private List getDifficultyNames(final ClimbingGym climbingGym) { diff --git a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java index a98053a1..3444ecb0 100644 --- a/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java +++ b/src/main/java/com/first/flash/climbing/gym/ui/ClimbingGymController.java @@ -105,10 +105,6 @@ private void validateDifficulties(final List difficulties) { @ApiResponse(responseCode = "404", description = "클라이밍장을 찾을 수 없음", content = @Content(mediaType = "application/json", examples = { @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}") - })), - @ApiResponse(responseCode = "404", description = "클라이밍장에 섹터가 없음", - content = @Content(mediaType = "application/json", examples = { - @ExampleObject(name = "섹터 없음", value = "{\"error\": \"아이디가 1인 클라이밍장엔 섹터가 존재하지 않습니다.\"}") })) }) @GetMapping("/{gymId}") From 5d477b5ee1f6b1e953061cfd10825f0bf32ce671 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 14:39:41 +0900 Subject: [PATCH 12/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=95=B4=EC=84=A4?= =?UTF-8?q?=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=A0=20=EB=95=8C=20=EC=A0=81?= =?UTF-8?q?=EC=A0=88=ED=95=9C=20problemId=EA=B0=80=20=EC=95=84=EB=8B=8C=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20404=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - problemId를 검증하는 Event 추가 - swagger 설명 추가 --- .../application/ProblemEventHandler.java | 8 ++++++++ .../problem/domain/ProblemIdConfirmEvent.java | 17 +++++++++++++++++ .../solution/application/SolutionService.java | 4 ++++ .../solution/ui/SolutionController.java | 19 +++++++++++++------ 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java diff --git a/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java b/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java index c4a6bee7..4a2a9f55 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java +++ b/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java @@ -1,5 +1,6 @@ package com.first.flash.climbing.problem.application; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; import com.first.flash.climbing.sector.domain.SectorExpiredEvent; import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; import com.first.flash.climbing.sector.domain.SectorRemovalDateUpdatedEvent; @@ -14,6 +15,7 @@ public class ProblemEventHandler { private final ProblemsService problemsService; + private final ProblemReadService problemReadService; @EventListener @Transactional @@ -39,4 +41,10 @@ public void updateQueryProblemInfo(final SectorInfoUpdatedEvent event) { problemsService.updateQueryProblemInfo(event.getId(), event.getSectorName(), event.getSettingDate()); } + + @EventListener + @Transactional + public void confirmProblemId(final ProblemIdConfirmEvent event) { + problemReadService.findProblemById(event.getProblemId()); + } } diff --git a/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java b/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java new file mode 100644 index 00000000..057cd225 --- /dev/null +++ b/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java @@ -0,0 +1,17 @@ +package com.first.flash.climbing.problem.domain; + +import com.first.flash.global.event.Event; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ProblemIdConfirmEvent extends Event { + + private final UUID problemId; + + public static ProblemIdConfirmEvent of(final UUID problemId) { + return new ProblemIdConfirmEvent(problemId); + } +} diff --git a/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java b/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java index deab135e..024bdcdd 100644 --- a/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java +++ b/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java @@ -1,5 +1,6 @@ package com.first.flash.climbing.solution.application; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; import com.first.flash.climbing.solution.application.dto.SolutionMetaResponseDto; import com.first.flash.climbing.solution.application.dto.SolutionResponseDto; import com.first.flash.climbing.solution.application.dto.SolutionsResponseDto; @@ -37,10 +38,13 @@ public Solution findSolutionById(final Long id) { } public SolutionsResponseDto findAllSolutionsByProblemId(final UUID problemId) { + Events.raise(ProblemIdConfirmEvent.of(problemId)); + List solutions = solutionRepository.findAllByProblemId(problemId) .stream() .map(SolutionResponseDto::toDto) .toList(); + return new SolutionsResponseDto(solutions, new SolutionMetaResponseDto(solutions.size())); } } diff --git a/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java b/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java index b99cb1ff..cc7bb18a 100644 --- a/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java +++ b/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java @@ -5,6 +5,9 @@ import com.first.flash.climbing.solution.application.dto.SolutionsResponseDto; import com.first.flash.climbing.solution.domain.dto.SolutionCreateRequestDto; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,7 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "solutions", description = "해설 영상 관리 API") +@Tag(name = "solutions", description = "해설 관리 API") @RestController @RequestMapping @RequiredArgsConstructor @@ -27,10 +30,14 @@ public class SolutionController { private final SolutionService solutionService; - @Operation(summary = "해설 영상 조회", description = "특정 문제에 대한 해설 영상 조회") + @Operation(summary = "해설 조회", description = "특정 문제에 대한 해설 조회") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 해설 영상을 조회함"), - @ApiResponse(responseCode = "404", description = "해설을 찾을 수 없음") + @ApiResponse(responseCode = "200", description = "성공적으로 해설을 조회함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SolutionsResponseDto.class))), + @ApiResponse(responseCode = "404", description = "문제를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "문제 없음", value = "{\"error\": \"아이디가 0190c558-9063-7050-b4fc-eb421e3236b3인 문제를 찾을 수 없습니다.\"}") + })) }) @GetMapping("problems/{problemId}/solutions") public ResponseEntity getSolutions(@PathVariable final UUID problemId) { @@ -40,9 +47,9 @@ public ResponseEntity getSolutions(@PathVariable final UUI return ResponseEntity.ok(response); } - @Operation(summary = "해설 영상 업로드", description = "특정 문제에 대한 해설 영상 업로드") + @Operation(summary = "해설 업로드", description = "특정 문제에 대한 해설 업로드") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 해설 영상을 업로드함") + @ApiResponse(responseCode = "201", description = "성공적으로 해설을 업로드함") }) @PostMapping("problems/{problemId}/solutions") public ResponseEntity createSolution(@PathVariable final UUID problemId, From 562fbad3324674d20498a2eec225e6efebd6466e Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 15:23:02 +0900 Subject: [PATCH 13/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=95=B4=EC=84=A4=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=8B=9C=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 요청값 누락 시 400 - 문제가 잘못됐을 시 404 --- .../domain/dto/SolutionCreateRequestDto.java | 12 ++++++++++-- .../climbing/solution/ui/SolutionController.java | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java b/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java index 186f196c..ce88b832 100644 --- a/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java @@ -1,6 +1,14 @@ package com.first.flash.climbing.solution.domain.dto; -public record SolutionCreateRequestDto(String videoUrl, String uploader, String review, - String instagramId) { +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +public record SolutionCreateRequestDto( + @NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl, + @NotEmpty(message = "업로더 정보는 필수입니다.") String uploader, + @NotNull(message = "리뷰 항목은 필수입니다.") + @Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review, + @NotEmpty(message = "인스타그램 ID는 필수입니다.") String instagramId) { } diff --git a/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java b/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java index cc7bb18a..9dc788bd 100644 --- a/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java +++ b/src/main/java/com/first/flash/climbing/solution/ui/SolutionController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -49,11 +50,20 @@ public ResponseEntity getSolutions(@PathVariable final UUI @Operation(summary = "해설 업로드", description = "특정 문제에 대한 해설 업로드") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 해설을 업로드함") + @ApiResponse(responseCode = "201", description = "성공적으로 해설을 업로드함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = SolutionResponseDto.class))), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"uploader\": \"업로더 정보는 필수입니다.\"}"), + })), + @ApiResponse(responseCode = "404", description = "문제를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "문제 없음", value = "{\"error\": \"아이디가 0190c558-9063-7050-b4fc-eb421e3236b3인 문제를 찾을 수 없습니다.\"}") + })) }) @PostMapping("problems/{problemId}/solutions") public ResponseEntity createSolution(@PathVariable final UUID problemId, - @RequestBody final SolutionCreateRequestDto solutionCreateRequestDto) { + @Valid @RequestBody final SolutionCreateRequestDto solutionCreateRequestDto) { return ResponseEntity.status(HttpStatus.CREATED) .body( From 5be7956d8c18c769c90053402b1fb224b229b864 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 15:47:01 +0900 Subject: [PATCH 14/22] =?UTF-8?q?FLASH-221=20refactor:=20gymId=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=EC=9D=84=20gym=20=EC=95=A0?= =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EA=B1=B0=ED=8A=B8=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=98=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 --- .../application/ClimbingGymEventHandler.java | 18 +++++------------- .../gym/domian/ClimbingGymIdConfirmEvent.java | 16 ++++++++++++++++ .../sector/application/SectorService.java | 7 ++++--- .../sector/domain/SectorCreatedEvent.java | 15 --------------- .../sector/domain/SectorInfoUpdatedEvent.java | 5 ++--- 5 files changed, 27 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java delete mode 100644 src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java diff --git a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java index 805a27c7..d063a1a6 100644 --- a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java +++ b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java @@ -1,10 +1,10 @@ package com.first.flash.climbing.gym.application; -import com.first.flash.climbing.sector.domain.SectorCreatedEvent; -import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; @Component @RequiredArgsConstructor @@ -13,16 +13,8 @@ public class ClimbingGymEventHandler { private final ClimbingGymService gymService; @EventListener - public void handleSectorCreatedEvent(final SectorCreatedEvent event) { - validateGymId(event.getGymId()); - } - - @EventListener - public void handleSectorInfoUpdatedEvent(final SectorInfoUpdatedEvent event) { - validateGymId(event.getGymId()); - } - - private void validateGymId(Long gymId) { - gymService.findClimbingGymById(gymId); + @Transactional + public void confirmGymId(final ClimbingGymIdConfirmEvent event) { + gymService.findClimbingGymById(event.getGymId()); } } diff --git a/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java b/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java new file mode 100644 index 00000000..cf5c9117 --- /dev/null +++ b/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java @@ -0,0 +1,16 @@ +package com.first.flash.climbing.gym.domian; + +import com.first.flash.global.event.Event; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ClimbingGymIdConfirmEvent extends Event { + + private final Long gymId; + + public static ClimbingGymIdConfirmEvent of(final Long gymId) { + return new ClimbingGymIdConfirmEvent(gymId); + } +} diff --git a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java index 14476d98..273aa87b 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java +++ b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java @@ -1,12 +1,12 @@ package com.first.flash.climbing.sector.application; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; import com.first.flash.climbing.sector.application.dto.SectorCreateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorDetailResponseDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRemovalDateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorsDetailResponseDto; import com.first.flash.climbing.sector.domain.Sector; -import com.first.flash.climbing.sector.domain.SectorCreatedEvent; import com.first.flash.climbing.sector.domain.SectorExpiredEvent; import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; import com.first.flash.climbing.sector.domain.SectorRemovalDateUpdatedEvent; @@ -32,7 +32,7 @@ public SectorDetailResponseDto saveSector(final Long gymId, final SectorCreateRequestDto createRequestDto) { Sector sector = createSectorByDto(gymId, createRequestDto); - Events.raise(new SectorCreatedEvent(gymId)); + Events.raise(new ClimbingGymIdConfirmEvent(gymId)); return SectorDetailResponseDto.toDto(sectorRepository.save(sector)); } @@ -62,7 +62,8 @@ public SectorDetailResponseDto updateSector( updateRequestDto.settingDate(), updateRequestDto.removalDate(), updateRequestDto.gymId()); Events.raise(SectorInfoUpdatedEvent.of(foundSector.getId(), updateRequestDto.sectorName(), - updateRequestDto.settingDate(), updateRequestDto.gymId())); + updateRequestDto.settingDate())); + Events.raise(ClimbingGymIdConfirmEvent.of(updateRequestDto.gymId())); return SectorDetailResponseDto.toDto(foundSector); } diff --git a/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java b/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java deleted file mode 100644 index 2e649b08..00000000 --- a/src/main/java/com/first/flash/climbing/sector/domain/SectorCreatedEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.first.flash.climbing.sector.domain; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class SectorCreatedEvent { - - private Long gymId; - - public static SectorCreatedEvent of(final Long gymId) { - return new SectorCreatedEvent(gymId); - } -} diff --git a/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java b/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java index f6ad914b..cdcf1dc2 100644 --- a/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java +++ b/src/main/java/com/first/flash/climbing/sector/domain/SectorInfoUpdatedEvent.java @@ -11,10 +11,9 @@ public class SectorInfoUpdatedEvent { private Long id; private String sectorName; private LocalDate settingDate; - private Long gymId; public static SectorInfoUpdatedEvent of(final Long id, final String sectorName, - final LocalDate settingDate, final Long gymId) { - return new SectorInfoUpdatedEvent(id, sectorName, settingDate, gymId); + final LocalDate settingDate) { + return new SectorInfoUpdatedEvent(id, sectorName, settingDate); } } From 5587d5dc09980cfab6d910bd3d9117c768b1f3e7 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 17:28:52 +0900 Subject: [PATCH 15/22] =?UTF-8?q?FLASH-221=20feat:=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=97=90=20id=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/ProblemReadService.java | 8 ++++++ .../problem/ui/ProblemController.java | 25 +++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java index 83a995b9..50595c9e 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java +++ b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java @@ -3,9 +3,11 @@ import static com.first.flash.climbing.problem.infrastructure.paging.SortBy.DIFFICULTY; import static com.first.flash.climbing.problem.infrastructure.paging.SortBy.VIEWS; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; import com.first.flash.climbing.problem.application.dto.ProblemDetailResponseDto; import com.first.flash.climbing.problem.application.dto.ProblemsResponseDto; import com.first.flash.climbing.problem.domain.Problem; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; import com.first.flash.climbing.problem.domain.ProblemRepository; import com.first.flash.climbing.problem.domain.QueryProblem; import com.first.flash.climbing.problem.domain.QueryProblemRepository; @@ -14,6 +16,7 @@ import com.first.flash.climbing.problem.exception.exceptions.QueryProblemNotFoundException; import com.first.flash.climbing.problem.infrastructure.paging.Cursor; import com.first.flash.climbing.problem.infrastructure.paging.SortBy; +import com.first.flash.global.event.Events; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -34,6 +37,8 @@ public ProblemsResponseDto findAll(final Long gymId, final String cursor, Cursor prevCursor = Cursor.decode(cursor); SortBy sortBy = SortBy.from(sortByRequest); + Events.raise(ClimbingGymIdConfirmEvent.of(gymId)); + List queryProblems = queryProblemRepository.findAll(prevCursor, sortBy, size, gymId, difficulty, sector, hasSolution); String nextCursor = getNextCursor(sortBy, size, queryProblems); @@ -42,11 +47,14 @@ public ProblemsResponseDto findAll(final Long gymId, final String cursor, @Transactional public ProblemDetailResponseDto viewProblems(final UUID problemId) { + Events.raise(ProblemIdConfirmEvent.of(problemId)); + QueryProblem queryProblem = findQueryProblemById(problemId); Problem problem = findProblemById(problemId); validateExpiration(problem, queryProblem); problem.view(); queryProblem.view(); + return ProblemDetailResponseDto.of(queryProblem); } diff --git a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java index 64af43f3..e322c7be 100644 --- a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java +++ b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java @@ -7,8 +7,12 @@ import com.first.flash.climbing.problem.application.dto.ProblemsResponseDto; import com.first.flash.climbing.problem.domain.dto.ProblemCreateRequestDto; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -21,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "problems", description = "문제 관리 API") @RestController @RequiredArgsConstructor public class ProblemController { @@ -31,9 +36,9 @@ public class ProblemController { private final ProblemsSaveService problemsSaveService; private final ProblemReadService problemReadService; - @Operation(summary = "문제 저장", description = "특정 섹터에 문제 저장") + @Operation(summary = "문제 생성", description = "특정 섹터에 문제 생성") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 문제 저장함"), + @ApiResponse(responseCode = "201", description = "성공적으로 문제 생성함"), }) @PostMapping("/gyms/{gymId}/sectors/{sectorId}/problems") public ResponseEntity saveProblems( @@ -41,12 +46,17 @@ public ResponseEntity saveProblems( @PathVariable("sectorId") final Long sectorId, @RequestBody final ProblemCreateRequestDto requestDto) { return ResponseEntity.status(HttpStatus.CREATED) - .body(problemsSaveService.saveProblems(gymId, sectorId, requestDto)); + .body(problemsSaveService.saveProblems(gymId, sectorId, requestDto)); } @Operation(summary = "문제 여러건 조회", description = "문제 필터링, 정렬, 페이지네이션 후 여러건 조회") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 문제 조회"), + @ApiResponse(responseCode = "200", description = "성공적으로 문제 조회", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ProblemsResponseDto.class))), + @ApiResponse(responseCode = "404", description = "리소스를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}") + })) }) @GetMapping("/gyms/{gymId}/problems") public ResponseEntity findAllProblems( @@ -64,7 +74,12 @@ public ResponseEntity findAllProblems( @Operation(summary = "문제 단건 조회", description = "특정 문제의 정보 조회") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "성공적으로 문제 정보 조회함"), + @ApiResponse(responseCode = "200", description = "성공적으로 문제 정보 조회함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ProblemDetailResponseDto.class))), + @ApiResponse(responseCode = "404", description = "리소스를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "문제 없음", value = "{\"error\": \"아이디가 0190c558-9063-7050-b4fc-eb421e3236b3인 문제를 찾을 수 없습니다.\"}") + })) }) @GetMapping("/problems/{problemId}") public ResponseEntity findProblemById( From 455908d5710ae227e4abd2205554bbe93a13723b Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 17:54:07 +0900 Subject: [PATCH 16/22] =?UTF-8?q?FLASH-221=20feat:=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/domain/dto/ProblemCreateRequestDto.java | 6 +++++- .../climbing/problem/ui/ProblemController.java | 13 ++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/problem/domain/dto/ProblemCreateRequestDto.java b/src/main/java/com/first/flash/climbing/problem/domain/dto/ProblemCreateRequestDto.java index 7faa9bdd..1c14c1ea 100644 --- a/src/main/java/com/first/flash/climbing/problem/domain/dto/ProblemCreateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/problem/domain/dto/ProblemCreateRequestDto.java @@ -1,5 +1,9 @@ package com.first.flash.climbing.problem.domain.dto; -public record ProblemCreateRequestDto(String imageUrl, String difficulty) { +import jakarta.validation.constraints.NotEmpty; + +public record ProblemCreateRequestDto( + @NotEmpty(message = "이미지 URL은 필수입니다.") String imageUrl, + @NotEmpty(message = "난이도는 필수입니다.") String difficulty) { } diff --git a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java index e322c7be..940f3870 100644 --- a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java +++ b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -39,12 +40,22 @@ public class ProblemController { @Operation(summary = "문제 생성", description = "특정 섹터에 문제 생성") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "성공적으로 문제 생성함"), + @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "요청값 누락", value = "{\"name\": \"이미지 URL은 필수입니다.\"}") + })), + @ApiResponse(responseCode = "404", description = "리소스를 찾을 수 없음", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "클라이밍장 없음", value = "{\"error\": \"아이디가 1인 클라이밍장을 찾을 수 없습니다.\"}"), + @ExampleObject(name = "섹터 없음", value = "{\"error\": \"아이디가 1인 섹터를 찾을 수 없습니다.\"}"), + @ExampleObject(name = "난이도 없음", value = "{\"error\": \"이름이 핑크인 난이도를 찾을 수 없습니다.\"}") + })) }) @PostMapping("/gyms/{gymId}/sectors/{sectorId}/problems") public ResponseEntity saveProblems( @PathVariable("gymId") final Long gymId, @PathVariable("sectorId") final Long sectorId, - @RequestBody final ProblemCreateRequestDto requestDto) { + @Valid @RequestBody final ProblemCreateRequestDto requestDto) { return ResponseEntity.status(HttpStatus.CREATED) .body(problemsSaveService.saveProblems(gymId, sectorId, requestDto)); } From 1ee269b68bf56b74bbd29dd0d694d23abdec4f8e Mon Sep 17 00:00:00 2001 From: wonyangs Date: Wed, 31 Jul 2024 18:28:14 +0900 Subject: [PATCH 17/22] =?UTF-8?q?FLASH-221=20chore:=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=EB=90=9C=20swagger=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/first/flash/climbing/problem/ui/ProblemController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java index 940f3870..4384de67 100644 --- a/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java +++ b/src/main/java/com/first/flash/climbing/problem/ui/ProblemController.java @@ -39,7 +39,8 @@ public class ProblemController { @Operation(summary = "문제 생성", description = "특정 섹터에 문제 생성") @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "성공적으로 문제 생성함"), + @ApiResponse(responseCode = "201", description = "성공적으로 문제 생성함", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ProblemCreateResponseDto.class))), @ApiResponse(responseCode = "400", description = "유효하지 않은 요청 형식", content = @Content(mediaType = "application/json", examples = { @ExampleObject(name = "요청값 누락", value = "{\"name\": \"이미지 URL은 필수입니다.\"}") From 5cd48384e50273f8c9aa3d82e2dab224e1734015 Mon Sep 17 00:00:00 2001 From: wonyangs Date: Thu, 1 Aug 2024 14:54:57 +0900 Subject: [PATCH 18/22] =?UTF-8?q?FLASH-221=20refactor:=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=EB=AA=85=EC=9D=98=20=EC=8B=9C=EC=A0=9C?= =?UTF-8?q?=EB=A5=BC=20=EA=B3=BC=EA=B1=B0=ED=98=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../climbing/gym/application/ClimbingGymEventHandler.java | 4 ++-- ...Event.java => ClimbingGymIdConfirmRequestedEvent.java} | 6 +++--- .../climbing/problem/application/ProblemEventHandler.java | 4 ++-- .../climbing/problem/application/ProblemReadService.java | 8 ++++---- ...firmEvent.java => ProblemIdConfirmRequestedEvent.java} | 6 +++--- .../flash/climbing/sector/application/SectorService.java | 6 +++--- .../climbing/solution/application/SolutionService.java | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) rename src/main/java/com/first/flash/climbing/gym/domian/{ClimbingGymIdConfirmEvent.java => ClimbingGymIdConfirmRequestedEvent.java} (51%) rename src/main/java/com/first/flash/climbing/problem/domain/{ProblemIdConfirmEvent.java => ProblemIdConfirmRequestedEvent.java} (55%) diff --git a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java index d063a1a6..6bc02f10 100644 --- a/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java +++ b/src/main/java/com/first/flash/climbing/gym/application/ClimbingGymEventHandler.java @@ -1,6 +1,6 @@ package com.first.flash.climbing.gym.application; -import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmRequestedEvent; import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -14,7 +14,7 @@ public class ClimbingGymEventHandler { @EventListener @Transactional - public void confirmGymId(final ClimbingGymIdConfirmEvent event) { + public void confirmGymId(final ClimbingGymIdConfirmRequestedEvent event) { gymService.findClimbingGymById(event.getGymId()); } } diff --git a/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java b/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmRequestedEvent.java similarity index 51% rename from src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java rename to src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmRequestedEvent.java index cf5c9117..09e21258 100644 --- a/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmEvent.java +++ b/src/main/java/com/first/flash/climbing/gym/domian/ClimbingGymIdConfirmRequestedEvent.java @@ -6,11 +6,11 @@ @Getter @AllArgsConstructor -public class ClimbingGymIdConfirmEvent extends Event { +public class ClimbingGymIdConfirmRequestedEvent extends Event { private final Long gymId; - public static ClimbingGymIdConfirmEvent of(final Long gymId) { - return new ClimbingGymIdConfirmEvent(gymId); + public static ClimbingGymIdConfirmRequestedEvent of(final Long gymId) { + return new ClimbingGymIdConfirmRequestedEvent(gymId); } } diff --git a/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java b/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java index 4a2a9f55..34df487b 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java +++ b/src/main/java/com/first/flash/climbing/problem/application/ProblemEventHandler.java @@ -1,6 +1,6 @@ package com.first.flash.climbing.problem.application; -import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent; import com.first.flash.climbing.sector.domain.SectorExpiredEvent; import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent; import com.first.flash.climbing.sector.domain.SectorRemovalDateUpdatedEvent; @@ -44,7 +44,7 @@ public void updateQueryProblemInfo(final SectorInfoUpdatedEvent event) { @EventListener @Transactional - public void confirmProblemId(final ProblemIdConfirmEvent event) { + public void confirmProblemId(final ProblemIdConfirmRequestedEvent event) { problemReadService.findProblemById(event.getProblemId()); } } diff --git a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java index 50595c9e..c896d78c 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java +++ b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java @@ -3,11 +3,11 @@ import static com.first.flash.climbing.problem.infrastructure.paging.SortBy.DIFFICULTY; import static com.first.flash.climbing.problem.infrastructure.paging.SortBy.VIEWS; -import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmRequestedEvent; import com.first.flash.climbing.problem.application.dto.ProblemDetailResponseDto; import com.first.flash.climbing.problem.application.dto.ProblemsResponseDto; import com.first.flash.climbing.problem.domain.Problem; -import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent; import com.first.flash.climbing.problem.domain.ProblemRepository; import com.first.flash.climbing.problem.domain.QueryProblem; import com.first.flash.climbing.problem.domain.QueryProblemRepository; @@ -37,7 +37,7 @@ public ProblemsResponseDto findAll(final Long gymId, final String cursor, Cursor prevCursor = Cursor.decode(cursor); SortBy sortBy = SortBy.from(sortByRequest); - Events.raise(ClimbingGymIdConfirmEvent.of(gymId)); + Events.raise(ClimbingGymIdConfirmRequestedEvent.of(gymId)); List queryProblems = queryProblemRepository.findAll(prevCursor, sortBy, size, gymId, difficulty, sector, hasSolution); @@ -47,7 +47,7 @@ public ProblemsResponseDto findAll(final Long gymId, final String cursor, @Transactional public ProblemDetailResponseDto viewProblems(final UUID problemId) { - Events.raise(ProblemIdConfirmEvent.of(problemId)); + Events.raise(ProblemIdConfirmRequestedEvent.of(problemId)); QueryProblem queryProblem = findQueryProblemById(problemId); Problem problem = findProblemById(problemId); diff --git a/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java b/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmRequestedEvent.java similarity index 55% rename from src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java rename to src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmRequestedEvent.java index 057cd225..b99ad484 100644 --- a/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmEvent.java +++ b/src/main/java/com/first/flash/climbing/problem/domain/ProblemIdConfirmRequestedEvent.java @@ -7,11 +7,11 @@ @Getter @AllArgsConstructor -public class ProblemIdConfirmEvent extends Event { +public class ProblemIdConfirmRequestedEvent extends Event { private final UUID problemId; - public static ProblemIdConfirmEvent of(final UUID problemId) { - return new ProblemIdConfirmEvent(problemId); + public static ProblemIdConfirmRequestedEvent of(final UUID problemId) { + return new ProblemIdConfirmRequestedEvent(problemId); } } diff --git a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java index 273aa87b..1066e454 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java +++ b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java @@ -1,6 +1,6 @@ package com.first.flash.climbing.sector.application; -import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmEvent; +import com.first.flash.climbing.gym.domian.ClimbingGymIdConfirmRequestedEvent; import com.first.flash.climbing.sector.application.dto.SectorCreateRequestDto; import com.first.flash.climbing.sector.application.dto.SectorDetailResponseDto; import com.first.flash.climbing.sector.application.dto.SectorUpdateRemovalDateRequestDto; @@ -32,7 +32,7 @@ public SectorDetailResponseDto saveSector(final Long gymId, final SectorCreateRequestDto createRequestDto) { Sector sector = createSectorByDto(gymId, createRequestDto); - Events.raise(new ClimbingGymIdConfirmEvent(gymId)); + Events.raise(new ClimbingGymIdConfirmRequestedEvent(gymId)); return SectorDetailResponseDto.toDto(sectorRepository.save(sector)); } @@ -63,7 +63,7 @@ public SectorDetailResponseDto updateSector( updateRequestDto.removalDate(), updateRequestDto.gymId()); Events.raise(SectorInfoUpdatedEvent.of(foundSector.getId(), updateRequestDto.sectorName(), updateRequestDto.settingDate())); - Events.raise(ClimbingGymIdConfirmEvent.of(updateRequestDto.gymId())); + Events.raise(ClimbingGymIdConfirmRequestedEvent.of(updateRequestDto.gymId())); return SectorDetailResponseDto.toDto(foundSector); } diff --git a/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java b/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java index 024bdcdd..9ff772e8 100644 --- a/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java +++ b/src/main/java/com/first/flash/climbing/solution/application/SolutionService.java @@ -1,6 +1,6 @@ package com.first.flash.climbing.solution.application; -import com.first.flash.climbing.problem.domain.ProblemIdConfirmEvent; +import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent; import com.first.flash.climbing.solution.application.dto.SolutionMetaResponseDto; import com.first.flash.climbing.solution.application.dto.SolutionResponseDto; import com.first.flash.climbing.solution.application.dto.SolutionsResponseDto; @@ -38,7 +38,7 @@ public Solution findSolutionById(final Long id) { } public SolutionsResponseDto findAllSolutionsByProblemId(final UUID problemId) { - Events.raise(ProblemIdConfirmEvent.of(problemId)); + Events.raise(ProblemIdConfirmRequestedEvent.of(problemId)); List solutions = solutionRepository.findAllByProblemId(problemId) .stream() From 23c0d6fe3389edbcb66185dc75cad1cd0adf515e Mon Sep 17 00:00:00 2001 From: wonyangs Date: Thu, 1 Aug 2024 14:58:00 +0900 Subject: [PATCH 19/22] =?UTF-8?q?FLASH-221=20refactor:=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flash/climbing/problem/application/ProblemReadService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java index c896d78c..922d885b 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java +++ b/src/main/java/com/first/flash/climbing/problem/application/ProblemReadService.java @@ -7,7 +7,6 @@ import com.first.flash.climbing.problem.application.dto.ProblemDetailResponseDto; import com.first.flash.climbing.problem.application.dto.ProblemsResponseDto; import com.first.flash.climbing.problem.domain.Problem; -import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent; import com.first.flash.climbing.problem.domain.ProblemRepository; import com.first.flash.climbing.problem.domain.QueryProblem; import com.first.flash.climbing.problem.domain.QueryProblemRepository; @@ -47,8 +46,6 @@ public ProblemsResponseDto findAll(final Long gymId, final String cursor, @Transactional public ProblemDetailResponseDto viewProblems(final UUID problemId) { - Events.raise(ProblemIdConfirmRequestedEvent.of(problemId)); - QueryProblem queryProblem = findQueryProblemById(problemId); Problem problem = findProblemById(problemId); validateExpiration(problem, queryProblem); From 4dcaef986dca22c8746acc0638238c0cf7d38f2d Mon Sep 17 00:00:00 2001 From: wonyangs Date: Thu, 1 Aug 2024 15:18:11 +0900 Subject: [PATCH 20/22] =?UTF-8?q?FLASH-221=20refactor:=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EC=83=9D=EC=84=B1=EC=9D=84=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../first/flash/climbing/sector/application/SectorService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java index 1066e454..ce7fffc7 100644 --- a/src/main/java/com/first/flash/climbing/sector/application/SectorService.java +++ b/src/main/java/com/first/flash/climbing/sector/application/SectorService.java @@ -32,7 +32,7 @@ public SectorDetailResponseDto saveSector(final Long gymId, final SectorCreateRequestDto createRequestDto) { Sector sector = createSectorByDto(gymId, createRequestDto); - Events.raise(new ClimbingGymIdConfirmRequestedEvent(gymId)); + Events.raise(ClimbingGymIdConfirmRequestedEvent.of(gymId)); return SectorDetailResponseDto.toDto(sectorRepository.save(sector)); } From 7197128e0702551aacf3a640e41b63b15a15746f Mon Sep 17 00:00:00 2001 From: wonyangs Date: Thu, 1 Aug 2024 15:22:24 +0900 Subject: [PATCH 21/22] =?UTF-8?q?FLASH-221=20feat:=20=ED=95=B4=EC=84=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EB=A6=AC=EB=B7=B0=20=ED=95=AD?= =?UTF-8?q?=EB=AA=A9=EA=B3=BC=20=EC=9D=B8=EC=8A=A4=ED=83=80=EA=B7=B8?= =?UTF-8?q?=EB=9E=A8=20Id=EC=97=90=20Null=EC=9D=B4=20=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EC=98=AC=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solution/domain/dto/SolutionCreateRequestDto.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java b/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java index ce88b832..b383ed25 100644 --- a/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java +++ b/src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java @@ -1,14 +1,12 @@ package com.first.flash.climbing.solution.domain.dto; import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; public record SolutionCreateRequestDto( @NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl, @NotEmpty(message = "업로더 정보는 필수입니다.") String uploader, - @NotNull(message = "리뷰 항목은 필수입니다.") @Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review, - @NotEmpty(message = "인스타그램 ID는 필수입니다.") String instagramId) { + String instagramId) { } From 8043d89a317c3883f647e4ba9f65b5d07986c48a Mon Sep 17 00:00:00 2001 From: WonyuChoi Date: Fri, 2 Aug 2024 14:02:18 +0900 Subject: [PATCH 22/22] =?UTF-8?q?FLASH-238=20fix:=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EB=8B=A8=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=EC=97=90=20=ED=81=B4?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B0=8D=EC=9E=A5=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../problem/application/dto/ProblemDetailResponseDto.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/first/flash/climbing/problem/application/dto/ProblemDetailResponseDto.java b/src/main/java/com/first/flash/climbing/problem/application/dto/ProblemDetailResponseDto.java index ddb70cdc..70f4bf66 100644 --- a/src/main/java/com/first/flash/climbing/problem/application/dto/ProblemDetailResponseDto.java +++ b/src/main/java/com/first/flash/climbing/problem/application/dto/ProblemDetailResponseDto.java @@ -7,12 +7,12 @@ public record ProblemDetailResponseDto(UUID id, String sector, String difficulty, LocalDate settingDate, LocalDate removalDate, boolean isFakeRemovalDate, boolean hasSolution, - String imageUrl) { + String imageUrl, String gymName) { public static ProblemDetailResponseDto of(final QueryProblem queryProblem) { return new ProblemDetailResponseDto(queryProblem.getId(), queryProblem.getSectorName(), queryProblem.getDifficultyName(), queryProblem.getSettingDate(), queryProblem.getRemovalDate(), queryProblem.getIsFakeRemovalDate(), - queryProblem.getHasSolution(), queryProblem.getImageUrl()); + queryProblem.getHasSolution(), queryProblem.getImageUrl(), queryProblem.getGymName()); } }