From 9423e78465eecf7cd1584edb3aff8374f429b439 Mon Sep 17 00:00:00 2001 From: tinon1004 Date: Fri, 17 May 2024 23:24:44 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20#116=20=EC=95=B0=ED=94=84=20=EB=A7=A4?= =?UTF-8?q?=EB=AC=BC=20=EC=88=98=EC=A0=95=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/AmplifierUpdateRequest.java | 57 +++++++++++++++++ .../controller/InstrumentController.java | 25 ++++++++ .../service/InstrumentCommandService.java | 17 +++++ .../controller/InstrumentControllerTest.java | 62 +++++++++++++++++++ .../service/InstrumentCommandServiceTest.java | 44 +++++++++++++ .../com/ajou/hertz/util/ReflectionUtils.java | 51 +++++++++++++-- 6 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ajou/hertz/domain/instrument/amplifier/dto/request/AmplifierUpdateRequest.java diff --git a/src/main/java/com/ajou/hertz/domain/instrument/amplifier/dto/request/AmplifierUpdateRequest.java b/src/main/java/com/ajou/hertz/domain/instrument/amplifier/dto/request/AmplifierUpdateRequest.java new file mode 100644 index 0000000..52db172 --- /dev/null +++ b/src/main/java/com/ajou/hertz/domain/instrument/amplifier/dto/request/AmplifierUpdateRequest.java @@ -0,0 +1,57 @@ +package com.ajou.hertz.domain.instrument.amplifier.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.amplifier.constant.AmplifierBrand; +import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierType; +import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierUsage; +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 AmplifierUpdateRequest extends InstrumentUpdateRequest { + + @NotNull + private AmplifierType type; + + @NotNull + private AmplifierBrand brand; + + @NotNull + private AmplifierUsage usage; + + private AmplifierUpdateRequest( + @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 AmplifierType type, + @Nullable AmplifierBrand brand, + @Nullable AmplifierUsage usage + ) { + super(title, progressStatus, tradeAddress, qualityStatus, price, hasAnomaly, description, + deletedImageIds, newImages, deletedHashtagIds, newHashtags); + this.type = type; + this.brand = brand; + this.usage = usage; + } +} 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 d79a7dc..8d69d43 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 @@ -27,6 +27,7 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.response.AcousticAndClassicGuitarResponse; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierUpdateRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.response.AmplifierResponse; import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; @@ -493,6 +494,29 @@ public AcousticAndClassicGuitarResponse updateAcousticAndClassicGuitarV1( return InstrumentMapper.toAcousticAndClassicGuitarResponse(acousticAndClassicGuitarDto); } + @Operation( + summary = "앰프 매물 수정", + description = """ +

앰프 매물 정보를 수정합니다. +

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

