diff --git a/src/main/java/com/ajou/hertz/common/exception/constant/CustomExceptionType.java b/src/main/java/com/ajou/hertz/common/exception/constant/CustomExceptionType.java index 8557cf6..319d35e 100644 --- a/src/main/java/com/ajou/hertz/common/exception/constant/CustomExceptionType.java +++ b/src/main/java/com/ajou/hertz/common/exception/constant/CustomExceptionType.java @@ -52,7 +52,8 @@ public enum CustomExceptionType { * 악기 관련 예외 */ INSTRUMENT_NOT_FOUND_BY_ID(2600, "일치하는 매물 정보를 찾을 수 없습니다."), - INSTRUMENT_DELETE_PERMISSION_DENIED(2601, "악기 매물을 삭제할 권한이 없습니다. 매물은 판매자 본인만 삭제할 수 있습니다."); + INSTRUMENT_DELETE_PERMISSION_DENIED(2601, "악기 매물을 삭제할 권한이 없습니다. 매물은 판매자 본인만 삭제할 수 있습니다."), + INSTRUMENT_UPDATE_PERMISSION_DENIED(2602, "악기 매물 정보를 수정할 권한이 없습니다. 매물 정보는 판매자 본인만 수정할 수 있습니다"); private final Integer code; private final String message; 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 a8f2b94..5a1c17b 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 @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,34 +20,35 @@ import org.springframework.web.bind.annotation.RestController; import com.ajou.hertz.common.auth.UserPrincipal; -import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; -import com.ajou.hertz.domain.instrument.dto.InstrumentDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; 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; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; 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; +import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; 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; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.response.BassGuitarResponse; +import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; +import com.ajou.hertz.domain.instrument.dto.InstrumentDto; +import com.ajou.hertz.domain.instrument.dto.response.InstrumentResponse; +import com.ajou.hertz.domain.instrument.dto.response.InstrumentSummaryResponse; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.response.AcousticAndClassicGuitarResponse; -import com.ajou.hertz.domain.instrument.amplifier.dto.response.AmplifierResponse; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.response.AudioEquipmentResponse; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.response.BassGuitarResponse; import com.ajou.hertz.domain.instrument.effector.dto.response.EffectorResponse; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.electric_guitar.dto.response.ElectricGuitarResponse; -import com.ajou.hertz.domain.instrument.dto.response.InstrumentResponse; -import com.ajou.hertz.domain.instrument.dto.response.InstrumentSummaryResponse; import com.ajou.hertz.domain.instrument.mapper.InstrumentMapper; import com.ajou.hertz.domain.instrument.service.InstrumentCommandService; import com.ajou.hertz.domain.instrument.service.InstrumentQueryService; @@ -416,6 +418,29 @@ public ResponseEntity createNewAudioEquipmentV1( .body(InstrumentMapper.toAudioEquipmentResponse(audioEquipment)); } + @Operation( + summary = "일렉 기타 매물 수정", + description = """ +

일렉 기타 매물 정보를 수정합니다. +

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

변경하고자 하는 매물 정보만 request body에 담아 요청하면 됩니다. 요청 시 보내지 않은 필드는 수정하지 않습니다. + """, + security = @SecurityRequirement(name = "access-token") + ) + @PatchMapping("/electric-guitars/{electricGuitarId}") + public ElectricGuitarResponse updateElectricGuitarV1( + @AuthenticationPrincipal UserPrincipal userPrincipal, + @Parameter(description = "수정하고자 하는 악기 매물의 id", example = "2") @PathVariable Long electricGuitarId, + @ParameterObject @ModelAttribute @Valid ElectricGuitarUpdateRequest updateRequest + ) { + ElectricGuitarDto electricGuitarDto = instrumentCommandService.updateElectricGuitar( + userPrincipal.getUserId(), + electricGuitarId, + updateRequest + ); + return InstrumentMapper.toElectricGuitarResponse(electricGuitarDto); + } + @Operation( summary = "악기 매물 삭제", description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.", diff --git a/src/main/java/com/ajou/hertz/domain/instrument/dto/request/InstrumentUpdateRequest.java b/src/main/java/com/ajou/hertz/domain/instrument/dto/request/InstrumentUpdateRequest.java new file mode 100644 index 0000000..28771fc --- /dev/null +++ b/src/main/java/com/ajou/hertz/domain/instrument/dto/request/InstrumentUpdateRequest.java @@ -0,0 +1,72 @@ +package com.ajou.hertz.domain.instrument.dto.request; + +import java.util.List; + +import org.hibernate.validator.constraints.Length; +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.constant.InstrumentProgressStatus; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Setter +@Getter +public abstract class InstrumentUpdateRequest { + + @Schema(description = "제목", example = "펜더 로드원 텔레캐스터") + @Nullable + private String title; + + @Nullable + private InstrumentProgressStatus progressStatus; + + @Schema(description = "거래 장소") + @Nullable + private AddressRequest tradeAddress; + + @Schema(description = "악기 상태. 1~5 단계로 구성됩니다.", example = "3") + @Min(1) + @Max(5) + @Nullable + private Short qualityStatus; + + @Schema(description = "가격", example = "527000") + @Nullable + private Integer price; + + @Schema(description = "특이사항 유무", example = "true") + @Nullable + private Boolean hasAnomaly; + + @Schema(description = "특이사항 및 상세 설명. 내용이 없을 경우에는 빈 문자열로 요청하면 됩니다.", example = "14년 시리얼 펜더 로드원 50 텔레입니다. 기존 ...") + @Nullable + private String description; + + @Schema(description = "삭제한 이미지의 id 리스트") + @Nullable + private List deletedImageIds; + + @Schema(description = "새로 추가된 악기 이미지 리스트") + @Nullable + private List newImages; + + @Schema(description = "삭제한 해시태그의 id 리스트") + @Nullable + private List deletedHashtagIds; + + @Schema(description = "새로 추가된 악기 해시태그(각 해시태그마다 최대 10글자) 리스트", example = "[\"펜더\", \"Fender\"]") + @Nullable + private List<@NotBlank @Length(max = 10) String> newHashtags; +} diff --git a/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/dto/request/CreateNewElectricGuitarRequest.java b/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/dto/request/CreateNewElectricGuitarRequest.java index da09259..0e5546a 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/dto/request/CreateNewElectricGuitarRequest.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/dto/request/CreateNewElectricGuitarRequest.java @@ -31,7 +31,7 @@ public class CreateNewElectricGuitarRequest extends CreateNewInstrumentRequest deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags, + @Nullable ElectricGuitarBrand brand, + @Nullable ElectricGuitarModel model, + @Nullable Short productionYear, + @Nullable GuitarColor color + ) { + super(title, progressStatus, tradeAddress, qualityStatus, price, hasAnomaly, description, + deletedImageIds, newImages, deletedHashtagIds, newHashtags); + this.brand = brand; + this.model = model; + this.productionYear = productionYear; + this.color = color; + } +} diff --git a/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/entity/ElectricGuitar.java b/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/entity/ElectricGuitar.java index 48d47af..0827b58 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/entity/ElectricGuitar.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/electric_guitar/entity/ElectricGuitar.java @@ -3,8 +3,10 @@ import com.ajou.hertz.common.entity.Address; import com.ajou.hertz.domain.instrument.constant.GuitarColor; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.user.entity.User; @@ -79,4 +81,13 @@ public static ElectricGuitar create( price, hasAnomaly, description, brand, model, productionYear, color ); } + + public void update(InstrumentUpdateRequest updateRequest) { + ElectricGuitarUpdateRequest electricGuitarUpdateRequest = (ElectricGuitarUpdateRequest)updateRequest; + super.update(updateRequest); + this.brand = electricGuitarUpdateRequest.getBrand(); + this.model = electricGuitarUpdateRequest.getModel(); + this.productionYear = electricGuitarUpdateRequest.getProductionYear(); + this.color = electricGuitarUpdateRequest.getColor(); + } } diff --git a/src/main/java/com/ajou/hertz/domain/instrument/entity/Instrument.java b/src/main/java/com/ajou/hertz/domain/instrument/entity/Instrument.java index cd8c569..6e931ea 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/entity/Instrument.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/entity/Instrument.java @@ -1,8 +1,11 @@ package com.ajou.hertz.domain.instrument.entity; +import org.springframework.util.StringUtils; + import com.ajou.hertz.common.entity.Address; import com.ajou.hertz.common.entity.TimeTrackedBaseEntity; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest; import com.ajou.hertz.domain.user.entity.User; import jakarta.persistence.Column; @@ -88,4 +91,25 @@ protected Instrument( this.hasAnomaly = hasAnomaly; this.description = description; } + + public void update(InstrumentUpdateRequest updateRequest) { + if (StringUtils.hasText(updateRequest.getTitle())) { + this.title = updateRequest.getTitle(); + } + if (updateRequest.getTradeAddress() != null) { + this.tradeAddress = updateRequest.getTradeAddress().toEntity(); + } + if (updateRequest.getQualityStatus() != null) { + this.qualityStatus = updateRequest.getQualityStatus(); + } + if (updateRequest.getPrice() != null) { + this.price = updateRequest.getPrice(); + } + if (updateRequest.getHasAnomaly() != null) { + this.hasAnomaly = updateRequest.getHasAnomaly(); + } + if (updateRequest.getDescription() != null) { + this.description = updateRequest.getDescription(); + } + } } diff --git a/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentHashtags.java b/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentHashtags.java index ec00fa4..3aedf14 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentHashtags.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentHashtags.java @@ -1,5 +1,6 @@ package com.ajou.hertz.domain.instrument.entity; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -21,6 +22,10 @@ public void addAll(List hashtags) { content.addAll(hashtags); } + public void deleteAllByIds(Collection ids) { + content.removeIf(hashtag -> ids.contains(hashtag.getId())); + } + public List toStrings() { return content.stream() .map(InstrumentHashtag::getContent) diff --git a/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentImages.java b/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentImages.java index 0403cfc..c21cfe6 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentImages.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/entity/InstrumentImages.java @@ -1,5 +1,6 @@ package com.ajou.hertz.domain.instrument.entity; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -23,6 +24,10 @@ public void addAll(List images) { content.addAll(images); } + public void deleteAllByIds(Collection ids) { + content.removeIf(image -> ids.contains(image.getId())); + } + public List toDtos() { return content.stream() .map(InstrumentImageDto::from) diff --git a/src/main/java/com/ajou/hertz/domain/instrument/exception/InstrumentUpdatePermissionDeniedException.java b/src/main/java/com/ajou/hertz/domain/instrument/exception/InstrumentUpdatePermissionDeniedException.java new file mode 100644 index 0000000..161193d --- /dev/null +++ b/src/main/java/com/ajou/hertz/domain/instrument/exception/InstrumentUpdatePermissionDeniedException.java @@ -0,0 +1,13 @@ +package com.ajou.hertz.domain.instrument.exception; + +import com.ajou.hertz.common.exception.ForbiddenException; +import com.ajou.hertz.common.exception.constant.CustomExceptionType; + +public class InstrumentUpdatePermissionDeniedException extends ForbiddenException { + public InstrumentUpdatePermissionDeniedException(Long userId, Long instrumentId) { + super( + CustomExceptionType.INSTRUMENT_UPDATE_PERMISSION_DENIED, + String.format("userId=%s instrumentId=%s", userId, instrumentId) + ); + } +} diff --git a/src/main/java/com/ajou/hertz/domain/instrument/repository/InstrumentImageRepository.java b/src/main/java/com/ajou/hertz/domain/instrument/repository/InstrumentImageRepository.java index 80a86e7..cec3e19 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/repository/InstrumentImageRepository.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/repository/InstrumentImageRepository.java @@ -1,5 +1,6 @@ package com.ajou.hertz.domain.instrument.repository; +import java.util.Collection; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,4 +10,6 @@ public interface InstrumentImageRepository extends JpaRepository { List findAllByInstrument_Id(Long instrumentId); + + List findAllByIdIn(Collection ids); } 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 502e665..5bdcc95 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 @@ -1,43 +1,46 @@ 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 org.springframework.web.multipart.MultipartFile; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; -import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; -import com.ajou.hertz.domain.instrument.dto.request.CreateNewInstrumentRequest; 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.CreateNewAmplifierRequest; 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.CreateNewAudioEquipmentRequest; import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; +import com.ajou.hertz.domain.instrument.audio_equipment.strategy.AudioEquipmentCreationStrategy; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; +import com.ajou.hertz.domain.instrument.bass_guitar.strategy.BassGuitarCreationStrategy; +import com.ajou.hertz.domain.instrument.dto.InstrumentDto; +import com.ajou.hertz.domain.instrument.dto.request.CreateNewInstrumentRequest; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentUpdateRequest; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; +import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; import com.ajou.hertz.domain.instrument.effector.entity.Effector; +import com.ajou.hertz.domain.instrument.effector.strategy.EffectorCreationStrategy; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar; +import com.ajou.hertz.domain.instrument.electric_guitar.strategy.ElectricGuitarCreationStrategy; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag; import com.ajou.hertz.domain.instrument.entity.InstrumentImage; import com.ajou.hertz.domain.instrument.exception.InstrumentDeletePermissionDeniedException; +import com.ajou.hertz.domain.instrument.exception.InstrumentUpdatePermissionDeniedException; import com.ajou.hertz.domain.instrument.mapper.InstrumentMapper; -import com.ajou.hertz.domain.instrument.repository.InstrumentHashtagRepository; import com.ajou.hertz.domain.instrument.repository.InstrumentRepository; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.strategy.AcousticAndClassicGuitarCreationStrategy; -import com.ajou.hertz.domain.instrument.amplifier.strategy.AmplifierCreationStrategy; -import com.ajou.hertz.domain.instrument.audio_equipment.strategy.AudioEquipmentCreationStrategy; -import com.ajou.hertz.domain.instrument.bass_guitar.strategy.BassGuitarCreationStrategy; -import com.ajou.hertz.domain.instrument.effector.strategy.EffectorCreationStrategy; -import com.ajou.hertz.domain.instrument.electric_guitar.strategy.ElectricGuitarCreationStrategy; import com.ajou.hertz.domain.instrument.strategy.InstrumentCreationStrategy; import com.ajou.hertz.domain.user.entity.User; import com.ajou.hertz.domain.user.service.UserQueryService; @@ -52,8 +55,39 @@ public class InstrumentCommandService { private final UserQueryService userQueryService; private final InstrumentQueryService instrumentQueryService; private final InstrumentImageCommandService instrumentImageCommandService; + private final InstrumentHashtagCommandService instrumentHashtagCommandService; private final InstrumentRepository instrumentRepository; - private final InstrumentHashtagRepository instrumentHashtagRepository; + + /** + * 신규 악기 매물을 생성하여 저장한다. + * + * @param sellerId 악기 판매자의 id + * @param createNewInstrumentRequest 판매하고자 하는 악기 정보 + * @param creationStrategy Instrument type별 entity 생성 전략 (strategy pattern 사용) + * @return 생성된 악기 entity + */ + private > T createNewInstrument( + Long sellerId, + U createNewInstrumentRequest, + InstrumentCreationStrategy creationStrategy + ) { + User seller = userQueryService.getById(sellerId); + T instrument = instrumentRepository.save(creationStrategy.createInstrument(seller, createNewInstrumentRequest)); + + List savedInstrumentImages = instrumentImageCommandService.saveImages( + instrument, + createNewInstrumentRequest.getImages() + ); + instrument.getImages().addAll(savedInstrumentImages); + + List savedInstrumentHashtags = instrumentHashtagCommandService.saveHashtags( + instrument, + createNewInstrumentRequest.getHashtags() + ); + instrument.getHashtags().addAll(savedInstrumentHashtags); + + return instrument; + } /** * 신규 일렉 기타 매물을 생성 및 저장한다. @@ -135,64 +169,87 @@ public AudioEquipmentDto createNewAudioEquipment(Long sellerId, CreateNewAudioEq } /** - * 악기 매물을 삭제한다. + * 악기 매물 정보를 수정한다. * - * @param userId 악기 매물을 삭제하려는 유저의 id - * @param instrumentId 삭제할 악기 매물의 id - * @throws InstrumentDeletePermissionDeniedException 악기를 삭제하려는 유저가 판매자가 아닌 경우 + * @param userId 수정하고자 하는 유저의 id + * @param instrumentId 수정하고자 하는 악기 매물의 id + * @param updateRequest 수정하고자 하는 정보 + * @return 수정된 악기 정보 */ - public void deleteInstrumentById(Long userId, Long instrumentId) { + private InstrumentDto updateInstrument( + Long userId, + Long instrumentId, + InstrumentUpdateRequest updateRequest + ) { Instrument instrument = instrumentQueryService.getInstrumentById(instrumentId); + if (!userId.equals(instrument.getSeller().getId())) { - throw new InstrumentDeletePermissionDeniedException(); + throw new InstrumentUpdatePermissionDeniedException(userId, instrumentId); } - instrumentImageCommandService.deleteAllByInstrumentId(instrumentId); - instrumentHashtagRepository.deleteAllByInstrument(instrument); - instrumentRepository.delete(instrument); + + instrument.update(updateRequest); + + List deletedImageIds = updateRequest.getDeletedImageIds(); + if (hasElement(deletedImageIds)) { + instrumentImageCommandService.deleteAllByIds(deletedImageIds); + instrument.getImages().deleteAllByIds(deletedImageIds); + } + + if (hasElement(updateRequest.getNewImages())) { + List newImages = + instrumentImageCommandService.saveImages(instrument, updateRequest.getNewImages()); + instrument.getImages().addAll(newImages); + } + + List deletedHashtagIds = updateRequest.getDeletedHashtagIds(); + if (hasElement(deletedHashtagIds)) { + instrumentHashtagCommandService.deleteAllByIds(deletedHashtagIds); + instrument.getHashtags().deleteAllByIds(deletedHashtagIds); + } + + if (hasElement(updateRequest.getNewHashtags())) { + List newHashtags = + instrumentHashtagCommandService.saveHashtags(instrument, updateRequest.getNewHashtags()); + instrument.getHashtags().addAll(newHashtags); + } + + return InstrumentMapper.toDto(instrument); } /** - * 신규 악기 매물을 생성하여 저장한다. + * 일렉 기타 매물 정보를 수정한다. * - * @param sellerId 악기 판매자의 id - * @param createNewInstrumentRequest 판매하고자 하는 악기 정보 - * @param creationStrategy Instrument type별 entity 생성 전략 (strategy pattern 사용) - * @return 생성된 악기 entity + * @param userId 수정하고자 하는 유저의 id. 악기 판매자와 동일해야 한다. + * @param electricGuitarId 수정할 일렉 기타의 id + * @param updateRequest 수정하고자 하는 정보 + * @return 수정된 일렉 기타 매물 정보 */ - private > T createNewInstrument( - Long sellerId, - U createNewInstrumentRequest, - InstrumentCreationStrategy creationStrategy + public ElectricGuitarDto updateElectricGuitar( + Long userId, + Long electricGuitarId, + ElectricGuitarUpdateRequest updateRequest ) { - User seller = userQueryService.getById(sellerId); - T instrument = instrumentRepository.save(creationStrategy.createInstrument(seller, createNewInstrumentRequest)); - registerInstrumentImages(instrument, createNewInstrumentRequest.getImages()); - registerInstrumentHashtags(instrument, createNewInstrumentRequest.getHashtags()); - return instrument; + return (ElectricGuitarDto)updateInstrument(userId, electricGuitarId, updateRequest); } /** - * 전달된 이미지들을 업로드하고, InstrumentImage list를 만들어 저장 및 등록한다. + * 악기 매물을 삭제한다. * - * @param instrument 이미지에 대한 악기 - * @param images image list + * @param userId 악기 매물을 삭제하려는 유저의 id + * @param instrumentId 삭제할 악기 매물의 id + * @throws InstrumentDeletePermissionDeniedException 악기를 삭제하려는 유저가 판매자가 아닌 경우 */ - private void registerInstrumentImages(Instrument instrument, List images) { - List savedInstrumentImages = instrumentImageCommandService.saveImages(instrument, images); - instrument.getImages().addAll(savedInstrumentImages); + public void deleteInstrumentById(Long userId, Long instrumentId) { + Instrument instrument = instrumentQueryService.getInstrumentById(instrumentId); + if (!userId.equals(instrument.getSeller().getId())) { + throw new InstrumentDeletePermissionDeniedException(); + } + instrumentImageCommandService.deleteAllByInstrumentId(instrumentId); + instrumentHashtagCommandService.deleteAllByInstrument(instrument); + instrumentRepository.delete(instrument); } - /** - * 전달된 hashtag content list로 InstrumentHashtag list를 만들어 저장 및 등록한다. - * - * @param instrument hashtag가 작성된 악기 - * @param hashtags hashtag list - */ - private void registerInstrumentHashtags(Instrument instrument, List hashtags) { - List instrumentHashtags = hashtags.stream() - .map(hashtagContent -> InstrumentHashtag.create(instrument, hashtagContent)) - .toList(); - List savedInstrumentHashtags = instrumentHashtagRepository.saveAll(instrumentHashtags); - instrument.getHashtags().addAll(savedInstrumentHashtags); + private boolean hasElement(Collection collection) { + return collection != null && !collection.isEmpty(); } } diff --git a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentHashtagCommandService.java b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentHashtagCommandService.java new file mode 100644 index 0000000..a42509d --- /dev/null +++ b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentHashtagCommandService.java @@ -0,0 +1,53 @@ +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.entity.Instrument; +import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag; +import com.ajou.hertz.domain.instrument.repository.InstrumentHashtagRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Transactional +@Service +public class InstrumentHashtagCommandService { + + private final InstrumentHashtagRepository instrumentHashtagRepository; + + /** + * 전달된 hashtag content list로 InstrumentHashtag list를 만들어 저장 및 등록한다. + * + * @param instrument hashtag가 작성된 악기 + * @param hashtags hashtag list + * @return 생성된 hashtag list + */ + public List saveHashtags(Instrument instrument, List hashtags) { + List instrumentHashtags = hashtags.stream() + .map(hashtagContent -> InstrumentHashtag.create(instrument, hashtagContent)) + .toList(); + return instrumentHashtagRepository.saveAll(instrumentHashtags); + } + + /** + * 특정 악기에 대해 모든 해시태그를 삭제한다. + * + * @param instrument 해시태그를 삭제할 악기 + */ + public void deleteAllByInstrument(Instrument instrument) { + instrumentHashtagRepository.deleteAllByInstrument(instrument); + } + + /** + * 전달받은 id 리스트에 해당하는 해시태그를 전부 삭제한다. + * + * @param ids 삭제할 해시태그 id 리스트 + */ + public void deleteAllByIds(Collection ids) { + instrumentHashtagRepository.deleteAllByIdInBatch(ids); + } +} diff --git a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentImageCommandService.java b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentImageCommandService.java index ee4d974..21c385a 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentImageCommandService.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentImageCommandService.java @@ -1,6 +1,8 @@ package com.ajou.hertz.domain.instrument.service; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -28,7 +30,7 @@ public class InstrumentImageCommandService { * 전달받은 multipart files로 instrument image entity를 생성 후 저장한다. * * @param instrument 이미지의 대상이 되는 instrument entity - * @param images 저장하고자 하는 image + * @param images 저장하고자 하는 image * @return 저장된 instrument images */ public List saveImages(Instrument instrument, Iterable images) { @@ -47,7 +49,7 @@ public List saveImages(Instrument instrument, Iterable instrumentImages = instrumentImageQueryService.findAllByInstrumentId(instrumentId); @@ -58,4 +60,19 @@ public void deleteAllByInstrumentId(Long instrumentId) { ); instrumentImageRepository.deleteAll(instrumentImages); } + + /** + * 전달받은 id 리스트에 해당하는 악기 이미지를 전부 삭제한다. + * + * @param ids 삭제할 악기들의 id 리스트 + */ + public void deleteAllByIds(Collection ids) { + List instrumentImages = instrumentImageRepository.findAllByIdIn(ids); + instrumentImageRepository.deleteAllInBatch(instrumentImages); + fileService.deleteAll( + instrumentImages.stream() + .map(InstrumentImage::getStoredName) + .collect(Collectors.toList()) + ); + } } diff --git a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentQueryService.java b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentQueryService.java index f6afd1d..3bc8677 100644 --- a/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentQueryService.java +++ b/src/main/java/com/ajou/hertz/domain/instrument/service/InstrumentQueryService.java @@ -5,20 +5,21 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; -import com.ajou.hertz.domain.instrument.dto.InstrumentDto; import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; +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.audio_equipment.dto.AudioEquipmentDto; import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; +import com.ajou.hertz.domain.instrument.dto.InstrumentDto; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.exception.InstrumentNotFoundByIdException; import com.ajou.hertz.domain.instrument.mapper.InstrumentMapper; @@ -44,6 +45,17 @@ public Instrument getInstrumentById(Long id) { .orElseThrow(() -> new InstrumentNotFoundByIdException(id)); } + /** + * Id로 일렉 기타를 조회한다. + * + * @param id 조회하고자 하는 일렉 기타 entity의 id + * @return 조회된 일렉 기타 entity + */ + public ElectricGuitar getElectricGuitarById(Long id) { + return instrumentRepository.findElectricGuitarById(id) + .orElseThrow(() -> new InstrumentNotFoundByIdException(id)); + } + /** * Id로 악기를 조회한다. * 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 69c10ba..dfaf5ab 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 @@ -33,43 +33,44 @@ 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.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.CreateNewAcousticAndClassicGuitarRequest; 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.amplifier.dto.AmplifierDto; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +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; +import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; +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; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; -import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; -import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; -import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; -import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; import com.ajou.hertz.domain.instrument.constant.GuitarColor; import com.ajou.hertz.domain.instrument.constant.InstrumentCategory; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; import com.ajou.hertz.domain.instrument.controller.InstrumentController; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; import com.ajou.hertz.domain.instrument.dto.InstrumentDto; import com.ajou.hertz.domain.instrument.dto.InstrumentImageDto; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentFilterConditions; +import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; +import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; +import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; +import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.dto.request.InstrumentFilterConditions; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.service.InstrumentCommandService; import com.ajou.hertz.domain.instrument.service.InstrumentQueryService; import com.ajou.hertz.domain.user.constant.Gender; @@ -401,7 +402,7 @@ public InstrumentControllerTest(MockMvc mvc) { void 새로_등록할_일렉기타의_정보가_주어지면_일렉기타_매물을_등록한다() throws Exception { // given long sellerId = 1L; - CreateNewElectricGuitarRequest electricGuitarRequest = createElectricGuitarRequest(); + CreateNewElectricGuitarRequest electricGuitarRequest = createNewElectricGuitarRequest(); ElectricGuitarDto expectedResult = createElectricGuitarDto(2L, sellerId); given(instrumentCommandService.createNewElectricGuitar( eq(sellerId), any(CreateNewElectricGuitarRequest.class) @@ -663,6 +664,47 @@ public InstrumentControllerTest(MockMvc mvc) { verifyEveryMocksShouldHaveNoMoreInteractions(); } + @Test + void 수정할_일렉_기타_정보가_주어지고_주어진_정보로_매물_정보를_수정한다() throws Exception { + // given + long userId = 1L; + long electricGuitarId = 2L; + ElectricGuitarUpdateRequest updateRequest = createElectricGuitarUpdateRequest(); + ElectricGuitarDto expectedResult = createElectricGuitarDto(electricGuitarId, userId); + given(instrumentCommandService.updateElectricGuitar( + eq(userId), + eq(electricGuitarId), + any(ElectricGuitarUpdateRequest.class) + )).willReturn(expectedResult); + + // when & then + mvc.perform( + multipart("/api/instruments/electric-guitars/{electricGuitarId}", electricGuitarId) + .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("productionYear", String.valueOf(updateRequest.getProductionYear())) + .param("color", String.valueOf(updateRequest.getColor())) + .with(user(createTestUser(userId))) + .with(request -> { + request.setMethod("PATCH"); + return request; + }) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(expectedResult.getId())); + then(instrumentCommandService) + .should() + .updateElectricGuitar(eq(userId), eq(electricGuitarId), any(ElectricGuitarUpdateRequest.class)); + verifyEveryMocksShouldHaveNoMoreInteractions(); + } + @Test void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception { // given @@ -875,7 +917,7 @@ private AddressRequest createAddressRequest() throws Exception { return ReflectionUtils.createAddressRequest("서울특별시", "강남구", "청담동"); } - private CreateNewElectricGuitarRequest createElectricGuitarRequest() throws Exception { + private CreateNewElectricGuitarRequest createNewElectricGuitarRequest() throws Exception { return ReflectionUtils.createElectricGuitarRequest( "Test electric guitar", InstrumentProgressStatus.SELLING, @@ -984,4 +1026,24 @@ private InstrumentFilterConditions createInstrumentFilterConditions() throws Exc "마포구" ); } + + private ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest() throws Exception { + return ReflectionUtils.createElectricGuitarUpdateRequest( + "title", + InstrumentProgressStatus.SOLD_OUT, + createAddressRequest(), + (short)3, + 550000, + true, + "description", + null, + null, + null, + null, + ElectricGuitarBrand.FENDER_JAPAN, + ElectricGuitarModel.TELECASTER, + (short)2014, + GuitarColor.RED + ); + } } 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 4ac8c73..f7f8758 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 @@ -15,6 +15,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; @@ -25,44 +26,46 @@ 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.AcousticAndClassicGuitarDto; +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; 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.CreateNewAmplifierRequest; +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.CreateNewAudioEquipmentRequest; +import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; +import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; +import com.ajou.hertz.domain.instrument.constant.GuitarColor; +import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; +import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; +import com.ajou.hertz.domain.instrument.effector.entity.Effector; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; -import com.ajou.hertz.domain.instrument.constant.GuitarColor; -import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; -import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; -import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; -import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; -import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; -import com.ajou.hertz.domain.instrument.effector.entity.Effector; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag; import com.ajou.hertz.domain.instrument.entity.InstrumentImage; import com.ajou.hertz.domain.instrument.exception.InstrumentDeletePermissionDeniedException; -import com.ajou.hertz.domain.instrument.repository.InstrumentHashtagRepository; +import com.ajou.hertz.domain.instrument.exception.InstrumentUpdatePermissionDeniedException; import com.ajou.hertz.domain.instrument.repository.InstrumentRepository; import com.ajou.hertz.domain.instrument.service.InstrumentCommandService; +import com.ajou.hertz.domain.instrument.service.InstrumentHashtagCommandService; import com.ajou.hertz.domain.instrument.service.InstrumentImageCommandService; import com.ajou.hertz.domain.instrument.service.InstrumentQueryService; import com.ajou.hertz.domain.user.constant.Gender; @@ -88,10 +91,10 @@ class InstrumentCommandServiceTest { private InstrumentImageCommandService instrumentImageCommandService; @Mock - private InstrumentRepository instrumentRepository; + private InstrumentHashtagCommandService instrumentHashtagCommandService; @Mock - private InstrumentHashtagRepository instrumentHashtagRepository; + private InstrumentRepository instrumentRepository; @Test void 새로_등록할_일렉기타의_정보가_주어지면_일렉기타_매물을_등록한다() throws Exception { @@ -106,7 +109,7 @@ class InstrumentCommandServiceTest { given(instrumentRepository.save(any(Instrument.class))).willReturn(electricGuitar); given(instrumentImageCommandService.saveImages(eq(electricGuitar), ArgumentMatchers.>any())) .willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + given(instrumentHashtagCommandService.saveHashtags(electricGuitar, electricGuitarRequest.getHashtags())) .willReturn(instrumentHashtags); // when @@ -118,7 +121,8 @@ class InstrumentCommandServiceTest { then(instrumentImageCommandService) .should() .saveImages(eq(electricGuitar), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService).should() + .saveHashtags(electricGuitar, electricGuitarRequest.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", electricGuitar.getId()) @@ -140,7 +144,7 @@ class InstrumentCommandServiceTest { given(instrumentRepository.save(any(Instrument.class))).willReturn(bassGuitar); given(instrumentImageCommandService.saveImages(eq(bassGuitar), ArgumentMatchers.>any())) .willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + given(instrumentHashtagCommandService.saveHashtags(bassGuitar, bassGuitarRequest.getHashtags())) .willReturn(instrumentHashtags); // when @@ -151,7 +155,7 @@ class InstrumentCommandServiceTest { then(instrumentRepository).should().save(any(Instrument.class)); then(instrumentImageCommandService).should() .saveImages(eq(bassGuitar), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService).should().saveHashtags(bassGuitar, bassGuitarRequest.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", bassGuitar.getId()) @@ -174,8 +178,10 @@ class InstrumentCommandServiceTest { given(instrumentImageCommandService.saveImages( eq(acousticAndClassicGuitar), ArgumentMatchers.>any() )).willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) - .willReturn(instrumentHashtags); + given(instrumentHashtagCommandService.saveHashtags( + acousticAndClassicGuitar, + acousticAndClassicGuitarReq.getHashtags()) + ).willReturn(instrumentHashtags); // when AcousticAndClassicGuitarDto result = sut.createNewAcousticAndClassicGuitar( @@ -188,7 +194,9 @@ class InstrumentCommandServiceTest { then(instrumentImageCommandService) .should() .saveImages(eq(acousticAndClassicGuitar), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService) + .should() + .saveHashtags(acousticAndClassicGuitar, acousticAndClassicGuitarReq.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", acousticAndClassicGuitar.getId()) @@ -210,7 +218,7 @@ class InstrumentCommandServiceTest { given(instrumentRepository.save(any(Instrument.class))).willReturn(effector); given(instrumentImageCommandService.saveImages(eq(effector), ArgumentMatchers.>any())) .willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + given(instrumentHashtagCommandService.saveHashtags(effector, effectorRequest.getHashtags())) .willReturn(instrumentHashtags); // when @@ -221,7 +229,7 @@ class InstrumentCommandServiceTest { then(instrumentRepository).should().save(any(Instrument.class)); then(instrumentImageCommandService).should() .saveImages(eq(effector), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService).should().saveHashtags(effector, effectorRequest.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", effector.getId()) @@ -243,7 +251,7 @@ class InstrumentCommandServiceTest { given(instrumentRepository.save(any(Instrument.class))).willReturn(amplifier); given(instrumentImageCommandService.saveImages(eq(amplifier), ArgumentMatchers.>any())) .willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + given(instrumentHashtagCommandService.saveHashtags(amplifier, amplifierRequest.getHashtags())) .willReturn(instrumentHashtags); // when @@ -254,7 +262,7 @@ class InstrumentCommandServiceTest { then(instrumentRepository).should().save(any(Instrument.class)); then(instrumentImageCommandService).should() .saveImages(eq(amplifier), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService).should().saveHashtags(amplifier, amplifierRequest.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", amplifier.getId()) @@ -276,7 +284,7 @@ class InstrumentCommandServiceTest { given(instrumentRepository.save(any(Instrument.class))).willReturn(audioEquipment); given(instrumentImageCommandService.saveImages(eq(audioEquipment), ArgumentMatchers.>any())) .willReturn(instrumentImages); - given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + given(instrumentHashtagCommandService.saveHashtags(audioEquipment, audioEquipmentRequest.getHashtags())) .willReturn(instrumentHashtags); // when @@ -288,7 +296,9 @@ class InstrumentCommandServiceTest { then(instrumentImageCommandService) .should() .saveImages(eq(audioEquipment), ArgumentMatchers.>any()); - then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + then(instrumentHashtagCommandService) + .should() + .saveHashtags(audioEquipment, audioEquipmentRequest.getHashtags()); verifyEveryMocksShouldHaveNoMoreInteractions(); assertThat(result) .hasFieldOrPropertyWithValue("id", audioEquipment.getId()) @@ -297,6 +307,136 @@ class InstrumentCommandServiceTest { assertThat(result.getHashtags()).hasSize(instrumentHashtags.size()); } + @Test + void 삭제할_이미지들의_id_리스트가_주어지고_매물_정보를_수정하면_악기_이미지들이_삭제된다() throws Exception { + // given + long userId = 1L; + long instrumentId = 2L; + List deleteImageIds = List.of(3L, 4L); + ElectricGuitar electricGuitar = createElectricGuitar(instrumentId, createUser(userId)); + List initialImages = List.of( + createInstrumentImage(deleteImageIds.get(0), electricGuitar), + createInstrumentImage(deleteImageIds.get(1), electricGuitar) + ); + electricGuitar.getImages().addAll(initialImages); + ElectricGuitarUpdateRequest updateRequest = createElectricGuitarUpdateRequest(deleteImageIds, null, null, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(electricGuitar); + willDoNothing().given(instrumentImageCommandService).deleteAllByIds(deleteImageIds); + + // when + ElectricGuitarDto result = sut.updateElectricGuitar(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 + long userId = 1L; + long instrumentId = 2L; + ElectricGuitar electricGuitar = createElectricGuitar(instrumentId, createUser(userId)); + List newImages = List.of( + createMultipartFile(), + createMultipartFile() + ); + List newInstrumentImages = List.of( + createInstrumentImage(3L, electricGuitar), + createInstrumentImage(4L, electricGuitar) + ); + ElectricGuitarUpdateRequest updateRequest = createElectricGuitarUpdateRequest(List.of(), newImages, null, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(electricGuitar); + given(instrumentImageCommandService.saveImages(electricGuitar, updateRequest.getNewImages())) + .willReturn(newInstrumentImages); + + // when + ElectricGuitarDto result = sut.updateElectricGuitar(userId, instrumentId, updateRequest); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + then(instrumentImageCommandService).should().saveImages(electricGuitar, updateRequest.getNewImages()); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(result.getImages()).hasSize(newImages.size()); + } + + @Test + void 삭제할_해시태그들의_id_리스트가_주어지고_매물_정보를_수정하면_해시태그가_삭제된다() throws Exception { + long userId = 1L; + long instrumentId = 2L; + List deleteHashtagIds = List.of(3L, 4L); + ElectricGuitar electricGuitar = createElectricGuitar(instrumentId, createUser(userId)); + List initialHashtags = List.of( + createInstrumentHashtag(deleteHashtagIds.get(0), electricGuitar), + createInstrumentHashtag(deleteHashtagIds.get(1), electricGuitar) + ); + electricGuitar.getHashtags().addAll(initialHashtags); + ElectricGuitarUpdateRequest updateRequest = + createElectricGuitarUpdateRequest(null, null, deleteHashtagIds, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(electricGuitar); + willDoNothing().given(instrumentHashtagCommandService).deleteAllByIds(deleteHashtagIds); + + // when + ElectricGuitarDto result = sut.updateElectricGuitar(userId, instrumentId, updateRequest); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + then(instrumentHashtagCommandService).should().deleteAllByIds(deleteHashtagIds); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(result.getHashtags()).hasSize(initialHashtags.size() - deleteHashtagIds.size()); + } + + @Test + void 추가할_해시태그들이_주어지고_매물_정보를_수정하면_새로운_해시태그들이_추가된다() throws Exception { + // given + long userId = 1L; + long instrumentId = 2L; + ElectricGuitar electricGuitar = createElectricGuitar(instrumentId, createUser(userId)); + List newHashtags = List.of("tag1", "tag2"); + List newInstrumentHashtags = List.of( + createInstrumentHashtag(3L, electricGuitar), + createInstrumentHashtag(4L, electricGuitar) + ); + ElectricGuitarUpdateRequest updateRequest = createElectricGuitarUpdateRequest(null, null, null, newHashtags); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(electricGuitar); + given(instrumentHashtagCommandService.saveHashtags(electricGuitar, updateRequest.getNewHashtags())) + .willReturn(newInstrumentHashtags); + + // when + ElectricGuitarDto result = sut.updateElectricGuitar(userId, instrumentId, updateRequest); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + then(instrumentHashtagCommandService).should().saveHashtags(electricGuitar, updateRequest.getNewHashtags()); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(result.getHashtags()).hasSize(newHashtags.size()); + } + + @Test + void 판매자가_아닌_유저가_악기_매물_정보를_수정하면_예외가_발생한다() throws Exception { + // given + long userId = 1L; + long instrumentId = 2L; + ElectricGuitar electricGuitar = createElectricGuitar(instrumentId, createUser(3L)); + ElectricGuitarUpdateRequest updateRequest = createElectricGuitarUpdateRequest(null, null, null, null); + given(instrumentQueryService.getInstrumentById(instrumentId)) + .willReturn(electricGuitar); + + // when + Throwable ex = catchThrowable(() -> sut.updateElectricGuitar(userId, instrumentId, updateRequest)); + + // then + then(instrumentQueryService).should().getInstrumentById(instrumentId); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(ex).isInstanceOf(InstrumentUpdatePermissionDeniedException.class); + } + @Test void 악기_id가_주어지고_해당하는_악기_매물을_삭제한다() throws Exception { // given @@ -305,7 +445,7 @@ class InstrumentCommandServiceTest { BassGuitar bassGuitar = createBassGuitar(instrumentId, createUser(userId)); given(instrumentQueryService.getInstrumentById(instrumentId)).willReturn(bassGuitar); willDoNothing().given(instrumentImageCommandService).deleteAllByInstrumentId(instrumentId); - willDoNothing().given(instrumentHashtagRepository).deleteAllByInstrument(bassGuitar); + willDoNothing().given(instrumentHashtagCommandService).deleteAllByInstrument(bassGuitar); willDoNothing().given(instrumentRepository).delete(bassGuitar); // when @@ -314,7 +454,7 @@ class InstrumentCommandServiceTest { // then then(instrumentQueryService).should().getInstrumentById(instrumentId); then(instrumentImageCommandService).should().deleteAllByInstrumentId(instrumentId); - then(instrumentHashtagRepository).should().deleteAllByInstrument(bassGuitar); + then(instrumentHashtagCommandService).should().deleteAllByInstrument(bassGuitar); then(instrumentRepository).should().delete(bassGuitar); verifyEveryMocksShouldHaveNoMoreInteractions(); } @@ -340,7 +480,7 @@ private void verifyEveryMocksShouldHaveNoMoreInteractions() { then(userQueryService).shouldHaveNoMoreInteractions(); then(instrumentRepository).shouldHaveNoMoreInteractions(); then(instrumentImageCommandService).shouldHaveNoMoreInteractions(); - then(instrumentHashtagRepository).shouldHaveNoMoreInteractions(); + then(instrumentHashtagCommandService).shouldHaveNoMoreInteractions(); } private MockMultipartFile createMultipartFile() { @@ -596,4 +736,17 @@ private CreateNewAudioEquipmentRequest createAudioEquipmentRequest() throws Exce AudioEquipmentType.AUDIO_EQUIPMENT ); } + + private ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest( + @Nullable List deletedImageIds, + @Nullable List newImages, + @Nullable List deletedHashtagIds, + @Nullable List newHashtags + ) throws Exception { + return ReflectionUtils.createElectricGuitarUpdateRequest( + null, null, null, null, null, null, null, + deletedImageIds, newImages, deletedHashtagIds, newHashtags, + null, null, null, null + ); + } } diff --git a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentHashtagCommandServiceTest.java b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentHashtagCommandServiceTest.java new file mode 100644 index 0000000..63b24e7 --- /dev/null +++ b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentHashtagCommandServiceTest.java @@ -0,0 +1,139 @@ +package com.ajou.hertz.unit.domain.instrument.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.BDDMockito.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.ajou.hertz.common.entity.Address; +import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand; +import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp; +import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; +import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; +import com.ajou.hertz.domain.instrument.constant.GuitarColor; +import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.entity.Instrument; +import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag; +import com.ajou.hertz.domain.instrument.repository.InstrumentHashtagRepository; +import com.ajou.hertz.domain.instrument.service.InstrumentHashtagCommandService; +import com.ajou.hertz.domain.user.constant.Gender; +import com.ajou.hertz.domain.user.constant.RoleType; +import com.ajou.hertz.domain.user.entity.User; +import com.ajou.hertz.util.ReflectionUtils; + +@DisplayName("[Unit] Service(Command) - Instrument Hashtag") +@ExtendWith(MockitoExtension.class) +class InstrumentHashtagCommandServiceTest { + + @InjectMocks + private InstrumentHashtagCommandService sut; + + @Mock + private InstrumentHashtagRepository instrumentHashtagRepository; + + @Test + void 주어진_해시태그_내용들로_해시태그_entity를_생성_및_저장한다() throws Exception { + // given + BassGuitar bassGuitar = createBassGuitar(1L, createUser(2L)); + List hashtagsContentList = List.of("test1", "test2"); + List expectedResult = List.of( + createInstrumentHashtag(3L, bassGuitar, hashtagsContentList.get(0)), + createInstrumentHashtag(4L, bassGuitar, hashtagsContentList.get(1)) + ); + given(instrumentHashtagRepository.saveAll(ArgumentMatchers.>any())) + .willReturn(expectedResult); + + // when + List actualResult = sut.saveHashtags(bassGuitar, hashtagsContentList); + + // then + then(instrumentHashtagRepository).should().saveAll(ArgumentMatchers.>any()); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(actualResult).hasSize(expectedResult.size()); + assertThat(actualResult.get(0).getId()).isEqualTo(expectedResult.get(0).getId()); + assertThat(actualResult.get(1).getId()).isEqualTo(expectedResult.get(1).getId()); + } + + @Test + void 악기_entity가_주어지고_주어진_악기의_모든_해시태그를_삭제한다() throws Exception { + // given + BassGuitar bassGuitar = createBassGuitar(1L, createUser(2L)); + willDoNothing().given(instrumentHashtagRepository).deleteAllByInstrument(bassGuitar); + + // when + sut.deleteAllByInstrument(bassGuitar); + + // then + then(instrumentHashtagRepository).should().deleteAllByInstrument(bassGuitar); + verifyEveryMocksShouldHaveNoMoreInteractions(); + } + + @Test + void 해시태그_id_리스트가_주어지고_주어진_id에_해당하는_모든_해시태그를_삭제한다() throws Exception { + // given + List deleteHashtagIds = List.of(1L, 2L); + willDoNothing().given(instrumentHashtagRepository).deleteAllByIdInBatch(deleteHashtagIds); + + // when + sut.deleteAllByIds(deleteHashtagIds); + + // then + then(instrumentHashtagRepository).should().deleteAllByIdInBatch(deleteHashtagIds); + verifyEveryMocksShouldHaveNoMoreInteractions(); + } + + private void verifyEveryMocksShouldHaveNoMoreInteractions() { + then(instrumentHashtagRepository).shouldHaveNoMoreInteractions(); + } + + private Address createAddress() { + return new Address("서울특별시", "강남구", "청담동"); + } + + private User createUser(long id) throws Exception { + return ReflectionUtils.createUser( + id, + Set.of(RoleType.USER), + "test@mail.com", + "password", + "12345", + "https://user-default-profile-image-url", + LocalDate.of(2024, 1, 1), + Gender.ETC, + "01012345678", + null + ); + } + + private BassGuitar createBassGuitar(long id, User seller) throws Exception { + return ReflectionUtils.createBassGuitar( + id, + seller, + "Test electric guitar", + InstrumentProgressStatus.SELLING, + createAddress(), + (short)3, + 550000, + true, + "description", + BassGuitarBrand.FENDER, + BassGuitarPickUp.JAZZ, + BassGuitarPreAmplifier.ACTIVE, + GuitarColor.RED + ); + } + + private InstrumentHashtag createInstrumentHashtag(Long id, Instrument instrument, String content) throws Exception { + return ReflectionUtils.createInstrumentHashtag(id, instrument, content); + } +} \ No newline at end of file diff --git a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentImageCommandServiceTest.java b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentImageCommandServiceTest.java index 90f7d6c..73deda1 100644 --- a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentImageCommandServiceTest.java +++ b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentImageCommandServiceTest.java @@ -4,6 +4,7 @@ import static org.mockito.BDDMockito.*; import java.time.LocalDate; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -24,9 +25,9 @@ import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; +import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; import com.ajou.hertz.domain.instrument.constant.GuitarColor; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; -import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.entity.InstrumentImage; import com.ajou.hertz.domain.instrument.repository.InstrumentImageRepository; @@ -110,6 +111,33 @@ class InstrumentImageCommandServiceTest { verifyEveryMocksShouldHaveNoMoreInteractions(); } + @Test + void 삭제할_악기_이미지들의_id_리스트가_주어지고_주어진_id_리스트에_포함된_이미지를_전부_삭제한다() throws Exception { + // given + List deleteImageIds = List.of(1L, 2L, 3L); + BassGuitar bassGuitar = createBassGuitar(4L, createUser(5L)); + List deleteImages = List.of( + createInstrumentImage(deleteImageIds.get(0), bassGuitar), + createInstrumentImage(deleteImageIds.get(1), bassGuitar), + createInstrumentImage(deleteImageIds.get(2), bassGuitar) + ); + Collection deleteImageStoredNames = deleteImages.stream() + .map(InstrumentImage::getStoredName) + .toList(); + given(instrumentImageRepository.findAllByIdIn(deleteImageIds)) + .willReturn(deleteImages); + willDoNothing().given(instrumentImageRepository).deleteAllInBatch(deleteImages); + willDoNothing().given(fileService).deleteAll(deleteImageStoredNames); + + // when + sut.deleteAllByIds(deleteImageIds); + + // then + then(instrumentImageRepository).should().findAllByIdIn(deleteImageIds); + then(instrumentImageRepository).should().deleteAllInBatch(deleteImages); + then(fileService).should().deleteAll(deleteImageStoredNames); + } + private void verifyEveryMocksShouldHaveNoMoreInteractions() { then(instrumentImageQueryService).shouldHaveNoMoreInteractions(); then(fileService).shouldHaveNoMoreInteractions(); diff --git a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentQueryServiceTest.java b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentQueryServiceTest.java index 1b93884..047b669 100644 --- a/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentQueryServiceTest.java +++ b/src/test/java/com/ajou/hertz/unit/domain/instrument/service/InstrumentQueryServiceTest.java @@ -24,39 +24,39 @@ 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.AcousticAndClassicGuitarDto; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; 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.amplifier.dto.AmplifierDto; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +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.AudioEquipmentFilterConditions; +import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; -import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; -import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; -import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; -import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; import com.ajou.hertz.domain.instrument.constant.GuitarColor; import com.ajou.hertz.domain.instrument.constant.InstrumentCategory; import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; import com.ajou.hertz.domain.instrument.constant.InstrumentSortOption; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; import com.ajou.hertz.domain.instrument.dto.InstrumentDto; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; +import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; -import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; -import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; -import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; -import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; import com.ajou.hertz.domain.instrument.effector.entity.Effector; +import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; +import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.exception.InstrumentNotFoundByIdException; @@ -110,6 +110,41 @@ class InstrumentQueryServiceTest { assertThat(t).isInstanceOf(InstrumentNotFoundByIdException.class); } + @Test + void id가_주어지고_id에_해당하는_일렉_기타를_단건_조회한다() throws Exception { + // given + long electricGuitarId = 1L; + ElectricGuitar expectedResult = createElectricGuitar(electricGuitarId, createUser(2L)); + given(instrumentRepository.findElectricGuitarById(electricGuitarId)) + .willReturn(Optional.of(expectedResult)); + + // when + ElectricGuitar actualResult = sut.getElectricGuitarById(electricGuitarId); + + // then + then(instrumentRepository).should().findElectricGuitarById(electricGuitarId); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(actualResult.getId()).isEqualTo(expectedResult.getId()); + assertThat(actualResult.getProductionYear()).isEqualTo(expectedResult.getProductionYear()); + } + + @Test + void 존재하지_않는_악기_id가_주어지고_id에_해당하는_일렉_기타를_단건_조회하면_예외가_발생한다() throws Exception { + // given + long electricGuitarId = 1L; + ElectricGuitar expectedResult = createElectricGuitar(electricGuitarId, createUser(2L)); + given(instrumentRepository.findElectricGuitarById(electricGuitarId)) + .willReturn(Optional.empty()); + + // when + Throwable ex = catchThrowable(() -> sut.getElectricGuitarById(electricGuitarId)); + + // then + then(instrumentRepository).should().findElectricGuitarById(electricGuitarId); + verifyEveryMocksShouldHaveNoMoreInteractions(); + assertThat(ex).isInstanceOf(InstrumentNotFoundByIdException.class); + } + @Test void 종류_상관_없이_전체_악기_목록을_조회한다() throws Exception { // given diff --git a/src/test/java/com/ajou/hertz/util/ReflectionUtils.java b/src/test/java/com/ajou/hertz/util/ReflectionUtils.java index 2249fae..23fad3b 100644 --- a/src/test/java/com/ajou/hertz/util/ReflectionUtils.java +++ b/src/test/java/com/ajou/hertz/util/ReflectionUtils.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.web.multipart.MultipartFile; import com.ajou.hertz.common.auth.dto.request.KakaoLoginRequest; @@ -22,44 +23,45 @@ 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.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.CreateNewAcousticAndClassicGuitarRequest; +import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; 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.amplifier.dto.AmplifierDto; +import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; +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; +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.CreateNewAudioEquipmentRequest; +import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarBrand; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPickUp; import com.ajou.hertz.domain.instrument.bass_guitar.constant.BassGuitarPreAmplifier; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; +import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; +import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; +import com.ajou.hertz.domain.instrument.constant.GuitarColor; +import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; +import com.ajou.hertz.domain.instrument.dto.InstrumentImageDto; +import com.ajou.hertz.domain.instrument.dto.request.InstrumentFilterConditions; import com.ajou.hertz.domain.instrument.effector.constant.EffectorFeature; import com.ajou.hertz.domain.instrument.effector.constant.EffectorType; +import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; +import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; +import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; +import com.ajou.hertz.domain.instrument.effector.entity.Effector; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarBrand; import com.ajou.hertz.domain.instrument.electric_guitar.constant.ElectricGuitarModel; -import com.ajou.hertz.domain.instrument.constant.GuitarColor; -import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.AcousticAndClassicGuitarDto; -import com.ajou.hertz.domain.instrument.amplifier.dto.AmplifierDto; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.AudioEquipmentDto; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.BassGuitarDto; -import com.ajou.hertz.domain.instrument.effector.dto.EffectorDto; import com.ajou.hertz.domain.instrument.electric_guitar.dto.ElectricGuitarDto; -import com.ajou.hertz.domain.instrument.dto.InstrumentImageDto; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.AcousticAndClassicGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.AmplifierFilterConditions; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.AudioEquipmentFilterConditions; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.BassGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.dto.request.CreateNewAcousticAndClassicGuitarRequest; -import com.ajou.hertz.domain.instrument.amplifier.dto.request.CreateNewAmplifierRequest; -import com.ajou.hertz.domain.instrument.audio_equipment.dto.request.CreateNewAudioEquipmentRequest; -import com.ajou.hertz.domain.instrument.bass_guitar.dto.request.CreateNewBassGuitarRequest; -import com.ajou.hertz.domain.instrument.effector.dto.request.CreateNewEffectorRequest; import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.CreateNewElectricGuitarRequest; -import com.ajou.hertz.domain.instrument.effector.dto.request.EffectorFilterConditions; import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarFilterConditions; -import com.ajou.hertz.domain.instrument.dto.request.InstrumentFilterConditions; -import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar; -import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier; -import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment; -import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar; -import com.ajou.hertz.domain.instrument.effector.entity.Effector; +import com.ajou.hertz.domain.instrument.electric_guitar.dto.request.ElectricGuitarUpdateRequest; import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar; import com.ajou.hertz.domain.instrument.entity.Instrument; import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag; @@ -836,6 +838,48 @@ public static AudioEquipmentFilterConditions createAudioEquipmentFilterCondition return constructor.newInstance(progressStatus, sido, sgg, type); } + public static ElectricGuitarUpdateRequest createElectricGuitarUpdateRequest( + @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 ElectricGuitarBrand brand, + @Nullable ElectricGuitarModel model, + @Nullable Short productionYear, + @Nullable GuitarColor color + ) throws Exception { + Constructor constructor = ElectricGuitarUpdateRequest.class.getDeclaredConstructor( + String.class, InstrumentProgressStatus.class, AddressRequest.class, Short.class, + Integer.class, Boolean.class, String.class, List.class, List.class, List.class, List.class, + ElectricGuitarBrand.class, ElectricGuitarModel.class, Short.class, GuitarColor.class + ); + constructor.setAccessible(true); + return constructor.newInstance( + title, + progressStatus, + tradeAddress, + qualityStatus, + price, + hasAnomaly, + description, + deletedImageIds, + newImages, + deletedHashtagIds, + newHashtags, + brand, + model, + productionYear, + color + ); + } + /** * DTO(Response) */