Skip to content

Commit

Permalink
[Weekly/11] Feature/image/delete (#117)
Browse files Browse the repository at this point in the history
* feat: 해시태그 네이밍 통일

* feat: 이벤트 응답 수정

* feat: validate member

* feat: import 추가
  • Loading branch information
Daolove0323 authored Nov 12, 2024
1 parent eb23d50 commit 98af56f
Show file tree
Hide file tree
Showing 25 changed files with 155 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import org.ktc2.cokaen.wouldyouin.Image.application.ImageStorageService;
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponse;
import org.ktc2.cokaen.wouldyouin._common.api.ApiResponseBody;
import org.ktc2.cokaen.wouldyouin.auth.Authorize;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -33,21 +36,21 @@ public ResponseEntity<byte[]> getImage(@PathVariable String directory, @PathVari
return ResponseEntity.status(HttpStatus.OK).body(imageStorageService.readFromDirectory(Paths.get(directory, file)));
}

// Todo: authorize
@PostMapping
public ResponseEntity<ApiResponseBody<List<ImageResponse>>> uploadImages(
@RequestParam List<MultipartFile> images,
@RequestParam(value = "type") ImageDomain imageDomain) {
@RequestParam(value = "type") ImageDomain imageDomain,
@Authorize({MemberType.normal, MemberType.curator, MemberType.host}) MemberIdentifier identifier) {
return ApiResponse.ok(imageServiceFactory.getImageService(imageDomain).saveImages(images));
}

// Todo: authorize
// Todo: 삭제로직 수정필요
@DeleteMapping("/{id}")
@DeleteMapping("/{imageId}")
public ResponseEntity<ApiResponseBody<Void>> deleteImage(
@PathVariable Long id,
@RequestParam(value = "type") ImageDomain imageDomain) {
imageServiceFactory.getImageService(imageDomain).deleteImage(id);
@PathVariable Long imageId,
@RequestParam(value = "type") ImageDomain imageDomain,
@Authorize({MemberType.normal, MemberType.curator, MemberType.host}) MemberIdentifier identifier) {
imageServiceFactory.getImageService(imageDomain).deleteImage(identifier, imageId);
return ApiResponse.noContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public class ImageResponse {
private String extension;
private LocalDateTime createdDate;

public static ImageResponse from(Image image, String path) {
public static ImageResponse from(Image image, String url) {
return ImageResponse.builder()
.id(image.getId())
.url(UriUtil.assembleFullUrl(path, image.getName()))
.url(url)
.size(image.getSize())
.extension(image.getExtension())
.createdDate(image.getCreatedDate())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.AdvertisementImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.AdvertisementImageRepository;
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin.advertisement.persist.Advertisement;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -39,12 +42,20 @@ protected String getChildPath() {
@Override
protected AdvertisementImage toEntity(ImageRequest imageRequest) {
return AdvertisementImage.builder()
.url(imageRequest.getUrl())
.name(imageRequest.getUrl())
.size(imageRequest.getSize())
.extension(imageRequest.getExtension())
.build();
}

// TODO : ad image 삭제 인가
@Override
protected void validateMemberId(MemberIdentifier identifier, AdvertisementImage image) {
if (!identifier.type().equals(MemberType.admin)) {
throw new UnauthorizedException("광고 이미지에 접근할 권한이 없습니다.");
}
}

@Transactional
public AdvertisementImage saveImage(MultipartFile image) {
return adImageRepository.save(toEntity(imageStorageService.saveToDirectory(image, getChildPath())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.CurationImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.CurationImageRepository;
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.curation.persist.CurationCard;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -37,12 +40,20 @@ protected String getChildPath() {
@Override
protected CurationImage toEntity(ImageRequest imageRequest) {
return CurationImage.builder()
.url(imageRequest.getUrl())
.name(imageRequest.getUrl())
.size(imageRequest.getSize())
.extension(imageRequest.getExtension())
.build();
}

@Override
protected void validateMemberId(MemberIdentifier identifier, CurationImage image) {
if (!identifier.type().equals(MemberType.admin) &&
!identifier.id().equals(image.getCurationCard().getCuration().getCurator().getId())) {
throw new UnauthorizedException("해당 큐레이션 이미지에 접근할 권한이 없습니다.");
}
}

@Transactional
public void setCuration(CurationImage image, CurationCard curationCard) {
image.setCurationCard(curationCard);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.EventImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.EventImageRepository;
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.event.persist.Event;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -37,12 +40,19 @@ protected String getChildPath() {
@Override
protected EventImage toEntity(ImageRequest imageRequest) {
return EventImage.builder()
.url(imageRequest.getUrl())
.name(imageRequest.getUrl())
.size(imageRequest.getSize())
.extension(imageRequest.getExtension())
.build();
}

@Override
protected void validateMemberId(MemberIdentifier identifier, EventImage image) {
if (!identifier.type().equals(MemberType.admin) && !identifier.id().equals(image.getEvent().getHost().getId())) {
throw new UnauthorizedException("해당 이벤트 이미지에 접근할 권한이 없습니다.");
}
}

@Transactional
public void setEvent(EventImage image, Event event) {
image.setEvent(event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.EntityNotFoundException;
import org.ktc2.cokaen.wouldyouin._common.util.UriUtil;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
Expand All @@ -23,7 +24,7 @@ public abstract class ImageService<T extends Image> {
protected ImageStorageService imageStorageService;

@Value("${image.api-url}")
private String apiUrl;
private String parentPath;

protected abstract ImageRepository<T> getImageRepository();

Expand All @@ -33,17 +34,21 @@ public abstract class ImageService<T extends Image> {

protected abstract T toEntity(ImageRequest imageRequest);

protected abstract void validateMemberId(MemberIdentifier identifier, T image);

@Transactional
public List<ImageResponse> saveImages(List<MultipartFile> images) {
return images.stream()
.map(image -> create(imageStorageService.saveToDirectory(image, getChildPath())))
.toList();
}

// TODO: delete 이미지 바꿔야함
@Transactional
public void deleteImage(Long id) {
T image = getById(id);
delete(id);
public void deleteImage(MemberIdentifier identifier, Long imageId) {
T image = getById(imageId);
validateMemberId(identifier, image);
delete(imageId);
imageStorageService.delete(getChildPath(), image.getName());
}

Expand All @@ -58,7 +63,7 @@ protected ImageResponse create(ImageRequest imageRequest) {
}

public String getImageUrl(T image) {
return UriUtil.assembleFullUrl(apiUrl, getChildPath(), image.getName());
return UriUtil.assembleFullUrl(parentPath, getChildPath(), image.getName());
}

protected void delete(Long id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import org.ktc2.cokaen.wouldyouin.Image.persist.ImageRepository;
import org.ktc2.cokaen.wouldyouin.Image.persist.MemberImage;
import org.ktc2.cokaen.wouldyouin.Image.persist.MemberImageRepository;
import org.ktc2.cokaen.wouldyouin._common.exception.UnauthorizedException;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.ktc2.cokaen.wouldyouin.member.persist.BaseMember;
import org.ktc2.cokaen.wouldyouin.member.persist.MemberType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -37,12 +40,19 @@ protected String getChildPath() {
@Override
protected MemberImage toEntity(ImageRequest imageRequest) {
return MemberImage.builder()
.url(imageRequest.getUrl())
.name(imageRequest.getUrl())
.size(imageRequest.getSize())
.extension(imageRequest.getExtension())
.build();
}

@Override
protected void validateMemberId(MemberIdentifier identifier, MemberImage image) {
if (!identifier.type().equals(MemberType.admin) && !identifier.id().equals(image.getBaseMember().getId())) {
throw new UnauthorizedException("해당 프로필 이미지에 접근할 권한이 없습니다.");
}
}

@Transactional
public void setBaseMember(MemberImage image, BaseMember member) {
image.setBaseMember(member);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.ktc2.cokaen.wouldyouin.advertisement.persist.Advertisement;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class AdvertisementImage extends Image {
Expand All @@ -19,8 +21,8 @@ public class AdvertisementImage extends Image {
private Advertisement advertisement;

@Builder
public AdvertisementImage(String url, Long size, String extension, Advertisement advertisement) {
super(url, size, extension);
public AdvertisementImage(String name, Long size, String extension, Advertisement advertisement) {
super(name, size, extension);
this.advertisement = advertisement;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.ktc2.cokaen.wouldyouin.curation.persist.CurationCard;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class CurationImage extends Image {
Expand All @@ -19,7 +21,7 @@ public class CurationImage extends Image {
private CurationCard curationCard;

@Builder
public CurationImage(String url, Long size, String extension) {
super(url, size, extension);
public CurationImage(String name, Long size, String extension) {
super(name, size, extension);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.ktc2.cokaen.wouldyouin.event.persist.Event;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class EventImage extends Image {
Expand All @@ -19,7 +21,7 @@ public class EventImage extends Image {
private Event event;

@Builder
public EventImage(String url, Long size, String extension) {
super(url, size, extension);
public EventImage(String name, Long size, String extension) {
super(name, size, extension);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.ktc2.cokaen.wouldyouin.member.persist.BaseMember;

@Entity
@Setter
@Getter
@NoArgsConstructor
public class MemberImage extends Image {

Expand All @@ -19,7 +21,7 @@ public class MemberImage extends Image {
private BaseMember baseMember;

@Builder
public MemberImage(String url, Long size, String extension) {
super(url, size, extension);
public MemberImage(String name, Long size, String extension) {
super(name, size, extension);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ public ResponseEntity<ApiResponseBody<AdvertisementResponse>> updateAdvertisemen
@PathVariable Long adId,
@Valid @RequestPart AdvertisementRequest advertisementRequest,
@RequestPart(required = false) MultipartFile image,
@Authorize(MemberType.admin) MemberIdentifier admin) {
return ApiResponse.ok(advertisementService.update(adId, advertisementRequest, image));
@Authorize(MemberType.admin) MemberIdentifier identifier) {
return ApiResponse.ok(advertisementService.update(identifier, adId, advertisementRequest, image));
}

@DeleteMapping("/{adId}")
public ResponseEntity<ApiResponseBody<Void>> deleteAdvertisement(
@PathVariable Long adId,
@Authorize(MemberType.admin) MemberIdentifier admin) {
advertisementService.delete(adId);
@Authorize(MemberType.admin) MemberIdentifier identifier) {
advertisementService.delete(identifier, adId);
return ApiResponse.noContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.ktc2.cokaen.wouldyouin.advertisement.api.dto.AdvertisementResponse;
import org.ktc2.cokaen.wouldyouin.advertisement.persist.Advertisement;
import org.ktc2.cokaen.wouldyouin.advertisement.persist.AdvertisementRepository;
import org.ktc2.cokaen.wouldyouin.auth.MemberIdentifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
Expand Down Expand Up @@ -51,11 +52,11 @@ public AdvertisementResponse create(AdvertisementRequest adRequest, MultipartFil
// Todo: 수정될 때 이미지가 null인 경우 기존 이미지로 대체하는 로직 프론트와 협의
// Todo: 롤백될 경우, 저장한 이미지 삭제
@Transactional
public AdvertisementResponse update(Long adId, AdvertisementRequest adRequest, MultipartFile multipartFile) {
public AdvertisementResponse update(MemberIdentifier identifier, Long adId, AdvertisementRequest adRequest, MultipartFile multipartFile) {
Advertisement ad = getByIdOrThrow(adId);
Optional.ofNullable(multipartFile).ifPresentOrElse(
image -> {
adImageService.deleteImage(ad.getAdvertisementImage().getId());
adImageService.deleteImage(identifier, ad.getAdvertisementImage().getId());
AdvertisementImage adImage = adImageService.saveImage(image);
ad.updateFrom(adRequest, adImage);
adImage.setAdvertisement(ad);
Expand All @@ -69,9 +70,9 @@ public AdvertisementResponse update(Long adId, AdvertisementRequest adRequest, M
}

@Transactional
public void delete(Long adId) {
public void delete(MemberIdentifier identifier, Long adId) {
Advertisement ad = getByIdOrThrow(adId);
adImageService.deleteImage(ad.getAdvertisementImage().getId());
adImageService.deleteImage(identifier, ad.getAdvertisementImage().getId());
adRepository.deleteById(adId);
}
}
Loading

0 comments on commit 98af56f

Please sign in to comment.