Skip to content

Commit

Permalink
Feat: #121 음향장비 매물 수정 api 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
tinon1004 authored and Wo-ogie committed May 18, 2024
1 parent dbe680c commit 5088146
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.ajou.hertz.domain.instrument.audio_equipment.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.audio_equipment.constant.AudioEquipmentType;
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 AudioEquipmentUpdateRequest extends InstrumentUpdateRequest {

@NotNull
private AudioEquipmentType type;

private AudioEquipmentUpdateRequest(
@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 AudioEquipmentType type
) {
super(title, progressStatus, tradeAddress, qualityStatus, price, hasAnomaly, description,
deletedImageIds, newImages, deletedHashtagIds, newHashtags);
this.type = type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.ajou.hertz.common.entity.Address;
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
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;

Expand Down Expand Up @@ -57,4 +59,10 @@ public static AudioEquipment create(
qualityStatus, price, hasAnomaly, description, type
);
}

public void update(InstrumentUpdateRequest updateRequest) {
AudioEquipmentUpdateRequest audioEquipmentUpdateRequest = (AudioEquipmentUpdateRequest)updateRequest;
super.update(updateRequest);
this.type = audioEquipmentUpdateRequest.getType();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.ajou.hertz.domain.instrument.amplifier.dto.response.AmplifierResponse;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.response.AudioEquipmentResponse;
import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto;
Expand Down Expand Up @@ -555,6 +556,29 @@ public EffectorResponse updateEffectorV1(
return InstrumentMapper.toEffectorResponse(effectorDto);
}

@Operation(
summary = "음향장비 매물 수정",
description = """
<p>음향장비 매물 정보를 수정합니다.
<p>요청 시 <strong>multipart/form-data</strong> content-type으로 요쳥해야 합니다.
<p>변경하고자 하는 매물 정보만 request body에 담아 요청하면 됩니다. 요청 시 보내지 않은 필드는 수정하지 않습니다.
""",
security = @SecurityRequirement(name = "access-token")
)
@PatchMapping("/audio-equipments/{audioEquipmentsId}")
public AudioEquipmentResponse updateAudioEquipmentsV1(
@AuthenticationPrincipal UserPrincipal userPrincipal,
@Parameter(description = "수정하고자 하는 악기 매물의 id", example = "2") @PathVariable Long audioEquipmentsId,
@ParameterObject @ModelAttribute @Valid AudioEquipmentUpdateRequest updateRequest
) {
AudioEquipmentDto audioEquipmentDto = instrumentCommandService.updateAudioEquipment(
userPrincipal.getUserId(),
audioEquipmentsId,
updateRequest
);
return InstrumentMapper.toAudioEquipmentResponse(audioEquipmentDto);
}

@Operation(
summary = "악기 매물 삭제",
description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.ajou.hertz.domain.instrument.service;

import java.util.Collection;
import java.util.List;

import org.springframework.stereotype.Service;
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;
Expand All @@ -11,6 +17,7 @@
import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier;
import com.ajou.hertz.domain.instrument.amplifier.strategy.AmplifierCreationStrategy;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
import com.ajou.hertz.domain.instrument.audio_equipment.strategy.AudioEquipmentCreationStrategy;
Expand Down Expand Up @@ -42,12 +49,8 @@
import com.ajou.hertz.domain.instrument.strategy.InstrumentCreationStrategy;
import com.ajou.hertz.domain.user.entity.User;
import com.ajou.hertz.domain.user.service.UserQueryService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional
Expand Down Expand Up @@ -298,14 +301,30 @@ public EffectorDto updateEffector(
return (EffectorDto)updateInstrument(userId, effectorId, updateRequest);
}

/**
* 음향장비 매물 정보를 수정한다.
*
* @param userId 수정하고자 하는 유저의 id. 악기 판매자와 동일해야 한다.
* @param audioEquipmentsId 수정할 일렉 기타의 id
* @param updateRequest 수정하고자 하는 정보
* @return 수정된 일렉 기타 매물 정보
*/
public AudioEquipmentDto updateAudioEquipment(
Long userId,
Long audioEquipmentsId,
AudioEquipmentUpdateRequest updateRequest
) {
return (AudioEquipmentDto)updateInstrument(userId, audioEquipmentsId, updateRequest);
}

/**
* 판매자가 <code>sellerId</code>와 일치하는 모든 악기 매물 데이터에서 판매자를 제거한다. (회원 탈퇴 시 사용)
*
* @param sellerId id of seller(user)
*/
public void removeSellerFromInstruments(Long sellerId) {
instrumentRepository.findAllBySellerId(sellerId)
.forEach(Instrument::removeSeller);
.forEach(Instrument::removeSeller);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp;
Expand Down Expand Up @@ -833,6 +834,45 @@ public InstrumentControllerTest(MockMvc mvc) {
verifyEveryMocksShouldHaveNoMoreInteractions();
}

@Test
void 수정할_음향장비_정보가_주어지고_주어진_정보로_매물_정보를_수정한다() throws Exception {
// given
long userId = 1L;
long audioEquipmentsId = 2L;
AudioEquipmentUpdateRequest updateRequest = createAudioEquipmentUpdateRequest();
AudioEquipmentDto expectedResult = createAudioEquipmentDto(audioEquipmentsId, userId);
given(instrumentCommandService.updateAudioEquipment(
eq(userId),
eq(audioEquipmentsId),
any(AudioEquipmentUpdateRequest.class)
)).willReturn(expectedResult);

// when & then
mvc.perform(
multipart("/api/instruments/audio-equipments/{audioEquipmentsId}", audioEquipmentsId)
.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("type", String.valueOf(updateRequest.getType()))
.with(user(createTestUser(userId)))
.with(request -> {
request.setMethod("PATCH");
return request;
})
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(expectedResult.getId()));
then(instrumentCommandService)
.should()
.updateAudioEquipment(eq(userId), eq(audioEquipmentsId),
any(AudioEquipmentUpdateRequest.class));
verifyEveryMocksShouldHaveNoMoreInteractions();
}

@Test
void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception {
// given
Expand Down Expand Up @@ -1232,4 +1272,21 @@ private EffectorUpdateRequest createEffectorUpdateRequest() throws Exception {
);
}

private AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest() throws Exception {
return ReflectionUtils.createAudioEquipmentUpdateRequest(
"Test AudioEquipment",
InstrumentProgressStatus.SOLD_OUT,
createAddressRequest(),
(short)3,
550000,
true,
"description",
null,
null,
null,
null,
AudioEquipmentType.AUDIO_EQUIPMENT
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier;
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
Expand Down Expand Up @@ -456,6 +457,36 @@ class InstrumentCommandServiceTest {
assertThat(result.getImages()).hasSize(newImages.size());
}

@Test
void 추가할_이미지들이_주어지고_음향장비_정보를_수정하면_새로운_악기_이미지들이_추가된다() throws Exception {
// given
long userId = 1L;
long instrumentId = 2L;
AudioEquipment audioEquipment = createAudioEquipment(instrumentId, createUser(userId));
List<MultipartFile> newImages = List.of(
createMultipartFile(),
createMultipartFile()
);
List<InstrumentImage> newInstrumentImages = List.of(
createInstrumentImage(3L, audioEquipment),
createInstrumentImage(4L, audioEquipment)
);
AudioEquipmentUpdateRequest updateRequest = createAudioEquipmentUpdateRequest(List.of(), newImages, null, null);
given(instrumentQueryService.getInstrumentById(instrumentId))
.willReturn(audioEquipment);
given(instrumentImageCommandService.saveImages(audioEquipment, updateRequest.getNewImages()))
.willReturn(newInstrumentImages);

// when
AudioEquipmentDto result = sut.updateAudioEquipment(userId, instrumentId, updateRequest);

// then
then(instrumentQueryService).should().getInstrumentById(instrumentId);
then(instrumentImageCommandService).should().saveImages(audioEquipment, updateRequest.getNewImages());
verifyEveryMocksShouldHaveNoMoreInteractions();
assertThat(result.getImages()).hasSize(newImages.size());
}

@Test
void 삭제할_해시태그들의_id_리스트가_주어지고_매물_정보를_수정하면_해시태그가_삭제된다() throws Exception {
long userId = 1L;
Expand Down Expand Up @@ -880,4 +911,17 @@ private EffectorUpdateRequest createEffectorUpdateRequest(
null, null
);
}

private AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest(
@Nullable List<Long> deletedImageIds,
@Nullable List<MultipartFile> newImages,
@Nullable List<Long> deletedHashtagIds,
@Nullable List<String> newHashtags
) throws Exception {
return ReflectionUtils.createAudioEquipmentUpdateRequest(
null, null, null, null, null, null, null,
deletedImageIds, newImages, deletedHashtagIds, newHashtags,
null
);
}
}
37 changes: 37 additions & 0 deletions src/test/java/com/ajou/hertz/util/ReflectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.ajou.hertz.domain.instrument.audio_equipment.constant.AudioEquipmentType;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentUpdateRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest;
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand;
Expand Down Expand Up @@ -1139,6 +1140,42 @@ public static EffectorUpdateRequest createEffectorUpdateRequest(
);
}

public static AudioEquipmentUpdateRequest createAudioEquipmentUpdateRequest(
@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 AudioEquipmentType type
) throws Exception {
Constructor<AudioEquipmentUpdateRequest> constructor = AudioEquipmentUpdateRequest.class.getDeclaredConstructor(
String.class, InstrumentProgressStatus.class, AddressRequest.class, Short.class,
Integer.class, Boolean.class, String.class, List.class, List.class, List.class, List.class,
AudioEquipmentType.class
);
constructor.setAccessible(true);
return constructor.newInstance(
title,
progressStatus,
tradeAddress,
qualityStatus,
price,
hasAnomaly,
description,
deletedImageIds,
newImages,
deletedHashtagIds,
newHashtags,
type
);
}

public static SendUserAuthCodeRequest createSendUserAuthCodeRequest(String phoneNumber) throws Exception {
Constructor<SendUserAuthCodeRequest> constructor =
SendUserAuthCodeRequest.class.getDeclaredConstructor(String.class);
Expand Down

0 comments on commit 5088146

Please sign in to comment.