diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/PhotoController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/PhotoController.java index dcb7981..7859d63 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/PhotoController.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/PhotoController.java @@ -53,7 +53,7 @@ public Flux uploadFileUrlPhoto( PhotoFileUrlUploadRequest request ){ return photoService - .createNewPhotoFileUrl(request.fileUrls(), memberId) + .createNewPhotoFileUrls(request.fileUrls(), request.albumId(), memberId) .map(PhotoResponse::fromEntity); } diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoFileUrlUploadRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoFileUrlUploadRequest.java index 1787366..442e8b9 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoFileUrlUploadRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoFileUrlUploadRequest.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.ULID; @Schema(description = "파일(url) 사진 n건 업로드 요청") public record PhotoFileUrlUploadRequest( @@ -9,6 +10,10 @@ public record PhotoFileUrlUploadRequest( schema = @Schema(description = "파일 URL 목록"), arraySchema = @Schema(example = "[\"file_url_1\", \"file_url_2\", \"file_url_3\"]") ) - String[] fileUrls + String[] fileUrls, + + @ULID + @Schema(description = "앨범 ID", example = "test_album_id") + String albumId ) { } diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumEntity.java index 467e76e..312addf 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumEntity.java +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumEntity.java @@ -77,13 +77,13 @@ public AlbumEntity updateType(AlbumType newType) { return this; } - public AlbumEntity increasePhotoCount() { - this.photoCount += 1; + public AlbumEntity increasePhotoCount(int count) { + this.photoCount += count; return this; } - public AlbumEntity decreasePhotoCount() { - this.photoCount -= 1; + public AlbumEntity decreasePhotoCount(int count) { + this.photoCount -= count; return this; } diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PhotoEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PhotoEntity.java index 5084cb5..5b446b3 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/PhotoEntity.java +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/PhotoEntity.java @@ -82,13 +82,14 @@ public PhotoEntity updateDisplayIndex(Integer displayIndex) { return this; } - public static PhotoEntity newPhoto(String photoId, String photoUrl, BrandType brandType, String ownerMemberId) { + public static PhotoEntity newPhoto(String photoId, String photoUrl, BrandType brandType, String albumId, Integer displayIndex, String ownerMemberId) { PhotoEntity photo = new PhotoEntity(); photo.photoId = photoId; photo.photoUrl = photoUrl; photo.brand = brandType; photo.ownerMemberId = ownerMemberId; - photo.displayIndex = 0; + photo.albumId = albumId; + photo.displayIndex = displayIndex; photo.isNew = true; photo.createdAt = LocalDateTime.now(); photo.updatedAt = LocalDateTime.now(); diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumService.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumService.java index 1b80189..b32abac 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumService.java @@ -67,85 +67,39 @@ public Mono findByAlbumId(String albumId, String requestMemberId) { @Transactional public Mono deleteAlbumById(String albumId, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if(!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumRepository + return findByAlbumId(albumId, requestMemberId) + .flatMap(albumEntity -> + albumRepository .deleteById(albumId) .then(albumRepository.popDisplayIndexBetween( - requestMemberId, albumEntity.getDisplayIndex(), Integer.MAX_VALUE)); - } - }); + requestMemberId, albumEntity.getDisplayIndex(), Integer.MAX_VALUE)) + ); } @Transactional public Mono updateAlbumName(String albumId, String albumName, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if(!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumRepository.save(albumEntity.updateName(albumName)); - } - }); + return findByAlbumId(albumId, requestMemberId) + .flatMap(albumEntity -> albumRepository.save(albumEntity.updateName(albumName))); } @Transactional public Mono updateAlbumType(String albumId, AlbumType albumType, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if(!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumRepository.save(albumEntity.updateType(albumType)); - } - }); + return findByAlbumId(albumId, requestMemberId) + .flatMap(albumEntity -> albumRepository.save(albumEntity.updateType(albumType))); } @Transactional - public Mono increaseAlbumPhotoCount(String albumId, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumRepository.save(albumEntity.increasePhotoCount()).then(); - } - }); + public Mono increaseAlbumPhotoCount(String albumId, int count, String requestMemberId) { + return findByAlbumId(albumId, requestMemberId) + .flatMap(albumEntity -> albumRepository.save(albumEntity.increasePhotoCount(count))); } @Transactional - public Mono decreaseAlbumPhotoCount(String albumId, String requestMemberId) { - - if (albumId == null) { - return Mono.empty(); - } - - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumRepository.save(albumEntity.decreasePhotoCount()).then(); - } - }); + public Mono decreaseAlbumPhotoCount(String albumId, int count, String requestMemberId) { + return Mono.justOrEmpty(albumId) + .switchIfEmpty(Mono.empty()) + .flatMap(id -> findByAlbumId(id, requestMemberId)) + .flatMap(albumEntity -> albumRepository.save(albumEntity.decreasePhotoCount(count))); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoService.java b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoService.java index b2a681f..e5f2a67 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoService.java @@ -2,11 +2,9 @@ import kr.mafoo.photo.domain.BrandType; import kr.mafoo.photo.domain.PhotoEntity; -import kr.mafoo.photo.exception.AlbumNotFoundException; import kr.mafoo.photo.exception.PhotoDisplayIndexIsSameException; import kr.mafoo.photo.exception.PhotoDisplayIndexNotValidException; import kr.mafoo.photo.exception.PhotoNotFoundException; -import kr.mafoo.photo.repository.AlbumRepository; import kr.mafoo.photo.repository.PhotoRepository; import kr.mafoo.photo.util.IdGenerator; import lombok.RequiredArgsConstructor; @@ -21,13 +19,14 @@ import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +import java.util.concurrent.atomic.AtomicInteger; + @Slf4j @RequiredArgsConstructor @Service public class PhotoService { private final PhotoRepository photoRepository; - private final AlbumRepository albumRepository; private final AlbumService albumService; private final QrService qrService; @@ -43,15 +42,29 @@ public Mono createNewPhotoByQrUrl(String qrUrl, String requestMembe } @Transactional - public Flux createNewPhotoFileUrl(String[] fileUrls, String requestMemberId) { - return Flux.fromArray(fileUrls) - .flatMap(fileUrl -> objectStorageService.setObjectPublicRead(fileUrl) - .flatMap(fileLink -> createNewPhoto(fileLink, BrandType.EXTERNAL, requestMemberId)) - ); + public Flux createNewPhotoFileUrls(String[] fileUrls, String albumId, String requestMemberId) { + return albumService.findByAlbumId(albumId, requestMemberId) + .flatMapMany(albumEntity -> { + AtomicInteger displayIndex = new AtomicInteger(albumEntity.getPhotoCount()); + + return Flux.fromArray(fileUrls) + .concatMap(fileUrl -> + createNewPhotoFileUrl(fileUrl, BrandType.EXTERNAL, albumId, displayIndex.getAndIncrement(), requestMemberId) + ); + }); + } + + private Mono createNewPhotoFileUrl(String fileUrl, BrandType type, String albumId, Integer displayIndex, String requestMemberId) { + return objectStorageService.setObjectPublicRead(fileUrl) + .flatMap(fileLink -> { + PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), fileLink, type, albumId, displayIndex, requestMemberId); + return albumService.increaseAlbumPhotoCount(albumId, 1, requestMemberId) + .then(photoRepository.save(photoEntity)); + }); } private Mono createNewPhoto(String photoUrl, BrandType type, String requestMemberId) { - PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, type, requestMemberId); + PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, type, null, 0, requestMemberId); return photoRepository.save(photoEntity); } @@ -73,7 +86,7 @@ public Flux uploadPhoto(Flux files, String requestMemberI }) .flatMap(bytes -> objectStorageService.uploadFile(bytes) .flatMap(photoUrl -> { - PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, BrandType.EXTERNAL, requestMemberId); + PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, BrandType.EXTERNAL, null, 0, requestMemberId); return photoRepository.save(photoEntity); })) .subscribeOn(Schedulers.boundedElastic()) @@ -82,122 +95,96 @@ public Flux uploadPhoto(Flux files, String requestMemberI } public Flux findAllByAlbumId(String albumId, String requestMemberId, String sort) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMapMany(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - String sortMethod = (sort == null) ? "CUSTOM" : sort.toUpperCase(); + String sortMethod = (sort == null) ? "CUSTOM" : sort.toUpperCase(); - return switch (sortMethod) { + return albumService.findByAlbumId(albumId, requestMemberId) + .thenMany( + switch (sortMethod) { case "ASC" -> photoRepository.findAllByAlbumIdOrderByCreatedAtAsc(albumId); case "DESC" -> photoRepository.findAllByAlbumIdOrderByCreatedAtDesc(albumId); default -> photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); - }; - } - }); + } + ); } - @Transactional - public Mono deletePhotoById(String photoId, String requestMemberId) { + public Mono findByPhotoId(String photoId, String requestMemberId) { return photoRepository .findById(photoId) .switchIfEmpty(Mono.error(new PhotoNotFoundException())) .flatMap(photoEntity -> { - if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) { + if (!photoEntity.hasOwnerMemberId()) { + return photoRepository.save(photoEntity.updateOwnerMemberId(requestMemberId)); + } + else if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) { // 내 사진이 아니면 그냥 없는 사진 처리 return Mono.error(new PhotoNotFoundException()); } else { - return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId(), requestMemberId) - .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) - .then(photoRepository.deleteById(photoId)); + return Mono.just(photoEntity); } }); } + @Transactional + public Mono deletePhotoById(String photoId, String requestMemberId) { + return findByPhotoId(photoId, requestMemberId) + .flatMap(photoEntity -> + albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId(), 1, requestMemberId) + .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) + .then(photoRepository.deleteById(photoId)) + ); + } + @Transactional public Flux updatePhotoBulkAlbumId(String[] photoIds, String albumId, String requestMemberId) { return Flux.fromArray(photoIds) - .flatMap(photoId -> - this.updatePhotoAlbumId(photoId, albumId, requestMemberId) - ); + .concatMap(photoId -> this.updatePhotoAlbumId(photoId, albumId, requestMemberId)); } @Transactional public Mono updatePhotoAlbumId(String photoId, String albumId, String requestMemberId) { - return photoRepository - .findById(photoId) - .switchIfEmpty(Mono.error(new PhotoNotFoundException())) - .flatMap(photoEntity -> { - - if (!photoEntity.hasOwnerMemberId()) { - photoRepository.save(photoEntity.updateOwnerMemberId(requestMemberId)); - } - - if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 사진이 아니면 그냥 없는 사진 처리 - return Mono.error(new PhotoNotFoundException()); - } else { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId(), requestMemberId) + return findByPhotoId(photoId, requestMemberId) + .flatMap(photoEntity -> + albumService.findByAlbumId(albumId, requestMemberId) + .flatMap(albumEntity -> + albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId(), 1, requestMemberId) .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) - .then(albumService.increaseAlbumPhotoCount(albumId, requestMemberId)) + .then(albumService.increaseAlbumPhotoCount(albumId, 1, requestMemberId)) .then(photoRepository.save( photoEntity .updateAlbumId(albumId) .updateDisplayIndex(albumEntity.getPhotoCount()) - )); - } - }); - } - }); + )) + ) + ); } @Transactional public Mono updatePhotoDisplayIndex(String photoId, Integer newIndex, String requestMemberId) { - return photoRepository - .findById(photoId) - .switchIfEmpty(Mono.error(new PhotoNotFoundException())) - .flatMap(photoEntity -> albumRepository - .findById(photoEntity.getAlbumId()) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - - int targetIndex = albumEntity.getPhotoCount() - newIndex - 1; - - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - return Mono.error(new AlbumNotFoundException()); - } - - if (photoEntity.getDisplayIndex().equals(targetIndex)) { - return Mono.error(new PhotoDisplayIndexIsSameException()); - } - - if (targetIndex < 0 || targetIndex >= albumEntity.getPhotoCount()) { - return Mono.error(new PhotoDisplayIndexNotValidException()); - } - - if (photoEntity.getDisplayIndex() < targetIndex) { - return photoRepository - .popDisplayIndexBetween(photoEntity.getAlbumId(), photoEntity.getDisplayIndex() + 1, targetIndex) - .then(photoRepository.save(photoEntity.updateDisplayIndex(targetIndex))); - } else { - return photoRepository - .pushDisplayIndexBetween(photoEntity.getAlbumId(), targetIndex, photoEntity.getDisplayIndex() - 1) - .then(photoRepository.save(photoEntity.updateDisplayIndex(targetIndex))); - } - - })); + return findByPhotoId(photoId, requestMemberId) + .flatMap(photoEntity -> + albumService.findByAlbumId(photoEntity.getAlbumId(), requestMemberId) + .flatMap(albumEntity -> { + int targetIndex = albumEntity.getPhotoCount() - newIndex - 1; + + if (photoEntity.getDisplayIndex().equals(targetIndex)) { + return Mono.error(new PhotoDisplayIndexIsSameException()); + } + + if (targetIndex < 0 || targetIndex >= albumEntity.getPhotoCount()) { + return Mono.error(new PhotoDisplayIndexNotValidException()); + } + + if (photoEntity.getDisplayIndex() < targetIndex) { + return photoRepository + .popDisplayIndexBetween(photoEntity.getAlbumId(), photoEntity.getDisplayIndex() + 1, targetIndex) + .then(photoRepository.save(photoEntity.updateDisplayIndex(targetIndex))); + } else { + return photoRepository + .pushDisplayIndexBetween(photoEntity.getAlbumId(), targetIndex, photoEntity.getDisplayIndex() - 1) + .then(photoRepository.save(photoEntity.updateDisplayIndex(targetIndex))); + } + }) + ); } }