Skip to content

Commit 8d3205b

Browse files
committed
Feat: #121 음향장비 매물 수정 api 구현
1 parent 08e05c0 commit 8d3205b

File tree

7 files changed

+240
-6
lines changed

7 files changed

+240
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.ajou.hertz.domain.instrument.audio_equipment.dto.request;
2+
3+
import java.util.List;
4+
5+
import org.springframework.lang.Nullable;
6+
import org.springframework.web.multipart.MultipartFile;
7+
8+
import com.ajou.hertz.common.dto.request.AddressRequest;
9+
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
10+
import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus;
11+
import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest;
12+
13+
import jakarta.validation.constraints.NotNull;
14+
import lombok.AccessLevel;
15+
import lombok.Getter;
16+
import lombok.NoArgsConstructor;
17+
import lombok.Setter;
18+
19+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
20+
@Setter
21+
@Getter
22+
public class AudioEquipmentUpdateRequest extends InstrumentUpdateRequest {
23+
24+
@NotNull
25+
private AudioEquipmentType type;
26+
27+
private AudioEquipmentUpdateRequest(
28+
@Nullable String title,
29+
@Nullable InstrumentProgressStatus progressStatus,
30+
@Nullable AddressRequest tradeAddress,
31+
@Nullable Short qualityStatus,
32+
@Nullable Integer price,
33+
@Nullable Boolean hasAnomaly,
34+
@Nullable String description,
35+
@Nullable List<Long> deletedImageIds,
36+
@Nullable List<MultipartFile> newImages,
37+
@Nullable List<Long> deletedHashtagIds,
38+
@Nullable List<String> newHashtags,
39+
@Nullable AudioEquipmentType type
40+
) {
41+
super(title, progressStatus, tradeAddress, qualityStatus, price, hasAnomaly, description,
42+
deletedImageIds, newImages, deletedHashtagIds, newHashtags);
43+
this.type = type;
44+
}
45+
}

src/main/java/com/ajou/hertz/domain/instrument/audio_equipment/entity/AudioEquipment.java

+8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.ajou.hertz.common.entity.Address;
44
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
5+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
56
import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus;
7+
import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest;
68
import com.ajou.hertz.domain.instrument.entity.Instrument;
79
import com.ajou.hertz.domain.user.entity.User;
810

@@ -57,4 +59,10 @@ public static AudioEquipment create(
5759
qualityStatus, price, hasAnomaly, description, type
5860
);
5961
}
62+
63+
public void update(InstrumentUpdateRequest updateRequest) {
64+
AudioEquipmentUpdateRequest audioEquipmentUpdateRequest = (AudioEquipmentUpdateRequest)updateRequest;
65+
super.update(updateRequest);
66+
this.type = audioEquipmentUpdateRequest.getType();
67+
}
6068
}

src/main/java/com/ajou/hertz/domain/instrument/controller/InstrumentController.java

+24
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.ajou.hertz.domain.instrument.amplifier.dto.response.AmplifierResponse;
3333
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
3434
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
35+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
3536
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
3637
import com.ajou.hertz.domain.instrument.audio_equipment.dto.response.AudioEquipmentResponse;
3738
import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto;
@@ -541,6 +542,29 @@ public EffectorResponse updateEffectorV1(
541542
return InstrumentMapper.toEffectorResponse(effectorDto);
542543
}
543544

