diff --git a/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/dto/request/AcousticAndClassicGuitarUpdateRequest.java b/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/dto/request/AcousticAndClassicGuitarUpdateRequest.java new file mode 100644 index 0000000..17b3b89 --- /dev/null +++ b/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/dto/request/AcousticAndClassicGuitarUpdateRequest.java @@ -0,0 +1,63 @@ +package com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request; + +import java.util.List; + +import org.springframework.lang.Nullable; +import org.springframework.web.multipart.MultipartFile; + +import com.ajou.hertz.common.dto.request.AddressRequest; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarBrand; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarModel; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarPickUp; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarWood; +import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest; + +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Setter +@Getter +public class AcousticAndClassicGuitarUpdateRequest extends InstrumentUpdateRequest { + + @Nullable + private AcousticAndClassicGuitarBrand brand; + + @Nullable + private AcousticAndClassicGuitarModel model; + + @NotNull + private AcousticAndClassicGuitarWood wood; + + @NotNull + private AcousticAndClassicGuitarPickUp pickUp; + + private AcousticAndClassicGuitarUpdateRequest( + @Nullable String title, + @Nullable InstrumentProgressStatus progressStatus, + @Nullable AddressRequest tradeAddress, + @Nullable Short qualityStatus, + @Nullable Integer price, + @Nullable Boolean hasAnomaly, + @Nullable String description, + @Nullable List deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags, + @Nullable AcousticAndClassicGuitarBrand brand, + @Nullable AcousticAndClassicGuitarModel model, + @Nullable AcousticAndClassicGuitarWood wood, + @Nullable AcousticAndClassicGuitarPickUp pickUp + ) { + super(title, progressStatus, tradeAddress, qualityStatus, price, hasAnomaly, description, + deletedImageIds, newImages, deletedHashtagIds, newHashtags); + this.brand = brand; + this.model = model; + this.wood = wood; + this.pickUp = pickUp; + } +} diff --git a/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/entity/AcousticAndClassicGuitar.java b/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/entity/AcousticAndClassicGuitar.java index dd1e93d..6ce3d2d 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/entity/AcousticAndClassicGuitar.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/acoustic_and_classic_guitar/entity/AcousticAndClassicGuitar.java @@ -5,7 +5,9 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarModel; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarPickUp; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarWood; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.user.entity.User; @@ -81,4 +83,13 @@ public static AcousticAndClassicGuitar create( price, hasAnomaly, description, brand, model, wood, pickUp ); } + + public void update(InstrumentUpdateRequest updateRequest) { + AcousticAndClassicGuitarUpdateRequest acousticAndClassicGuitarUpdateRequest = (AcousticAndClassicGuitarUpdateRequest)updateRequest; + super.update(updateRequest); + this.brand = acousticAndClassicGuitarUpdateRequest.getBrand(); + this.model = acousticAndClassicGuitarUpdateRequest.getModel(); + this.wood = acousticAndClassicGuitarUpdateRequest.getWood(); + this.pickUp = acousticAndClassicGuitarUpdateRequest.getPickUp(); + } } diff --git a/src/main/java/com/ajou/hertz/domain/instrument/controller/InstrumentController.java b/src/main/java/com/ajou/hertz/domain/instrument/controller/InstrumentController.java index cce2800..d79a7dc 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/controller/InstrumentController.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/controller/InstrumentController.java @@ -22,6 +22,7 @@ import com.ajou.hertz.common.auth.UserPrincipal; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.response.AcousticAndClassicGuitarResponse; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; @@ -469,6 +470,29 @@ public ElectricGuitarResponse updateElectricGuitarV1( return InstrumentMapper.toElectricGuitarResponse(electricGuitarDto); } + @Operation( + summary = "어쿠스틱 기타 매물 수정", + description = """ +

어쿠스틱 기타 매물 정보를 수정합니다. +

요청 시 multipart/form-data content-type으로 요쳥해야 합니다. +

변경하고자 하는 매물 정보만 request body에 담아 요청하면 됩니다. 요청 시 보내지 않은 필드는 수정하지 않습니다. + """, + security = @SecurityRequirement(name = "access-token") + ) + @PatchMapping("/acoustic-and-classic-guitars/{AcousticAndClassicGuitarId}") + public AcousticAndClassicGuitarResponse updateAcousticAndClassicGuitarV1( + @AuthenticationPrincipal UserPrincipal userPrincipal, + @Parameter(description = "수정하고자 하는 악기 매물의 id", example = "2") @PathVariable Long AcousticAndClassicGuitarId, + @ParameterObject @ModelAttribute @Valid AcousticAndClassicGuitarUpdateRequest updateRequest + ) { + AcousticAndClassicGuitarDto acousticAndClassicGuitarDto = instrumentCommandService.updateAcousticAndClassicGuitar( + userPrincipal.getUserId(), + AcousticAndClassicGuitarId, + updateRequest + ); + return InstrumentMapper.toAcousticAndClassicGuitarResponse(acousticAndClassicGuitarDto); + } + @Operation( summary = "악기 매물 삭제", description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.", diff --git a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentCommandService.java b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentCommandService.java index 5bdcc95..5fa4de4 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentCommandService.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentCommandService.java @@ -7,6 +7,7 @@ import org.springframework.transaction.annotation.Transactional; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.strategy.AcousticAndClassicGuitarCreationStrategy; @@ -232,6 +233,22 @@ public ElectricGuitarDto updateElectricGuitar( return (ElectricGuitarDto)updateInstrument(userId, electricGuitarId, updateRequest); } + /** + * 어쿠스틱 & 클래식 기타 매물 정보를 수정한다. + * + * @param userId 수정하고자 하는 유저의 id. 악기 판매자와 동일해야 한다. + * @param acousticAndClassicGuitarId 수정할 일렉 기타의 id + * @param updateRequest 수정하고자 하는 정보 + * @return 수정된 일렉 기타 매물 정보 + */ + public AcousticAndClassicGuitarDto updateAcousticAndClassicGuitar( + Long userId, + Long acousticAndClassicGuitarId, + AcousticAndClassicGuitarUpdateRequest updateRequest + ) { + return (AcousticAndClassicGuitarDto)updateInstrument(userId, acousticAndClassicGuitarId, updateRequest); + } + /** * 악기 매물을 삭제한다. * diff --git a/src/test/java/com/ajou/hertz/unit/domain/instrument/controller/InstrumentControllerTest.java b/src/test/java/com/ajou/hertz/unit/domain/instrument/controller/InstrumentControllerTest.java index dfaf5ab..b83bcdf 100644 --- a/src/test/java/com/ajou/hertz/unit/domain/instrument/controller/InstrumentControllerTest.java +++ b/src/test/java/com/ajou/hertz/unit/domain/instrument/controller/InstrumentControllerTest.java @@ -35,6 +35,7 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarWood; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierBrand; import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierType; @@ -705,6 +706,50 @@ public InstrumentControllerTest(MockMvc mvc) { verifyEveryMocksShouldHaveNoMoreInteractions(); } + @Test + void 수정할_어쿠스틱기타와_클래식기타_정보가_주어지고_주어진_정보로_매물_정보를_수정한다() throws Exception { + // given + long userId = 1L; + long acousticAndClassicGuitarId = 2L; + AcousticAndClassicGuitarUpdateRequest updateRequest = createAcousticAndClassicGuitarUpdateRequest(); + AcousticAndClassicGuitarDto expectedResult = createAcousticAndClassicGuitarDto(acousticAndClassicGuitarId, + userId); + given(instrumentCommandService.updateAcousticAndClassicGuitar( + eq(userId), + eq(acousticAndClassicGuitarId), + any(AcousticAndClassicGuitarUpdateRequest.class) + )).willReturn(expectedResult); + + // when & then + mvc.perform( + multipart("/api/instruments/acoustic-and-classic-guitars/{acousticAndClassicGuitarId}", + acousticAndClassicGuitarId) + .header(API_VERSION_HEADER_NAME, 1) + .param("title", updateRequest.getTitle()) + .param("progressStatus", String.valueOf(updateRequest.getProgressStatus())) + .param("qualityStatus", String.valueOf(updateRequest.getQualityStatus())) + .param("price", String.valueOf(updateRequest.getPrice())) + .param("hasAnomaly", String.valueOf(updateRequest.getHasAnomaly())) + .param("description", updateRequest.getDescription()) + .param("brand", String.valueOf(updateRequest.getBrand())) + .param("model", String.valueOf(updateRequest.getModel())) + .param("wood", String.valueOf(updateRequest.getWood())) + .param("pickUp", String.valueOf(updateRequest.getPickUp())) + .with(user(createTestUser(userId))) + .with(request -> { + request.setMethod("PATCH"); + return request; + }) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(expectedResult.getId())); + then(instrumentCommandService) + .should() + .updateAcousticAndClassicGuitar(eq(userId), eq(acousticAndClassicGuitarId), + any(AcousticAndClassicGuitarUpdateRequest.class)); + verifyEveryMocksShouldHaveNoMoreInteractions(); + } + @Test void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception { // given @@ -1046,4 +1091,25 @@ private ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest() throws E GuitarColor.RED ); } + + private AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpdateRequest() throws Exception { + return ReflectionUtils.createAcousticAndClassicGuitarUpdateRequest( + "Test AcousticAndClassicGuitar", + InstrumentProgressStatus.SOLD_OUT, + createAddressRequest(), + (short)3, + 550000, + true, + "description", + null, + null, + null, + null, + AcousticAndClassicGuitarBrand.CRAFTER, + AcousticAndClassicGuitarModel.CUTAWAY, + AcousticAndClassicGuitarWood.SOLID_WOOD, + AcousticAndClassicGuitarPickUp.MAGNETIC + ); + } + } diff --git a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentCommandServiceTest.java b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentCommandServiceTest.java index f7f8758..3e61e66 100644 --- a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentCommandServiceTest.java +++ b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentCommandServiceTest.java @@ -27,6 +27,7 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarPickUp; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarWood; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierBrand; @@ -334,6 +335,35 @@ class InstrumentCommandServiceTest { assertThat(result.getImages()).hasSize(initialImages.size() - deleteImageIds.size()); } + @Test + void 삭제할_이미지들의_id_리스트가_주어지고_어쿠스틱_매물_정보를_수정하면_악기_이미지들이_삭제된다() throws Exception { + // given + long userId = 1L; + long instrumentId = 2L; + List deleteImageIds = List.of(3L, 4L); + AcousticAndClassicGuitar AcousticAndClassicGuitar = createAcousticAndClassicGuitar(instrumentId, + createUser(userId)); + List initialImages = List.of( + createInstrumentImage(deleteImageIds.get(0), AcousticAndClassicGuitar), + createInstrumentImage(deleteImageIds.get(1), AcousticAndClassicGuitar) + ); + AcousticAndClassicGuitar.getImages().addAll(initialImages); + AcousticAndClassicGuitarUpdateRequest updateRequest = createAcousticAndClassicGuitarUpdateRequest( + deleteImageIds, null, null, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(AcousticAndClassicGuitar); + willDoNothing().given(instrumentImageCommandService).deleteAllByIds(deleteImageIds); + + // when + AcousticAndClassicGuitarDto result = sut.updateAcousticAndClassicGuitar(userId, instrumentId, updateRequest); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + then(instrumentImageCommandService).should().deleteAllByIds(deleteImageIds); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(result.getImages()).hasSize(initialImages.size() - deleteImageIds.size()); + } + @Test void 추가할_이미지들이_주어지고_매물_정보를_수정하면_새로운_악기_이미지들이_추가된다() throws Exception { // given @@ -749,4 +779,17 @@ private ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest( null, null, null, null ); } + + private AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpdateRequest( + @Nullable List deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags + ) throws Exception { + return ReflectionUtils.createAcousticAndClassicGuitarUpdateRequest( + null, null, null, null, null, null, null, + deletedImageIds, newImages, deletedHashtagIds, newHashtags, + null, null, null, null + ); + } } diff --git a/src/test/java/com/ajou/hertz/util/ReflectionUtils.java b/src/test/java/com/ajou/hertz/util/ReflectionUtils.java index dc2c781..2561436 100644 --- a/src/test/java/com/ajou/hertz/util/ReflectionUtils.java +++ b/src/test/java/com/ajou/hertz/util/ReflectionUtils.java @@ -27,6 +27,7 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.constant.AcousticAndClassicGuitarWood; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierBrand; @@ -882,6 +883,49 @@ public static ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest( ); } + public static AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpdateRequest( + @Nullable String title, + @Nullable InstrumentProgressStatus progressStatus, + @Nullable AddressRequest tradeAddress, + @Nullable Short qualityStatus, + @Nullable Integer price, + @Nullable Boolean hasAnomaly, + @Nullable String description, + @Nullable List deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags, + @Nullable AcousticAndClassicGuitarBrand brand, + @Nullable AcousticAndClassicGuitarModel model, + @Nullable AcousticAndClassicGuitarWood wood, + @Nullable AcousticAndClassicGuitarPickUp pickUp + ) throws Exception { + Constructor constructor = AcousticAndClassicGuitarUpdateRequest.class.getDeclaredConstructor( + String.class, InstrumentProgressStatus.class, AddressRequest.class, Short.class, + Integer.class, Boolean.class, String.class, List.class, List.class, List.class, List.class, + AcousticAndClassicGuitarBrand.class, AcousticAndClassicGuitarModel.class, + AcousticAndClassicGuitarWood.class, AcousticAndClassicGuitarPickUp.class + ); + constructor.setAccessible(true); + return constructor.newInstance( + title, + progressStatus, + tradeAddress, + qualityStatus, + price, + hasAnomaly, + description, + deletedImageIds, + newImages, + deletedHashtagIds, + newHashtags, + brand, + model, + wood, + pickUp + ); + } + public static SendUserAuthCodeRequest createSendUserAuthCodeRequest(String phoneNumber) throws Exception { Constructor constructor = SendUserAuthCodeRequest.class.getDeclaredConstructor(String.class);