From cf7caad70a36a0fb275527aa37632f93163e8632 Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 15:54:47 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=ED=9C=B4=EB=8C=80=ED=8F=B0=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EB=B3=80=EA=B2=BD=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20dto=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ray/pominowner/store/controller/StoreController.java | 6 ++++++ .../pominowner/store/controller/dto/PhoneNumberRequest.java | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 src/main/java/com/ray/pominowner/store/controller/dto/PhoneNumberRequest.java diff --git a/src/main/java/com/ray/pominowner/store/controller/StoreController.java b/src/main/java/com/ray/pominowner/store/controller/StoreController.java index 1e2ceffd..1d01709a 100644 --- a/src/main/java/com/ray/pominowner/store/controller/StoreController.java +++ b/src/main/java/com/ray/pominowner/store/controller/StoreController.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.ray.pominowner.store.controller.dto.CategoryRequest; +import com.ray.pominowner.store.controller.dto.PhoneNumberRequest; import com.ray.pominowner.store.controller.dto.StoreRegisterRequest; import com.ray.pominowner.store.service.StoreService; import jakarta.validation.Valid; @@ -33,4 +34,9 @@ public void registerCategory(@RequestBody @Valid CategoryRequest categories, @Pa storeService.registerCategory(categories.categories(), storeId); } + @PostMapping("/{id}/phone-numbers") + public void registerPhoneNumber(@RequestBody @Valid PhoneNumberRequest phoneNumberRequest, @PathVariable(value = "id") Long storeId) { + storeService.registerPhoneNumber(phoneNumberRequest.phoneNumber(), storeId); + } + } diff --git a/src/main/java/com/ray/pominowner/store/controller/dto/PhoneNumberRequest.java b/src/main/java/com/ray/pominowner/store/controller/dto/PhoneNumberRequest.java new file mode 100644 index 00000000..00bd2f75 --- /dev/null +++ b/src/main/java/com/ray/pominowner/store/controller/dto/PhoneNumberRequest.java @@ -0,0 +1,6 @@ +package com.ray.pominowner.store.controller.dto; + +import jakarta.validation.constraints.NotBlank; + +public record PhoneNumberRequest(@NotBlank String phoneNumber) { +} From 45892e2f4481a48dc557d3ba0cc1a9b107499fbd Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 15:56:02 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20Store=20=EC=97=94=ED=8B=B0=ED=8B=B0?= =?UTF-8?q?=20=EA=B0=92=20=EA=B0=9D=EC=B2=B4=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A0=84=ED=99=94=EB=B2=88=ED=98=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pominowner/store/domain/PhoneNumber.java | 38 +++++++++++++++++++ .../ray/pominowner/store/domain/Store.java | 35 ++++++++++++++--- 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java diff --git a/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java b/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java new file mode 100644 index 00000000..8cef58e5 --- /dev/null +++ b/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java @@ -0,0 +1,38 @@ +package com.ray.pominowner.store.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.util.Assert; + +import java.util.regex.Pattern; + +@Embeddable +@EqualsAndHashCode(of = "tel") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class PhoneNumber { + + private static final String DEFAULT_VALUE = "NOT_SELECTED"; + private static final String REGEX = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$"; + + @Column(columnDefinition = "TEXT default 'NOT_SELECTED'") + private String tel = DEFAULT_VALUE; + + public PhoneNumber(String phoneNumber) { + validatePhoneNumber(phoneNumber); + + this.tel = phoneNumber; + } + + private void validatePhoneNumber(String phoneNumber) { + Assert.hasText(phoneNumber, "올바른 전화번호를 입력해 주세요."); + Assert.isTrue(Pattern.matches(REGEX, phoneNumber), "올바른 전화번호를 입력해 주세요."); + } + + public String getTel() { + return tel; + } + +} diff --git a/src/main/java/com/ray/pominowner/store/domain/Store.java b/src/main/java/com/ray/pominowner/store/domain/Store.java index b4710448..541ff0a4 100644 --- a/src/main/java/com/ray/pominowner/store/domain/Store.java +++ b/src/main/java/com/ray/pominowner/store/domain/Store.java @@ -7,6 +7,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import lombok.AccessLevel; +import lombok.Builder; import lombok.NoArgsConstructor; import org.springframework.util.Assert; @@ -27,27 +28,51 @@ public class Store extends BaseTimeEntity { @Column(columnDefinition = "TEXT default 'NOT_SELECTED'") private String info = DEFAULT_VALUE; // 선택 + @Embedded @Column(columnDefinition = "TEXT default 'NOT_SELECTED'") - private String tel = DEFAULT_VALUE; // 선택 + private PhoneNumber tel = new PhoneNumber(); // 선택 private Long ownerId; // 추후 연관관계 설정 예정 - public Store(final RequiredStoreInfo requiredStoreInfo) { + @Builder + private Store(Long id, RequiredStoreInfo requiredStoreInfo, String info, PhoneNumber tel, Long ownerId) { + this.id = id; + this.requiredStoreInfo = requiredStoreInfo; + this.info = info; + this.tel = tel; + this.ownerId = ownerId; + } + + public Store(RequiredStoreInfo requiredStoreInfo) { validateRequiredInfo(requiredStoreInfo); this.requiredStoreInfo = requiredStoreInfo; } - private void validateRequiredInfo(final RequiredStoreInfo requiredStoreInfo) { + private void validateRequiredInfo(RequiredStoreInfo requiredStoreInfo) { Assert.notNull(requiredStoreInfo, "가게 정보는 필수 입니다."); } + public String getBusinessNumber() { + return requiredStoreInfo.getBusinessNumber(); + } + + public Store afterRegisterPhoneNumber(String phoneNumber) { + return Store.builder() + .id(this.id) + .requiredStoreInfo(this.requiredStoreInfo) + .info(this.info) + .tel(new PhoneNumber(phoneNumber)) + .ownerId(this.ownerId) + .build(); + } + public Long getId() { return id; } - public String getBusinessNumber() { - return requiredStoreInfo.getBusinessNumber(); + public String getTel() { + return tel.getTel(); } } From f09cbab3e20c8c47b146dd00de309e1f63dc427f Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 15:56:37 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=ED=9C=B4=EB=8C=80=ED=8F=B0=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EB=B3=80=EA=B2=BD=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=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 --- .../com/ray/pominowner/store/service/StoreService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/ray/pominowner/store/service/StoreService.java b/src/main/java/com/ray/pominowner/store/service/StoreService.java index a7093dc8..c9b1f443 100644 --- a/src/main/java/com/ray/pominowner/store/service/StoreService.java +++ b/src/main/java/com/ray/pominowner/store/service/StoreService.java @@ -25,6 +25,7 @@ public class StoreService { @Transactional public Long registerStore(Store store) throws JsonProcessingException { storeServiceValidator.validateBusinessNumber(store.getBusinessNumber()); + return storeRepository.save(store).getId(); } @@ -34,6 +35,12 @@ public void registerCategory(final List categories, Long storeId) { storeCategoryService.saveCategories(findStore(storeId), categories); } + @Transactional + public void registerPhoneNumber(String phoneNumber, Long storeId) { + Store store = findStore(storeId).afterRegisterPhoneNumber(phoneNumber); + storeRepository.save(store); + } + private Store findStore(final Long storeId) { return storeRepository.findById(storeId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 가게입니다.")); From 385e17588daa59436eb0c319201017bdd9a157fa Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 15:59:27 +0900 Subject: [PATCH 4/7] =?UTF-8?q?test:=20=EC=A0=84=ED=99=94=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EB=93=B1=EB=A1=9D=20=EA=B4=80=EB=A0=A8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../store/controller/StoreControllerTest.java | 16 ++++++++++ .../store/domain/PhoneNumberTest.java | 32 +++++++++++++++++++ .../pominowner/store/domain/StoreTest.java | 16 ++++++++++ .../store/service/StoreServiceTest.java | 16 +++++++++- 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java diff --git a/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java b/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java index 363a47ee..16d99667 100644 --- a/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java +++ b/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.ray.pominowner.store.controller.dto.CategoryRequest; +import com.ray.pominowner.store.controller.dto.PhoneNumberRequest; import com.ray.pominowner.store.controller.dto.StoreRegisterRequest; import com.ray.pominowner.store.domain.Store; import com.ray.pominowner.store.service.StoreService; @@ -68,4 +69,19 @@ void successRegisterCategory() throws Exception { .andExpect(status().isOk()); } + @Test + @WithMockUser + @DisplayName("전화번호 등록에 성공한다") + void successRegisterPhoneNumber() throws Exception { + // given + PhoneNumberRequest phoneNumberRequest = new PhoneNumberRequest("01012345678"); + + // when, then + mvc.perform(post("/api/v1/stores/1/phone-numbers") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(phoneNumberRequest))) + .andExpect(status().isOk()); + } + } diff --git a/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java b/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java new file mode 100644 index 00000000..4b9efe45 --- /dev/null +++ b/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java @@ -0,0 +1,32 @@ +package com.ray.pominowner.store.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class PhoneNumberTest { + + @ParameterizedTest + @ValueSource(strings = {"abcdef", "0212345678", "02", "", " "}) + @NullSource + @DisplayName("전화번호 형식이 올바르지 않으면 예외가 발생한다") + void failWhenIncorrectPhoneNumberFormat(String phoneNumber) { + // when, then + assertThatThrownBy(() -> new PhoneNumber(phoneNumber)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("올바른 전화번호를 입력해 주세요."); + } + + @ParameterizedTest + @ValueSource(strings = {"010-1234-5678", "01012345678", "011-111-1111"}) + @DisplayName("전화번호 형식이 올바르면 예외가 발생하지 않는다") + void successWhenCorrectPhoneNumberFormat(String phoneNumber) { + // when, then + assertThatNoException().isThrownBy(() -> new PhoneNumber(phoneNumber)); + } + +} diff --git a/src/test/java/com/ray/pominowner/store/domain/StoreTest.java b/src/test/java/com/ray/pominowner/store/domain/StoreTest.java index 422cddaa..f5529610 100644 --- a/src/test/java/com/ray/pominowner/store/domain/StoreTest.java +++ b/src/test/java/com/ray/pominowner/store/domain/StoreTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -30,4 +31,19 @@ void successWhenRequiredInfoIsNotNull() { .isThrownBy(() -> new Store(requiredStoreInfo)); } + @Test + @DisplayName("전화번호를 등록하면 전화번호가 설정된다") + void successRegisterPhoneNumber() { + // given + Store store = StoreTestFixture.store(); + String validPhoneNumber = "01012345678"; + + // when + Store storeAfterRegisteredPhoneNumber = store.afterRegisterPhoneNumber(validPhoneNumber); + + // then + assertThat(store.getTel()).isEqualTo("NOT_SELECTED"); + assertThat(storeAfterRegisteredPhoneNumber.getTel()).isEqualTo(validPhoneNumber); + } + } diff --git a/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java b/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java index d2c68dd8..74be5edc 100644 --- a/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java +++ b/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java @@ -50,7 +50,8 @@ void successRegisterStore() throws JsonProcessingException { given(storeRepository.save(store)).willReturn(store); // when, then - assertThatNoException().isThrownBy(() -> storeService.registerStore(store)); + assertThatNoException() + .isThrownBy(() -> storeService.registerStore(store)); } @@ -67,4 +68,17 @@ void successRegisterCategories() { .isThrownBy(() -> storeService.registerCategory(categoryRequest, store.getId())); } + @Test + @DisplayName("전화번호가 정상적으로 등록된다") + void successRegisterPhoneNumber() { + // given + String validPhoneNumber = "010-1234-5678"; + given(storeRepository.findById(store.getId())).willReturn(Optional.of(store)); + + // when, then + assertThatNoException() + .isThrownBy(() -> storeService.registerPhoneNumber(validPhoneNumber, store.getId())); + } + + } From fedbf50c62f45d4368a3cd6d3c52694e05155f91 Mon Sep 17 00:00:00 2001 From: Junho Hwang <72647031+juno-junho@users.noreply.github.com> Date: Thu, 14 Sep 2023 00:25:48 -0700 Subject: [PATCH 5/7] =?UTF-8?q?test:=20displayname=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: HongSeok Ju <75611167+Juhongseok@users.noreply.github.com> --- .../java/com/ray/pominowner/store/domain/PhoneNumberTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java b/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java index 4b9efe45..d61fb1b5 100644 --- a/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java +++ b/src/test/java/com/ray/pominowner/store/domain/PhoneNumberTest.java @@ -23,7 +23,7 @@ void failWhenIncorrectPhoneNumberFormat(String phoneNumber) { @ParameterizedTest @ValueSource(strings = {"010-1234-5678", "01012345678", "011-111-1111"}) - @DisplayName("전화번호 형식이 올바르면 예외가 발생하지 않는다") + @DisplayName("전화번호 형식이 올바르면 생성에 성공한다") void successWhenCorrectPhoneNumberFormat(String phoneNumber) { // when, then assertThatNoException().isThrownBy(() -> new PhoneNumber(phoneNumber)); From 02158f6cd402d934b502764fb76fd91c0c43d489 Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 16:34:57 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=B3=80=EC=88=98=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20post=20->=20patch=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 --- .../ray/pominowner/store/controller/StoreController.java | 9 +++++---- .../pominowner/store/controller/StoreControllerTest.java | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ray/pominowner/store/controller/StoreController.java b/src/main/java/com/ray/pominowner/store/controller/StoreController.java index 1d01709a..bff2e876 100644 --- a/src/main/java/com/ray/pominowner/store/controller/StoreController.java +++ b/src/main/java/com/ray/pominowner/store/controller/StoreController.java @@ -8,6 +8,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -29,13 +30,13 @@ public ResponseEntity registerStore(@RequestBody @Valid StoreRegisterReque return ResponseEntity.created(URI.create("/api/v1/stores/" + storeId)).build(); } - @PostMapping("/{id}/categories") - public void registerCategory(@RequestBody @Valid CategoryRequest categories, @PathVariable(value = "id") Long storeId) { + @PostMapping("/{storeId}/categories") + public void registerCategory(@RequestBody @Valid CategoryRequest categories, @PathVariable Long storeId) { storeService.registerCategory(categories.categories(), storeId); } - @PostMapping("/{id}/phone-numbers") - public void registerPhoneNumber(@RequestBody @Valid PhoneNumberRequest phoneNumberRequest, @PathVariable(value = "id") Long storeId) { + @PatchMapping("/{storeId}/phone-numbers") + public void registerPhoneNumber(@RequestBody @Valid PhoneNumberRequest phoneNumberRequest, @PathVariable Long storeId) { storeService.registerPhoneNumber(phoneNumberRequest.phoneNumber(), storeId); } diff --git a/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java b/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java index 16d99667..0ce6f61b 100644 --- a/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java +++ b/src/test/java/com/ray/pominowner/store/controller/StoreControllerTest.java @@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -29,7 +30,7 @@ class StoreControllerTest { @Autowired private MockMvc mvc; - + @Autowired private ObjectMapper mapper; @@ -77,7 +78,7 @@ void successRegisterPhoneNumber() throws Exception { PhoneNumberRequest phoneNumberRequest = new PhoneNumberRequest("01012345678"); // when, then - mvc.perform(post("/api/v1/stores/1/phone-numbers") + mvc.perform(patch("/api/v1/stores/1/phone-numbers") .with(csrf()) .contentType(MediaType.APPLICATION_JSON) .content(mapper.writeValueAsString(phoneNumberRequest))) From 14a111bf70bc7faf0e9eda380195db05b663fff2 Mon Sep 17 00:00:00 2001 From: junho Date: Thu, 14 Sep 2023 16:47:23 +0900 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java | 2 +- .../java/com/ray/pominowner/store/service/StoreServiceTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java b/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java index 8cef58e5..f008ccfb 100644 --- a/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java +++ b/src/main/java/com/ray/pominowner/store/domain/PhoneNumber.java @@ -10,7 +10,7 @@ import java.util.regex.Pattern; @Embeddable -@EqualsAndHashCode(of = "tel") +@EqualsAndHashCode @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PhoneNumber { diff --git a/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java b/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java index 74be5edc..0474100d 100644 --- a/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java +++ b/src/test/java/com/ray/pominowner/store/service/StoreServiceTest.java @@ -80,5 +80,4 @@ void successRegisterPhoneNumber() { .isThrownBy(() -> storeService.registerPhoneNumber(validPhoneNumber, store.getId())); } - }