Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

앰프 매물 수정 api 구현 #119

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<Long> deletedImageIds,
@Nullable List<MultipartFile> newImages,
@Nullable List<Long> deletedHashtagIds,
@Nullable List<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -493,6 +494,29 @@ public AcousticAndClassicGuitarResponse updateAcousticAndClassicGuitarV1(
return InstrumentMapper.toAcousticAndClassicGuitarResponse(acousticAndClassicGuitarDto);
}

@Operation(
summary = "앰프 매물 수정",
description = """
<p>앰프 매물 정보를 수정합니다.
<p>요청 시 <strong>multipart/form-data</strong> content-type으로 요쳥해야 합니다.
<p>변경하고자 하는 매물 정보만 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 = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.",
Expand All @@ -510,4 +534,5 @@ public ResponseEntity<Void> deleteInstrumentV1(
instrumentCommandService.deleteInstrumentById(userPrincipal.getUserId(), instrumentId);
return ResponseEntity.noContent().build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

/**
* 악기 매물을 삭제한다.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<MultipartFile> newImages = List.of(
createMultipartFile(),
createMultipartFile()
);
List<InstrumentImage> 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;
Expand Down Expand Up @@ -792,4 +823,17 @@ private AcousticAndClassicGuitarUpdateRequest createAcousticAndClassicGuitarUpda
null, null, null, null
);
}

private AmplifierUpdateRequest createAmplifierUpdateRequest(
@Nullable List<Long> deletedImageIds,
@Nullable List<MultipartFile> newImages,
@Nullable List<Long> deletedHashtagIds,
@Nullable List<String> newHashtags
) throws Exception {
return ReflectionUtils.createAmplifierUpdateRequest(
null, null, null, null, null, null, null,
deletedImageIds, newImages, deletedHashtagIds, newHashtags,
null, null, null
);
}
}
51 changes: 46 additions & 5 deletions src/test/java/com/ajou/hertz/util/ReflectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<UpdatePasswordWithoutAuthenticationRequest> 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);
Expand Down Expand Up @@ -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<Long> deletedImageIds,
@Nullable List<MultipartFile> newImages,
@Nullable List<Long> deletedHashtagIds,
@Nullable List<String> newHashtags,
@Nullable AmplifierType type,
@Nullable AmplifierBrand brand,
@Nullable AmplifierUsage usage
) throws Exception {
Constructor<AmplifierUpdateRequest> 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<SendUserAuthCodeRequest> constructor =
SendUserAuthCodeRequest.class.getDeclaredConstructor(String.class);
Expand Down
Loading