변경하고자 하는 매물 정보만 request body에 담아 요청하면 됩니다. 요청 시 보내지 않은 필드는 수정하지 않습니다. + """, + security = @SecurityRequirement(name = "access-token") + ) + @PatchMapping("/amplifiers/{AmplifierId}") + public AmplifierResponse updateAmplifiersV1( + @AuthenticationPrincipal UserPrincipal userPrincipal, + @Parameter(description = "수정하고자 하는 악기 매물의 id", example = "2") @PathVariable Long AmplifierId, + @ParameterObject @ModelAttribute @Valid AmplifierUpdateRequest updateRequest + ) { + AmplifierDto amplifierDto = instrumentCommandService.updateAmplifier( + userPrincipal.getUserId(), + AmplifierId, + updateRequest + ); + return InstrumentMapper.toAmplifierResponse(amplifierDto); + } + @Operation( summary = "악기 매물 삭제", description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.", @@ -510,4 +534,5 @@ public ResponseEntity deleteInstrumentV1( instrumentCommandService.deleteInstrumentById(userPrincipal.getUserId(), instrumentId); return ResponseEntity.noContent().build(); } + } 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 5fa4de4..f9ee636 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 @@ -12,6 +12,7 @@ import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.strategy.AcousticAndClassicGuitarCreationStrategy; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierUpdateRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; import com.ajou.hertz.domain.instrument.amplifier.strategy.AmplifierCreationStrategy; @@ -249,6 +250,22 @@ public AcousticAndClassicGuitarDto updateAcousticAndClassicGuitar( return (AcousticAndClassicGuitarDto)updateInstrument(userId, acousticAndClassicGuitarId, updateRequest); } + /** + * 앰프 매물 정보를 수정한다. + * + * @param userId 수정하고자 하는 유저의 id. 악기 판매자와 동일해야 한다. + * @param amplifierId 수정할 일렉 기타의 id + * @param updateRequest 수정하고자 하는 정보 + * @return 수정된 일렉 기타 매물 정보 + */ + public AmplifierDto updateAmplifier( + Long userId, + Long amplifierId, + AmplifierUpdateRequest updateRequest + ) { + return (AmplifierDto)updateInstrument(userId, amplifierId, 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 7ebb1a9..933ae46 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 @@ -42,6 +42,7 @@ import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierUsage; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierUpdateRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType; import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; @@ -750,6 +751,48 @@ public InstrumentControllerTest(MockMvc mvc) { verifyEveryMocksShouldHaveNoMoreInteractions(); } + @Test + void 수정할_앰프_정보가_주어지고_주어진_정보로_매물_정보를_수정한다() throws Exception { + // given + long userId = 1L; + long amplifierId = 2L; + AmplifierUpdateRequest updateRequest = createAmplifierUpdateRequest(); + AmplifierDto expectedResult = createAmplifierDto(amplifierId, userId); + given(instrumentCommandService.updateAmplifier( + eq(userId), + eq(amplifierId), + any(AmplifierUpdateRequest.class) + )).willReturn(expectedResult); + + // when & then + mvc.perform( + multipart("/api/instruments/amplifiers/{amplifierId}", amplifierId) + .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("type", String.valueOf(updateRequest.getType())) + .param("brand", String.valueOf(updateRequest.getBrand())) + .param("usage", String.valueOf(updateRequest.getUsage())) + .with(user(createTestUser(userId))) + .with(request -> { + request.setMethod("PATCH"); + return request; + }) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(expectedResult.getId())); + then(instrumentCommandService) + .should() + .updateAmplifier(eq(userId), eq(amplifierId), + any(AmplifierUpdateRequest.class)); + verifyEveryMocksShouldHaveNoMoreInteractions(); + } + @Test void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception { // given @@ -1112,4 +1155,23 @@ private AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpda ); } + private AmplifierUpdateRequest createAmplifierUpdateRequest() throws Exception { + return ReflectionUtils.createAmplifierUpdateRequest( + "Test Amplifier", + InstrumentProgressStatus.SOLD_OUT, + createAddressRequest(), + (short)3, + 550000, + true, + "description", + null, + null, + null, + null, + AmplifierType.GUITAR, + AmplifierBrand.FENDER, + AmplifierUsage.HOME + ); + } + } 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 3e61e66..e3aee2b 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 @@ -34,6 +34,7 @@ import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierType; import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierUsage; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierUpdateRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType; @@ -394,6 +395,36 @@ class InstrumentCommandServiceTest { assertThat(result.getImages()).hasSize(newImages.size()); } + @Test + void 추가할_이미지들이_주어지고_앰프_정보를_수정하면_새로운_악기_이미지들이_추가된다() throws Exception { + // given + long userId = 1L; + long instrumentId = 2L; + Amplifier amplifier = createAmplifier(instrumentId, createUser(userId)); + List newImages = List.of( + createMultipartFile(), + createMultipartFile() + ); + List newInstrumentImages = List.of( + createInstrumentImage(3L, amplifier), + createInstrumentImage(4L, amplifier) + ); + AmplifierUpdateRequest updateRequest = createAmplifierUpdateRequest(List.of(), newImages, null, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(amplifier); + given(instrumentImageCommandService.saveImages(amplifier, updateRequest.getNewImages())) + .willReturn(newInstrumentImages); + + // when + AmplifierDto result = sut.updateAmplifier(userId, instrumentId, updateRequest); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + then(instrumentImageCommandService).should().saveImages(amplifier, updateRequest.getNewImages()); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(result.getImages()).hasSize(newImages.size()); + } + @Test void 삭제할_해시태그들의_id_리스트가_주어지고_매물_정보를_수정하면_해시태그가_삭제된다() throws Exception { long userId = 1L; @@ -792,4 +823,17 @@ private AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpda null, null, null, null ); } + + private AmplifierUpdateRequest createAmplifierUpdateRequest( + @Nullable List deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags + ) throws Exception { + return ReflectionUtils.createAmplifierUpdateRequest( + null, null, null, null, null, null, null, + deletedImageIds, newImages, deletedHashtagIds, newHashtags, + 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 2be6cb1..dac8c14 100644 --- a/src/test/java/com/ajou/hertz/util/ReflectionUtils.java +++ b/src/test/java/com/ajou/hertz/util/ReflectionUtils.java @@ -6,7 +6,6 @@ import java.util.List; import java.util.Set; -import com.ajou.hertz.domain.user.controller.UpdatePasswordWithoutAuthenticationRequest; import org.springframework.lang.Nullable; import org.springframework.web.multipart.MultipartFile; @@ -42,6 +41,7 @@ import com.ajou.hertz.domain.instrument.amplifier.constant.AmplifierUsage; import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierUpdateRequest; import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType; @@ -84,6 +84,7 @@ import com.ajou.hertz.domain.practice_room.entity.PracticeRoomImage; import com.ajou.hertz.domain.user.constant.Gender; import com.ajou.hertz.domain.user.constant.RoleType; +import com.ajou.hertz.domain.user.controller.UpdatePasswordWithoutAuthenticationRequest; import com.ajou.hertz.domain.user.dto.UserDto; import com.ajou.hertz.domain.user.dto.request.SignUpRequest; import com.ajou.hertz.domain.user.entity.User; @@ -669,12 +670,12 @@ public static SignUpRequest createSignUpRequest( } public static UpdatePasswordWithoutAuthenticationRequest createUpdatePasswordWithoutAuthenticationRequest( - String phoneNumber, - String password, - String userAuthCode + String phoneNumber, + String password, + String userAuthCode ) throws Exception { Constructor constructor = UpdatePasswordWithoutAuthenticationRequest.class.getDeclaredConstructor( - String.class, String.class, String.class + String.class, String.class, String.class ); constructor.setAccessible(true); return constructor.newInstance(phoneNumber, password, userAuthCode); @@ -1059,6 +1060,46 @@ public static AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuit ); } + public static AmplifierUpdateRequest createAmplifierUpdateRequest( + @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 AmplifierType type, + @Nullable AmplifierBrand brand, + @Nullable AmplifierUsage usage + ) throws Exception { + Constructor constructor = AmplifierUpdateRequest.class.getDeclaredConstructor( + String.class, InstrumentProgressStatus.class, AddressRequest.class, Short.class, + Integer.class, Boolean.class, String.class, List.class, List.class, List.class, List.class, + AmplifierType.class, AmplifierBrand.class, AmplifierUsage.class + ); + constructor.setAccessible(true); + return constructor.newInstance( + title, + progressStatus, + tradeAddress, + qualityStatus, + price, + hasAnomaly, + description, + deletedImageIds, + newImages, + deletedHashtagIds, + newHashtags, + type, + brand, + usage + ); + } + public static SendUserAuthCodeRequest createSendUserAuthCodeRequest(String phoneNumber) throws Exception { Constructor constructor = SendUserAuthCodeRequest.class.getDeclaredConstructor(String.class);