From 5c91918d8dc494f25de744f9cb5730c2fff03678 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Wed, 20 Mar 2024 17:35:04 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=82=AC=EC=9E=A5=EB=8B=98=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/owner/controller/OwnerApi.java | 19 ++++++++++++ .../owner/controller/OwnerController.java | 14 +++++++++ .../domain/owner/dto/OwnerUpdateRequest.java | 30 +++++++++++++++++++ .../domain/owner/model/OwnerAttachment.java | 3 +- .../domain/owner/service/OwnerService.java | 25 ++++++++++++++++ 5 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java diff --git a/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerApi.java b/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerApi.java index 63fc81aca6..3d7a0c9e06 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerApi.java +++ b/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerApi.java @@ -5,9 +5,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import in.koreatech.koin.domain.owner.dto.OwnerResponse; +import in.koreatech.koin.domain.owner.dto.OwnerUpdateRequest; import in.koreatech.koin.domain.owner.dto.VerifyEmailRequest; import in.koreatech.koin.global.auth.Auth; import io.swagger.v3.oas.annotations.Operation; @@ -48,4 +50,21 @@ ResponseEntity requestVerificationToRegister( ResponseEntity getOwner( @Auth(permit = {OWNER}) Long userId ); + + @ApiResponses( + value = { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "422", content = @Content(schema = @Schema(hidden = true))), + } + ) + @Operation(summary = "사장님 인증용 첨부파일 등록") + @SecurityRequirement(name = "Jwt Authentication") + @PutMapping("/owner") + ResponseEntity putOwner( + @Auth(permit = {OWNER}) Long userId, + @RequestBody @Valid OwnerUpdateRequest request + ); } diff --git a/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerController.java b/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerController.java index 10a710d879..38e54e391e 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerController.java +++ b/src/main/java/in/koreatech/koin/domain/owner/controller/OwnerController.java @@ -3,11 +3,14 @@ import static in.koreatech.koin.domain.user.model.UserType.OWNER; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import in.koreatech.koin.domain.owner.dto.OwnerResponse; +import in.koreatech.koin.domain.owner.dto.OwnerUpdateRequest; import in.koreatech.koin.domain.owner.dto.VerifyEmailRequest; import in.koreatech.koin.domain.owner.service.OwnerService; import in.koreatech.koin.global.auth.Auth; @@ -29,10 +32,21 @@ public ResponseEntity requestVerificationToRegister( } @Override + @GetMapping("/owner") public ResponseEntity getOwner( @Auth(permit = {OWNER}) Long ownerId ) { OwnerResponse ownerInfo = ownerService.getOwner(ownerId); return ResponseEntity.ok().body(ownerInfo); } + + @Override + @PutMapping("/owner") + public ResponseEntity putOwner( + @Auth(permit = {OWNER}) Long userId, + @RequestBody @Valid OwnerUpdateRequest request + ) { + OwnerResponse ownerInfo = ownerService.putOwner(userId, request); + return ResponseEntity.ok().body(ownerInfo); + } } diff --git a/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java b/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java new file mode 100644 index 0000000000..233845cedf --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java @@ -0,0 +1,30 @@ +package in.koreatech.koin.domain.owner.dto; + +import java.util.List; + +import org.hibernate.validator.constraints.URL; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +@JsonNaming(SnakeCaseStrategy.class) +public record OwnerUpdateRequest( + @Size(min = 3, max = 5, message = "이미지는 사업자등록증, 영업신고증, 통장사본을 포함하여 최소 3개 최대 5개까지 가능합니다.") + @Schema(description = "첨부 파일 URL 목록(최소 3개 최대 5개, 코인 파일 형식이어야 함)") + List attachmentUrls +) { + + @JsonNaming(SnakeCaseStrategy.class) + public record InnerAttachmentUrlRequest( + @NotBlank + @URL(protocol = "https", regexp = ".*static\\.koreatech\\.in.*", message = "코인 파일 저장 형식이 아닙니다.") + @Schema(description = "첨부 파일 URL (코인 파일 형식이어야 함)", example = "https://static.koreatech.in/1.png") + String fileUrl + ) { + + } +} diff --git a/src/main/java/in/koreatech/koin/domain/owner/model/OwnerAttachment.java b/src/main/java/in/koreatech/koin/domain/owner/model/OwnerAttachment.java index bfef0b1ada..b89cc50796 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/model/OwnerAttachment.java +++ b/src/main/java/in/koreatech/koin/domain/owner/model/OwnerAttachment.java @@ -68,10 +68,9 @@ public void updateName() { } @Builder - private OwnerAttachment(Owner owner, String url, Boolean isDeleted, String name) { + private OwnerAttachment(Owner owner, String url, Boolean isDeleted) { this.owner = owner; this.url = url; this.isDeleted = isDeleted; - this.name = name; } } diff --git a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java index 841f15c774..6e9f673794 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java +++ b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java @@ -9,6 +9,7 @@ import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.owner.dto.OwnerResponse; +import in.koreatech.koin.domain.owner.dto.OwnerUpdateRequest; import in.koreatech.koin.domain.owner.dto.VerifyEmailRequest; import in.koreatech.koin.domain.owner.model.Owner; import in.koreatech.koin.domain.owner.model.OwnerAttachment; @@ -66,4 +67,28 @@ public OwnerResponse getOwner(Long ownerId) { List shops = shopRepository.findAllByOwnerId(ownerId); return OwnerResponse.of(foundOwner, attachments, shops); } + + @Transactional + public OwnerResponse putOwner(Long userId, OwnerUpdateRequest request) { + // 인증되지 않은 사장님이어야 할까? + // 인증 사진이 기존에 없는 사장님이어야 할까? + // size 예외처리 MethodArgumentNotValidException + Owner foundOwner = ownerRepository.getById(userId); + List attachments = request.attachmentUrls().stream() + .map(url -> OwnerAttachment.builder() + .owner(foundOwner) + .url(url.fileUrl()) + .isDeleted(false) + .build() + ) + .toList(); + + for (OwnerAttachment attachment : attachments) { + ownerAttachmentRepository.save(attachment); + } + + List allAttachments = ownerAttachmentRepository.findAllByOwnerId(userId); + List shops = shopRepository.findAllByOwnerId(userId); + return OwnerResponse.of(foundOwner, allAttachments, shops); + } } From 635559b35b2e3a76973c16551f34c22ee52d3c78 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Wed, 20 Mar 2024 19:40:34 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20RequestBody=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=EB=B0=8F=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/owner/dto/OwnerUpdateRequest.java | 2 ++ .../koin/domain/owner/service/OwnerService.java | 5 ++--- .../koin/global/exception/GlobalExceptionHandler.java | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java b/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java index 233845cedf..0773b66110 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java +++ b/src/main/java/in/koreatech/koin/domain/owner/dto/OwnerUpdateRequest.java @@ -8,11 +8,13 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; @JsonNaming(SnakeCaseStrategy.class) public record OwnerUpdateRequest( + @Valid @Size(min = 3, max = 5, message = "이미지는 사업자등록증, 영업신고증, 통장사본을 포함하여 최소 3개 최대 5개까지 가능합니다.") @Schema(description = "첨부 파일 URL 목록(최소 3개 최대 5개, 코인 파일 형식이어야 함)") List attachmentUrls diff --git a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java index 6e9f673794..9653a6cb2b 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java +++ b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java @@ -70,9 +70,8 @@ public OwnerResponse getOwner(Long ownerId) { @Transactional public OwnerResponse putOwner(Long userId, OwnerUpdateRequest request) { - // 인증되지 않은 사장님이어야 할까? - // 인증 사진이 기존에 없는 사장님이어야 할까? - // size 예외처리 MethodArgumentNotValidException + // TODO + // 기존에 있는건 중복안되게 Owner foundOwner = ownerRepository.getById(userId); List attachments = request.attachmentUrls().stream() .map(url -> OwnerAttachment.builder() diff --git a/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java b/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java index aa12ea21cc..c992a5e621 100644 --- a/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java @@ -2,15 +2,15 @@ import java.time.format.DateTimeParseException; -import in.koreatech.koin.global.auth.exception.AuthException; -import lombok.extern.slf4j.Slf4j; - import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import in.koreatech.koin.global.auth.exception.AuthException; +import lombok.extern.slf4j.Slf4j; + @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @@ -18,7 +18,8 @@ public class GlobalExceptionHandler { @ExceptionHandler public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.warn(e.getMessage()); - return ResponseEntity.badRequest().body(ErrorResponse.from(e.getMessage())); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ErrorResponse.from("요청 파라미터가 잘못되었습니다.")); } @ExceptionHandler From e4b45653d4433dc7f3daf30394d66d38cef65708 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Thu, 21 Mar 2024 16:18:30 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EC=B2=A8=EB=B6=80=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B0=9C=EC=88=98=EA=B0=80=20=EB=B6=80=EC=A1=B1?= =?UTF-8?q?=ED=95=A0=20=EC=8B=9C=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OwnerAttachmentsCountException.java | 17 +++++++++++++++++ .../repository/OwnerAttachmentRepository.java | 3 +++ .../koin/domain/owner/service/OwnerService.java | 15 +++++++++++++-- .../exception/ArgumentCountException.java | 8 ++++++++ .../exception/GlobalExceptionHandler.java | 7 +++++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/main/java/in/koreatech/koin/domain/owner/exception/OwnerAttachmentsCountException.java create mode 100644 src/main/java/in/koreatech/koin/global/exception/ArgumentCountException.java diff --git a/src/main/java/in/koreatech/koin/domain/owner/exception/OwnerAttachmentsCountException.java b/src/main/java/in/koreatech/koin/domain/owner/exception/OwnerAttachmentsCountException.java new file mode 100644 index 0000000000..9aeea3660b --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/owner/exception/OwnerAttachmentsCountException.java @@ -0,0 +1,17 @@ +package in.koreatech.koin.domain.owner.exception; + +import in.koreatech.koin.global.exception.ArgumentCountException; + +public class OwnerAttachmentsCountException extends ArgumentCountException { + + private static final String DEFAULT_MESSAGE = "첨부파일 개수가 부족합니다."; + + public OwnerAttachmentsCountException(String message) { + super(message); + } + + public static OwnerAttachmentsCountException withDetail(String detail) { + String message = String.format("%s %s", DEFAULT_MESSAGE, detail); + return new OwnerAttachmentsCountException(message); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/owner/repository/OwnerAttachmentRepository.java b/src/main/java/in/koreatech/koin/domain/owner/repository/OwnerAttachmentRepository.java index 0b3cda1f2e..ce67e8e33c 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/repository/OwnerAttachmentRepository.java +++ b/src/main/java/in/koreatech/koin/domain/owner/repository/OwnerAttachmentRepository.java @@ -1,6 +1,7 @@ package in.koreatech.koin.domain.owner.repository; import java.util.List; +import java.util.Optional; import org.springframework.data.repository.Repository; @@ -13,4 +14,6 @@ public interface OwnerAttachmentRepository extends Repository findAllByOwnerId(Long ownerId); + + Optional findByOwnerIdAndUrl(Long userId, String url); } diff --git a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java index 9653a6cb2b..34766a43fb 100644 --- a/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java +++ b/src/main/java/in/koreatech/koin/domain/owner/service/OwnerService.java @@ -11,6 +11,7 @@ import in.koreatech.koin.domain.owner.dto.OwnerResponse; import in.koreatech.koin.domain.owner.dto.OwnerUpdateRequest; import in.koreatech.koin.domain.owner.dto.VerifyEmailRequest; +import in.koreatech.koin.domain.owner.exception.OwnerAttachmentsCountException; import in.koreatech.koin.domain.owner.model.Owner; import in.koreatech.koin.domain.owner.model.OwnerAttachment; import in.koreatech.koin.domain.owner.model.OwnerEmailRequestEvent; @@ -32,6 +33,8 @@ @Transactional(readOnly = true) public class OwnerService { + private static final int MIN_ATTACHMENT_COUNT = 3; + private final UserRepository userRepository; private final OwnerInVerificationRepository ownerInVerificationRepository; private final MailService mailService; @@ -70,8 +73,6 @@ public OwnerResponse getOwner(Long ownerId) { @Transactional public OwnerResponse putOwner(Long userId, OwnerUpdateRequest request) { - // TODO - // 기존에 있는건 중복안되게 Owner foundOwner = ownerRepository.getById(userId); List attachments = request.attachmentUrls().stream() .map(url -> OwnerAttachment.builder() @@ -83,11 +84,21 @@ public OwnerResponse putOwner(Long userId, OwnerUpdateRequest request) { .toList(); for (OwnerAttachment attachment : attachments) { + if (ownerAttachmentRepository.findByOwnerIdAndUrl(userId, attachment.getUrl()).isPresent()) { + continue; + } ownerAttachmentRepository.save(attachment); } List allAttachments = ownerAttachmentRepository.findAllByOwnerId(userId); + validateAttachments(allAttachments); List shops = shopRepository.findAllByOwnerId(userId); return OwnerResponse.of(foundOwner, allAttachments, shops); } + + private void validateAttachments(List allAttachments) { + if (allAttachments.size() < MIN_ATTACHMENT_COUNT) { + throw OwnerAttachmentsCountException.withDetail("attachments size: " + allAttachments.size()); + } + } } diff --git a/src/main/java/in/koreatech/koin/global/exception/ArgumentCountException.java b/src/main/java/in/koreatech/koin/global/exception/ArgumentCountException.java new file mode 100644 index 0000000000..39c485c2eb --- /dev/null +++ b/src/main/java/in/koreatech/koin/global/exception/ArgumentCountException.java @@ -0,0 +1,8 @@ +package in.koreatech.koin.global.exception; + +public class ArgumentCountException extends RuntimeException { + + public ArgumentCountException(String message) { + super(message); + } +} diff --git a/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java b/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java index c992a5e621..e9e0f155c9 100644 --- a/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/in/koreatech/koin/global/exception/GlobalExceptionHandler.java @@ -56,4 +56,11 @@ public ResponseEntity handleDateTimeParseException(DateTimeParseE return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(ErrorResponse.from("잘못된 날짜 형식입니다.")); } + + @ExceptionHandler + public ResponseEntity handleArgumentCountException(ArgumentCountException e) { + log.warn(e.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ErrorResponse.from("요청 파라미터가 잘못되었습니다.")); + } } From 90d028d990e829fef1c83963473c79921d278ebb Mon Sep 17 00:00:00 2001 From: songsunkook Date: Thu, 21 Mar 2024 18:42:14 +0900 Subject: [PATCH 4/4] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/acceptance/OwnerApiTest.java | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java b/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java index 86913ec561..d315167892 100644 --- a/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java @@ -104,7 +104,6 @@ void getOwner() { .when() .get("/owner") .then() - .log().all() .statusCode(HttpStatus.OK.value()) .extract(); @@ -172,4 +171,109 @@ void checkOwnerEventListener() { Mockito.verify(ownerEventListener).onOwnerEmailRequest(event); } + + @Test + @DisplayName("사장님 인증용 이미지를 업로드한다.") + void putOwner() { + // given + User user = User.builder() + .password("1234") + .nickname("주노") + .name("최준호") + .phoneNumber("010-1234-5678") + .userType(OWNER) + .gender(UserGender.MAN) + .email("test@koreatech.ac.kr") + .isAuthed(true) + .isDeleted(false) + .build(); + + Owner ownerRequest = Owner.builder() + .companyRegistrationNumber("123-45-67890") + .companyRegistrationCertificateImageUrl("https://test.com/test.jpg") + .grantShop(true) + .grantEvent(true) + .user(user) + .build(); + + Owner owner = ownerRepository.save(ownerRequest); + + Shop shopRequest = Shop.builder() + .owner(owner) + .name("테스트 상점") + .internalName("테스트") + .chosung("테스트") + .phone("010-1234-5678") + .address("대전광역시 유성구 대학로 291") + .description("테스트 상점입니다.") + .delivery(true) + .deliveryPrice(3000L) + .payCard(true) + .payBank(true) + .isDeleted(false) + .isEvent(false) + .remarks("비고") + .hit(0L) + .build(); + + Shop shop = shopRepository.save(shopRequest); + + String token = jwtProvider.createToken(owner.getUser()); + + // when then + ExtractableResponse response = RestAssured + .given() + .header("Authorization", "Bearer " + token) + .body(""" + { + "attachment_urls": [ + { + "file_url": "https://static.koreatech.in/example/example_image1.png" + }, + { + "file_url": "https://static.koreatech.in/example/example_image2.png" + }, + { + "file_url": "https://static.koreatech.in/example/example_image3.png" + } + ] + } + """) + .contentType(ContentType.JSON) + .when() + .put("/owner") + .then().log().all() + .statusCode(HttpStatus.OK.value()) + .extract(); + + assertSoftly( + softly -> { + softly.assertThat(response.body().jsonPath().getString("email")).isEqualTo(user.getEmail()); + softly.assertThat(response.body().jsonPath().getString("name")).isEqualTo(user.getName()); + softly.assertThat(response.body().jsonPath().getString("company_number")) + .isEqualTo(owner.getCompanyRegistrationNumber()); + + softly.assertThat(response.body().jsonPath().getList("attachments").size()).isEqualTo(3); + softly.assertThat(response.body().jsonPath().getLong("attachments[0].id")).isNotNull(); + softly.assertThat(response.body().jsonPath().getString("attachments[0].file_url")) + .isEqualTo("https://static.koreatech.in/example/example_image1.png"); + softly.assertThat(response.body().jsonPath().getString("attachments[0].file_name")) + .isEqualTo("example_image1.png"); + softly.assertThat(response.body().jsonPath().getLong("attachments[1].id")).isNotNull(); + softly.assertThat(response.body().jsonPath().getString("attachments[1].file_url")) + .isEqualTo("https://static.koreatech.in/example/example_image2.png"); + softly.assertThat(response.body().jsonPath().getString("attachments[1].file_name")) + .isEqualTo("example_image2.png"); + softly.assertThat(response.body().jsonPath().getLong("attachments[2].id")).isNotNull(); + softly.assertThat(response.body().jsonPath().getString("attachments[2].file_url")) + .isEqualTo("https://static.koreatech.in/example/example_image3.png"); + softly.assertThat(response.body().jsonPath().getString("attachments[2].file_name")) + .isEqualTo("example_image3.png"); + + softly.assertThat(response.body().jsonPath().getList("shops").size()).isEqualTo(1); + softly.assertThat(response.body().jsonPath().getLong("shops[0].id")).isEqualTo(shop.getId()); + softly.assertThat(response.body().jsonPath().getString("shops[0].name")).isEqualTo(shop.getName()); + } + ); + } }