545+
@Operation(
546+
summary = "음향장비 매물 수정",
547+
description = """
548+
<p>음향장비 매물 정보를 수정합니다.
549+
<p>요청 시 <strong>multipart/form-data</strong> content-type으로 요쳥해야 합니다.
550+
<p>변경하고자 하는 매물 정보만 request body에 담아 요청하면 됩니다. 요청 시 보내지 않은 필드는 수정하지 않습니다.
551+
""",
552+
security = @SecurityRequirement(name = "access-token")
553+
)
554+
@PatchMapping("/audio-equipments/{audioEquipmentsId}")
555+
public AudioEquipmentResponse updateAudioEquipmentsV1(
556+
@AuthenticationPrincipal UserPrincipal userPrincipal,
557+
@Parameter(description = "수정하고자 하는 악기 매물의 id", example = "2") @PathVariable Long audioEquipmentsId,
558+
@ParameterObject @ModelAttribute @Valid AudioEquipmentUpdateRequest updateRequest
559+
) {
560+
AudioEquipmentDto audioEquipmentDto = instrumentCommandService.updateAudioEquipment(
561+
userPrincipal.getUserId(),
562+
audioEquipmentsId,
563+
updateRequest
564+
);
565+
return InstrumentMapper.toAudioEquipmentResponse(audioEquipmentDto);
566+
}
567+
544568
@Operation(
545569
summary = "악기 매물 삭제",
546570
description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.",

src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentCommandService.java

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.ajou.hertz.domain.instrument.service;
22

3+
import java.util.Collection;
4+
import java.util.List;
5+
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
8+
39
import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto;
410
import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarUpdateRequest;
511
import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest;
@@ -11,6 +17,7 @@
1117
import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier;
1218
import com.ajou.hertz.domain.instrument.amplifier.strategy.AmplifierCreationStrategy;
1319
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
20+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
1421
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
1522
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
1623
import com.ajou.hertz.domain.instrument.audio_equipment.strategy.AudioEquipmentCreationStrategy;
@@ -41,12 +48,8 @@
4148
import com.ajou.hertz.domain.instrument.strategy.InstrumentCreationStrategy;
4249
import com.ajou.hertz.domain.user.entity.User;
4350
import com.ajou.hertz.domain.user.service.UserQueryService;
44-
import lombok.RequiredArgsConstructor;
45-
import org.springframework.stereotype.Service;
46-
import org.springframework.transaction.annotation.Transactional;
4751

48-
import java.util.Collection;
49-
import java.util.List;
52+
import lombok.RequiredArgsConstructor;
5053

5154
@RequiredArgsConstructor
5255
@Transactional
@@ -281,14 +284,30 @@ public EffectorDto updateEffector(
281284
return (EffectorDto)updateInstrument(userId, effectorId, updateRequest);
282285
}
283286

287+
/**
288+
* 음향장비 매물 정보를 수정한다.
289+
*
290+
* @param userId 수정하고자 하는 유저의 id. 악기 판매자와 동일해야 한다.
291+
* @param audioEquipmentsId 수정할 일렉 기타의 id
292+
* @param updateRequest 수정하고자 하는 정보
293+
* @return 수정된 일렉 기타 매물 정보
294+
*/
295+
public AudioEquipmentDto updateAudioEquipment(
296+
Long userId,
297+
Long audioEquipmentsId,
298+
AudioEquipmentUpdateRequest updateRequest
299+
) {
300+
return (AudioEquipmentDto)updateInstrument(userId, audioEquipmentsId, updateRequest);
301+
}
302+
284303
/**
285304
* 판매자가 <code>sellerId</code>와 일치하는 모든 악기 매물 데이터에서 판매자를 제거한다. (회원 탈퇴 시 사용)
286305
*
287306
* @param sellerId id of seller(user)
288307
*/
289308
public void removeSellerFromInstruments(Long sellerId) {
290309
instrumentRepository.findAllBySellerId(sellerId)
291-
.forEach(Instrument::removeSeller);
310+
.forEach(Instrument::removeSeller);
292311
}
293312

294313
/**

src/test/java/com/ajou/hertz/unit/domain/instrument/controller/InstrumentControllerTest.java

+57
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
4848
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
4949
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
50+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
5051
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
5152
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
5253
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp;
@@ -833,6 +834,45 @@ public InstrumentControllerTest(MockMvc mvc) {
833834
verifyEveryMocksShouldHaveNoMoreInteractions();
834835
}
835836

837+
@Test
838+
void 수정할_음향장비_정보가_주어지고_주어진_정보로_매물_정보를_수정한다() throws Exception {
839+
// given
840+
long userId = 1L;
841+
long audioEquipmentsId = 2L;
842+
AudioEquipmentUpdateRequest updateRequest = createAudioEquipmentUpdateRequest();
843+
AudioEquipmentDto expectedResult = createAudioEquipmentDto(audioEquipmentsId, userId);
844+
given(instrumentCommandService.updateAudioEquipment(
845+
eq(userId),
846+
eq(audioEquipmentsId),
847+
any(AudioEquipmentUpdateRequest.class)
848+
)).willReturn(expectedResult);
849+
850+
// when & then
851+
mvc.perform(
852+
multipart("/api/instruments/audio-equipments/{audioEquipmentsId}", audioEquipmentsId)
853+
.header(API_VERSION_HEADER_NAME, 1)
854+
.param("title", updateRequest.getTitle())
855+
.param("progressStatus", String.valueOf(updateRequest.getProgressStatus()))
856+
.param("qualityStatus", String.valueOf(updateRequest.getQualityStatus()))
857+
.param("price", String.valueOf(updateRequest.getPrice()))
858+
.param("hasAnomaly", String.valueOf(updateRequest.getHasAnomaly()))
859+
.param("description", updateRequest.getDescription())
860+
.param("type", String.valueOf(updateRequest.getType()))
861+
.with(user(createTestUser(userId)))
862+
.with(request -> {
863+
request.setMethod("PATCH");
864+
return request;
865+
})
866+
)
867+
.andExpect(status().isOk())
868+
.andExpect(jsonPath("$.id").value(expectedResult.getId()));
869+
then(instrumentCommandService)
870+
.should()
871+
.updateAudioEquipment(eq(userId), eq(audioEquipmentsId),
872+
any(AudioEquipmentUpdateRequest.class));
873+
verifyEveryMocksShouldHaveNoMoreInteractions();
874+
}
875+
836876
@Test
837877
void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception {
838878
// given
@@ -1232,4 +1272,21 @@ private EffectorUpdateRequest createEffectorUpdateRequest() throws Exception {
12321272
);
12331273
}
12341274

1275+
private AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest() throws Exception {
1276+
return ReflectionUtils.createAudioEquipmentUpdateRequest(
1277+
"Test AudioEquipment",
1278+
InstrumentProgressStatus.SOLD_OUT,
1279+
createAddressRequest(),
1280+
(short)3,
1281+
550000,
1282+
true,
1283+
"description",
1284+
null,
1285+
null,
1286+
null,
1287+
null,
1288+
AudioEquipmentType.AUDIO_EQUIPMENT
1289+
);
1290+
}
1291+
12351292
}

src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentCommandServiceTest.java

+44
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier;
4040
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
4141
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
42+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
4243
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
4344
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
4445
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
@@ -456,6 +457,36 @@ class InstrumentCommandServiceTest {
456457
assertThat(result.getImages()).hasSize(newImages.size());
457458
}
458459

460+
@Test
461+
void 추가할_이미지들이_주어지고_음향장비_정보를_수정하면_새로운_악기_이미지들이_추가된다() throws Exception {
462+
// given
463+
long userId = 1L;
464+
long instrumentId = 2L;
465+
AudioEquipment audioEquipment = createAudioEquipment(instrumentId, createUser(userId));
466+
List<MultipartFile> newImages = List.of(
467+
createMultipartFile(),
468+
createMultipartFile()
469+
);
470+
List<InstrumentImage> newInstrumentImages = List.of(
471+
createInstrumentImage(3L, audioEquipment),
472+
createInstrumentImage(4L, audioEquipment)
473+
);
474+
AudioEquipmentUpdateRequest updateRequest = createAudioEquipmentUpdateRequest(List.of(), newImages, null, null);
475+
given(instrumentQueryService.getInstrumentById(instrumentId))
476+
.willReturn(audioEquipment);
477+
given(instrumentImageCommandService.saveImages(audioEquipment, updateRequest.getNewImages()))
478+
.willReturn(newInstrumentImages);
479+
480+
// when
481+
AudioEquipmentDto result = sut.updateAudioEquipment(userId, instrumentId, updateRequest);
482+
483+
// then
484+
then(instrumentQueryService).should().getInstrumentById(instrumentId);
485+
then(instrumentImageCommandService).should().saveImages(audioEquipment, updateRequest.getNewImages());
486+
verifyEveryMocksShouldHaveNoMoreInteractions();
487+
assertThat(result.getImages()).hasSize(newImages.size());
488+
}
489+
459490
@Test
460491
void 삭제할_해시태그들의_id_리스트가_주어지고_매물_정보를_수정하면_해시태그가_삭제된다() throws Exception {
461492
long userId = 1L;
@@ -880,4 +911,17 @@ private EffectorUpdateRequest createEffectorUpdateRequest(
880911
null, null
881912
);
882913
}
914+
915+
private AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest(
916+
@Nullable List<Long> deletedImageIds,
917+
@Nullable List<MultipartFile> newImages,
918+
@Nullable List<Long> deletedHashtagIds,
919+
@Nullable List<String> newHashtags
920+
) throws Exception {
921+
return ReflectionUtils.createAudioEquipmentUpdateRequest(
922+
null, null, null, null, null, null, null,
923+
deletedImageIds, newImages, deletedHashtagIds, newHashtags,
924+
null
925+
);
926+
}
883927
}

src/test/java/com/ajou/hertz/util/ReflectionUtils.java

+37
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
4848
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
4949
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
50+
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
5051
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
5152
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
5253
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
@@ -1139,6 +1140,42 @@ public static EffectorUpdateRequest createEffectorUpdateRequest(
11391140
);
11401141
}
11411142

1143+
public static AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest(
1144+
@Nullable String title,
1145+
@Nullable InstrumentProgressStatus progressStatus,
1146+
@Nullable AddressRequest tradeAddress,
1147+
@Nullable Short qualityStatus,
1148+
@Nullable Integer price,
1149+
@Nullable Boolean hasAnomaly,
1150+
@Nullable String description,
1151+
@Nullable List<Long> deletedImageIds,
1152+
@Nullable List<MultipartFile> newImages,
1153+
@Nullable List<Long> deletedHashtagIds,
1154+
@Nullable List<String> newHashtags,
1155+
@Nullable AudioEquipmentType type
1156+
) throws Exception {
1157+
Constructor<AudioEquipmentUpdateRequest> constructor = AudioEquipmentUpdateRequest.class.getDeclaredConstructor(
1158+
String.class, InstrumentProgressStatus.class, AddressRequest.class, Short.class,
1159+
Integer.class, Boolean.class, String.class, List.class, List.class, List.class, List.class,
1160+
AudioEquipmentType.class
1161+
);
1162+
constructor.setAccessible(true);
1163+
return constructor.newInstance(
1164+
title,
1165+
progressStatus,
1166+
tradeAddress,
1167+
qualityStatus,
1168+
price,
1169+
hasAnomaly,
1170+
description,
1171+
deletedImageIds,
1172+
newImages,
1173+
deletedHashtagIds,
1174+
newHashtags,
1175+
type
1176+
);
1177+
}
1178+
11421179
public static SendUserAuthCodeRequest createSendUserAuthCodeRequest(String phoneNumber) throws Exception {
11431180
Constructor<SendUserAuthCodeRequest> constructor =
11441181
SendUserAuthCodeRequest.class.getDeclaredConstructor(String.class);

0 commit comments

Comments
 (0)