Skip to content

Commit

Permalink
feat: #83 악기 매물 삭제 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Wo-ogie committed Mar 15, 2024
1 parent f33823f commit 65bb905
Show file tree
Hide file tree
Showing 14 changed files with 609 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public enum CustomExceptionType {
/**
* 악기 관련 예외
*/
INSTRUMENT_NOT_FOUND_BY_ID(2600, "일치하는 매물 정보를 찾을 수 없습니다.")
;
INSTRUMENT_NOT_FOUND_BY_ID(2600, "일치하는 매물 정보를 찾을 수 없습니다."),
INSTRUMENT_DELETE_PERMISSION_DENIED(2601, "악기 매물을 삭제할 권한이 없습니다. 매물은 판매자 본인만 삭제할 수 있습니다.");

private final Integer code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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.PathVariable;
Expand Down Expand Up @@ -52,6 +53,9 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -411,4 +415,22 @@ public ResponseEntity<AudioEquipmentResponse> createNewAudioEquipmentV1(
.created(URI.create("/instruments/" + audioEquipment.getId()))
.body(InstrumentMapper.toAudioEquipmentResponse(audioEquipment));
}

@Operation(
summary = "악기 매물 삭제",
description = "악기 매물을 삭제합니다. 매물 삭제는 판매자만 할 수 있습니다.",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "204"),
@ApiResponse(responseCode = "403", description = "[2601] 악기를 삭제하려는 유저가 판매자가 아닌 경우", content = @Content)
})
@DeleteMapping(value = "/{instrumentId}", headers = API_VERSION_HEADER_NAME + "=" + 1)
public ResponseEntity<Void> deleteInstrumentV1(
@AuthenticationPrincipal UserPrincipal userPrincipal,
@Parameter(description = "Id of instrument", example = "2") @PathVariable Long instrumentId
) {
instrumentCommandService.deleteInstrumentById(userPrincipal.getUserId(), instrumentId);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.ajou.hertz.domain.instrument.exception;

import com.ajou.hertz.common.exception.ForbiddenException;
import com.ajou.hertz.common.exception.constant.CustomExceptionType;

public class InstrumentDeletePermissionDeniedException extends ForbiddenException {

public InstrumentDeletePermissionDeniedException() {
super(CustomExceptionType.INSTRUMENT_DELETE_PERMISSION_DENIED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import org.springframework.data.jpa.repository.JpaRepository;

import com.ajou.hertz.domain.instrument.entity.Instrument;
import com.ajou.hertz.domain.instrument.entity.InstrumentHashtag;

public interface InstrumentHashtagRepository extends JpaRepository<InstrumentHashtag, Long> {

void deleteAllByInstrument(Instrument instrument);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.ajou.hertz.domain.instrument.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.ajou.hertz.domain.instrument.entity.InstrumentImage;

public interface InstrumentImageRepository extends JpaRepository<InstrumentImage, Long> {

List<InstrumentImage> findAllByInstrument_Id(Long instrumentId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.ajou.hertz.common.file.service.FileService;
import com.ajou.hertz.domain.instrument.dto.AcousticAndClassicGuitarDto;
import com.ajou.hertz.domain.instrument.dto.AmplifierDto;
import com.ajou.hertz.domain.instrument.dto.AudioEquipmentDto;
Expand All @@ -29,9 +28,9 @@
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.mapper.InstrumentMapper;
import com.ajou.hertz.domain.instrument.repository.InstrumentHashtagRepository;
import com.ajou.hertz.domain.instrument.repository.InstrumentImageRepository;
import com.ajou.hertz.domain.instrument.repository.InstrumentRepository;
import com.ajou.hertz.domain.instrument.strategy.AcousticAndClassicGuitarCreationStrategy;
import com.ajou.hertz.domain.instrument.strategy.AmplifierCreationStrategy;
Expand All @@ -50,13 +49,11 @@
@Service
public class InstrumentCommandService {

private static final String INSTRUMENT_IMAGE_UPLOAD_PATH = "instrument-image/";

private final UserQueryService userQueryService;
private final FileService fileService;
private final InstrumentQueryService instrumentQueryService;
private final InstrumentImageCommandService instrumentImageCommandService;
private final InstrumentRepository instrumentRepository;
private final InstrumentHashtagRepository instrumentHashtagRepository;
private final InstrumentImageRepository instrumentImageRepository;

/**
* 신규 일렉 기타 매물을 생성 및 저장한다.
Expand Down Expand Up @@ -137,6 +134,23 @@ public AudioEquipmentDto createNewAudioEquipment(Long sellerId, CreateNewAudioEq
return InstrumentMapper.toAmplifierDto(audioEquipment);
}

/**
* 악기 매물을 삭제한다.
*
* @param userId 악기 매물을 삭제하려는 유저의 id
* @param instrumentId 삭제할 악기 매물의 id
* @throws InstrumentDeletePermissionDeniedException 악기를 삭제하려는 유저가 판매자가 아닌 경우
*/
public void deleteInstrumentById(Long userId, Long instrumentId) {
Instrument instrument = instrumentQueryService.getInstrumentById(instrumentId);
if (!userId.equals(instrument.getSeller().getId())) {
throw new InstrumentDeletePermissionDeniedException();
}
instrumentImageCommandService.deleteAllByInstrumentId(instrumentId);
instrumentHashtagRepository.deleteAllByInstrument(instrument);
instrumentRepository.delete(instrument);
}

/**
* 신규 악기 매물을 생성하여 저장한다.
*
Expand Down Expand Up @@ -164,16 +178,7 @@ private <T extends Instrument, U extends CreateNewInstrumentRequest<T>> T create
* @param images image list
*/
private void registerInstrumentImages(Instrument instrument, List<MultipartFile> images) {
List<InstrumentImage> instrumentImages = fileService
.uploadFiles(images, INSTRUMENT_IMAGE_UPLOAD_PATH)
.stream()
.map(fileDto -> InstrumentImage.create(
instrument,
fileDto.getOriginalName(),
fileDto.getStoredName(),
fileDto.getUrl()
)).toList();
List<InstrumentImage> savedInstrumentImages = instrumentImageRepository.saveAll(instrumentImages);
List<InstrumentImage> savedInstrumentImages = instrumentImageCommandService.saveImages(instrument, images);
instrument.getImages().addAll(savedInstrumentImages);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.ajou.hertz.domain.instrument.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.ajou.hertz.common.file.service.FileService;
import com.ajou.hertz.domain.instrument.entity.Instrument;
import com.ajou.hertz.domain.instrument.entity.InstrumentImage;
import com.ajou.hertz.domain.instrument.repository.InstrumentImageRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional
@Service
public class InstrumentImageCommandService {

private static final String INSTRUMENT_IMAGE_UPLOAD_PATH = "instrument-image/";

private final InstrumentImageQueryService instrumentImageQueryService;
private final FileService fileService;
private final InstrumentImageRepository instrumentImageRepository;

/**
* 전달받은 multipart files로 instrument image entity를 생성 후 저장한다.
*
* @param instrument 이미지의 대상이 되는 instrument entity
* @param images 저장하고자 하는 image
* @return 저장된 instrument images
*/
public List<InstrumentImage> saveImages(Instrument instrument, Iterable<MultipartFile> images) {
List<InstrumentImage> instrumentImages = fileService
.uploadFiles(images, INSTRUMENT_IMAGE_UPLOAD_PATH)
.stream()
.map(fileDto -> InstrumentImage.create(
instrument,
fileDto.getOriginalName(),
fileDto.getStoredName(),
fileDto.getUrl()
)).toList();
return instrumentImageRepository.saveAll(instrumentImages);
}

/**
* 특정 악기 매물의 모든 이미지를 삭제한다.
*
* @param instrumentId 이미지를 전체 삭제할 악기 매물의 id
*/
public void deleteAllByInstrumentId(Long instrumentId) {
List<InstrumentImage> instrumentImages = instrumentImageQueryService.findAllByInstrumentId(instrumentId);
fileService.deleteAll(
instrumentImages.stream()
.map(InstrumentImage::getStoredName)
.toList()
);
instrumentImageRepository.deleteAll(instrumentImages);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.ajou.hertz.domain.instrument.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ajou.hertz.domain.instrument.entity.InstrumentImage;
import com.ajou.hertz.domain.instrument.repository.InstrumentImageRepository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class InstrumentImageQueryService {

private final InstrumentImageRepository instrumentImageRepository;

/**
* 악기 id를 전달받고, 해당하는 악기의 이미지를 전부 조회한다.
*
* @param instrumentId 이미지를 조회하고자 하는 악기의 id
* @return 조회된 Instrument image entity list
*/
public List<InstrumentImage> findAllByInstrumentId(Long instrumentId) {
return instrumentImageRepository.findAllByInstrument_Id(instrumentId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,50 @@ public class InstrumentQueryService {

private final InstrumentRepository instrumentRepository;

/**
* Id로 악기를 조회한다.
*
* @param id 조회하고자 하는 Instrument entity의 id
* @return 조회된 Instrument entity
*/
public Instrument getInstrumentById(Long id) {
return instrumentRepository.findById(id)
.orElseThrow(() -> new InstrumentNotFoundByIdException(id));
}

/**
* Id로 악기를 조회한다.
*
* @param id 조회하고자 하는 악기의 id
* @return 조회된 Instrument dto
*/
public InstrumentDto getInstrumentDtoById(Long id) {
Instrument instrument = getInstrumentById(id);
return InstrumentMapper.toDto(instrument);
}

/**
* 악기 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 악기 dto 목록
*/
public Page<InstrumentDto> findInstrumentDtos(int page, int pageSize, InstrumentSortOption sort) {
return instrumentRepository
.findAll(PageRequest.of(page, pageSize, sort.toSort()))
.map(InstrumentMapper::toDto);
}

/**
* 일렉 기타 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 일렉 기타 dto 목록
*/
public Page<ElectricGuitarDto> findElectricGuitarDtos(
int page,
int pageSize,
Expand All @@ -55,6 +88,14 @@ public Page<ElectricGuitarDto> findElectricGuitarDtos(
.map(InstrumentMapper::toElectricGuitarDto);
}

/**
* 베이스 기타 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 베이스 기타 dto 목록
*/
public Page<BassGuitarDto> findBassGuitarDtos(
int page,
int pageSize,
Expand All @@ -66,6 +107,14 @@ public Page<BassGuitarDto> findBassGuitarDtos(
.map(InstrumentMapper::toBassGuitarDto);
}

/**
* 어쿠스틱&클래식 기타 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 어쿠스틱&클래식 기타 dto 목록
*/
public Page<AcousticAndClassicGuitarDto> findAcousticAndClassicGuitarDtos(
int page,
int pageSize,
Expand All @@ -77,6 +126,14 @@ public Page<AcousticAndClassicGuitarDto> findAcousticAndClassicGuitarDtos(
.map(InstrumentMapper::toAcousticAndClassicGuitarDto);
}

/**
* 이펙터 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 이펙터 dto 목록
*/
public Page<EffectorDto> findEffectorDtos(
int page,
int pageSize,
Expand All @@ -88,6 +145,14 @@ public Page<EffectorDto> findEffectorDtos(
.map(InstrumentMapper::toEffectorDto);
}

/**
* 앰프 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 앰프 dto 목록
*/
public Page<AmplifierDto> findAmplifierDtos(
int page,
int pageSize,
Expand All @@ -99,6 +164,14 @@ public Page<AmplifierDto> findAmplifierDtos(
.map(InstrumentMapper::toAmplifierDto);
}

/**
* 음향 장비 목록을 조회한다.
*
* @param page 페이지 번호
* @param pageSize 페이지 크기
* @param sort 정렬 기준
* @return 조회된 음향 장비 dto 목록
*/
public Page<AudioEquipmentDto> findAudioEquipmentDtos(
int page,
int pageSize,
Expand All @@ -109,9 +182,4 @@ public Page<AudioEquipmentDto> findAudioEquipmentDtos(
.findAudioEquipments(page, pageSize, sort, filterConditions)
.map(InstrumentMapper::toAmplifierDto);
}

private Instrument getInstrumentById(Long id) {
return instrumentRepository.findById(id)
.orElseThrow(() -> new InstrumentNotFoundByIdException(id));
}
}
Loading

0 comments on commit 65bb905

Please sign in to comment.