diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/UserBannerController.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/UserBannerController.java index 3c762503..8fc56751 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/UserBannerController.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/UserBannerController.java @@ -5,7 +5,6 @@ import ddingdong.ddingdongBE.domain.banner.service.FacadeUserBannerService; import java.util.List; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/request/CreateBannerRequest.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/request/CreateBannerRequest.java index ba813d2e..76797f58 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/request/CreateBannerRequest.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/request/CreateBannerRequest.java @@ -4,22 +4,26 @@ import ddingdong.ddingdongBE.domain.user.entity.User; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import org.hibernate.validator.constraints.URL; @Schema( name = "CreateBannerRequest", description = "어드민 - 배너 생성 요청" ) public record CreateBannerRequest( - @Schema(description = "웹 이미지 key", example = "local/file/2024-01-01/ddingdong/uuid") - @NotNull(message = "webImageKey는 필수입니다.") - String webImageKey, - @Schema(description = "모바일 이미지 key", example = "local/file/2024-01-01/ddingdong/uuid") - @NotNull(message = "mobileImageKey 필수입니다.") - String mobileImageKey + @Schema(description = "연결 링크", example = "https://test-link.com") + @URL + String link, + @Schema(description = "웹 이미지 식별자", example = "0192c828-ffce-7ee8-94a8-d9d4c8cdec00") + @NotNull(message = "webImageId는 필수입니다.") + String webImageId, + @Schema(description = "모바일 이미지 식별자", example = "0192c828-ffce-7ee8-94a8-d9d4c8cdec00") + @NotNull(message = "mobileImageId 필수입니다.") + String mobileImageId ) { public CreateBannerCommand toCommand(User user) { - return new CreateBannerCommand(user, webImageKey, mobileImageKey); + return new CreateBannerCommand(user, link, webImageId, mobileImageId); } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/AdminBannerListResponse.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/AdminBannerListResponse.java index 7b3884a7..619d643f 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/AdminBannerListResponse.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/AdminBannerListResponse.java @@ -11,6 +11,8 @@ public record AdminBannerListResponse( @Schema(description = "배너 식별자", example = "1") Long id, + @Schema(description = "연결 링크", example = "https://test.com") + String link, AdminBannerListImageUrlResponse webImageUrl, AdminBannerListImageUrlResponse mobileImageUrl ) { @@ -18,6 +20,7 @@ public record AdminBannerListResponse( public static AdminBannerListResponse from(AdminBannerListQuery query) { return new AdminBannerListResponse( query.id(), + query.link(), AdminBannerListImageUrlResponse.from(query.webImageUrlQuery()), AdminBannerListImageUrlResponse.from(query.mobileImageUrlQuery()) ); diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/UserBannerListResponse.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/UserBannerListResponse.java index cf2dc949..0127c299 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/UserBannerListResponse.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/controller/dto/response/UserBannerListResponse.java @@ -11,6 +11,8 @@ public record UserBannerListResponse( @Schema(description = "배너 식별자", example = "1") Long id, + @Schema(description = "연결 링크", example = "https://test.com") + String link, UserBannerListImageUrlResponse webImageUrl, UserBannerListImageUrlResponse mobileImageUrl ) { @@ -18,6 +20,7 @@ public record UserBannerListResponse( public static UserBannerListResponse from(UserBannerListQuery query) { return new UserBannerListResponse( query.id(), + query.link(), UserBannerListImageUrlResponse.from(query.webImageUrlQuery()), UserBannerListImageUrlResponse.from(query.mobileImageUrlQuery()) ); diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/entity/Banner.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/entity/Banner.java index 7de636c0..0cece87d 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/entity/Banner.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/entity/Banner.java @@ -33,23 +33,16 @@ public class Banner extends BaseEntity { @JoinColumn(name = "user_id") private User user; - private String webImageKey; - - private String mobileImageKey; + private String link; @Column(name = "deleted_at", columnDefinition = "TIMESTAMP") private LocalDateTime deletedAt; @Builder - private Banner(Long id, User user, String webImageKey, String mobileImageKey) { + private Banner(Long id, User user, String link) { this.id = id; this.user = user; - this.webImageKey = webImageKey; - this.mobileImageKey = mobileImageKey; + this.link = link; } - public void update(Banner banner) { - this.webImageKey = banner.getWebImageKey(); - this.mobileImageKey = banner.getMobileImageKey(); - } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/repository/dto/BannerWithFileMetaDataDto.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/repository/dto/BannerWithFileMetaDataDto.java new file mode 100644 index 00000000..873abad3 --- /dev/null +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/repository/dto/BannerWithFileMetaDataDto.java @@ -0,0 +1,12 @@ +package ddingdong.ddingdongBE.domain.banner.repository.dto; + +import ddingdong.ddingdongBE.domain.banner.entity.Banner; +import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; +import java.util.List; + +public record BannerWithFileMetaDataDto( + Banner banner, + List fileMetaDataList +) { + +} diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/BannerService.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/BannerService.java index 36dc046a..99751782 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/BannerService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/BannerService.java @@ -9,8 +9,6 @@ public interface BannerService { List findAll(); - void update(Long bannerId, Banner updatedBanner); - void delete(Long bannerId); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImpl.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImpl.java index 2e3b66af..047c6665 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImpl.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImpl.java @@ -3,9 +3,15 @@ import ddingdong.ddingdongBE.domain.banner.entity.Banner; import ddingdong.ddingdongBE.domain.banner.service.dto.command.CreateBannerCommand; import ddingdong.ddingdongBE.domain.banner.service.dto.query.AdminBannerListQuery; +import ddingdong.ddingdongBE.domain.filemetadata.entity.DomainType; +import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; import ddingdong.ddingdongBE.domain.filemetadata.service.FileMetaDataService; import ddingdong.ddingdongBE.file.service.S3FileService; +import ddingdong.ddingdongBE.file.service.dto.query.UploadedFileUrlQuery; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,24 +28,23 @@ public class FacadeAdminBannerServiceImpl implements FacadeAdminBannerService { @Override @Transactional public Long create(CreateBannerCommand command) { -// fileMetaDataService.save(List.of( -// FileMetaData.of(command.webImageKey(), BANNER_WEB_IMAGE), -// FileMetaData.of(command.mobileImageKey(), BANNER_MOBILE_IMAGE) -// ) -// ); - return bannerService.save(command.toEntity()); + Long savedBannerId = bannerService.save(command.toEntity()); + fileMetaDataService.updateStatusToCoupled(command.webImageId(), DomainType.BANNER_WEB_IMAGE, savedBannerId); + fileMetaDataService.updateStatusToCoupled( + command.mobileImageId(), DomainType.BANNER_MOBILE_IMAGE, savedBannerId); + return savedBannerId; } @Override public List findAll() { List banners = bannerService.findAll(); + if (banners.isEmpty()) { + return Collections.emptyList(); + } + List bannerImages = fileMetaDataService.getCoupledAllByEntityIds( + banners.stream().map(Banner::getId).toList()); return banners.stream() - .map(banner -> AdminBannerListQuery.of( - banner, - s3FileService.getUploadedFileUrl(banner.getWebImageKey()), - s3FileService.getUploadedFileUrl(banner.getMobileImageKey()) - ) - ) + .map(banner -> createBannerListQuery(banner, bannerImages)) .toList(); } @@ -47,6 +52,26 @@ public List findAll() { @Transactional public void delete(Long bannerId) { bannerService.delete(bannerId); + fileMetaDataService.updateStatusToDelete(DomainType.BANNER_WEB_IMAGE, bannerId); + fileMetaDataService.updateStatusToDelete(DomainType.BANNER_MOBILE_IMAGE, bannerId); + } + + private AdminBannerListQuery createBannerListQuery(Banner banner, List bannerImages) { + Map fileMetaDataMap = bannerImages.stream() + .filter(fileMetaData -> fileMetaData.isOwn(banner.getId())) + .collect(Collectors.toMap( + FileMetaData::getDomainType, + fileMetaData -> fileMetaData, + (existing, replacement) -> existing + )); + + UploadedFileUrlQuery webImageUrlQuery = s3FileService.getUploadedFileUrl( + fileMetaDataMap.get(DomainType.BANNER_WEB_IMAGE).getFileKey() + ); + UploadedFileUrlQuery mobileImageUrlQuery = s3FileService.getUploadedFileUrl( + fileMetaDataMap.get(DomainType.BANNER_MOBILE_IMAGE).getFileKey() + ); + return AdminBannerListQuery.of(banner, webImageUrlQuery, mobileImageUrlQuery); } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImpl.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImpl.java index dc1bcd34..881395ca 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImpl.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImpl.java @@ -2,8 +2,15 @@ import ddingdong.ddingdongBE.domain.banner.entity.Banner; import ddingdong.ddingdongBE.domain.banner.service.dto.query.UserBannerListQuery; +import ddingdong.ddingdongBE.domain.filemetadata.entity.DomainType; +import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; +import ddingdong.ddingdongBE.domain.filemetadata.service.FileMetaDataService; import ddingdong.ddingdongBE.file.service.S3FileService; +import ddingdong.ddingdongBE.file.service.dto.query.UploadedFileUrlQuery; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,18 +21,45 @@ public class FacadeUserBannerServiceImpl implements FacadeUserBannerService { private final BannerService bannerService; + private final FileMetaDataService fileMetaDataService; private final S3FileService s3FileService; @Override public List findAll() { List banners = bannerService.findAll(); + if (banners.isEmpty()) { + return Collections.emptyList(); + } + + List bannerImages = fileMetaDataService.getCoupledAllByEntityIds( + banners.stream() + .map(Banner::getId) + .toList() + ); + return banners.stream() - .map(banner -> UserBannerListQuery.of( - banner, - s3FileService.getUploadedFileUrl(banner.getWebImageKey()), - s3FileService.getUploadedFileUrl(banner.getMobileImageKey()) - ) - ) + .map(banner -> createBannerListQuery(banner, bannerImages)) .toList(); } + + private UserBannerListQuery createBannerListQuery(Banner banner, List bannerImages) { + if (bannerImages.isEmpty()) { + return UserBannerListQuery.of(banner, null, null); + } + Map fileMetaDataMap = bannerImages.stream() + .filter(fileMetaData -> fileMetaData.getEntityId().equals(banner.getId())) + .collect(Collectors.toMap( + FileMetaData::getDomainType, + fileMetaData -> fileMetaData, + (existing, replacement) -> existing + )); + + UploadedFileUrlQuery webImageUrlQuery = s3FileService.getUploadedFileUrl( + fileMetaDataMap.get(DomainType.BANNER_WEB_IMAGE).getFileKey() + ); + UploadedFileUrlQuery mobileImageUrlQuery = s3FileService.getUploadedFileUrl( + fileMetaDataMap.get(DomainType.BANNER_MOBILE_IMAGE).getFileKey() + ); + return UserBannerListQuery.of(banner, webImageUrlQuery, mobileImageUrlQuery); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/GeneralBannerService.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/GeneralBannerService.java index 59f2a67e..e40a34f7 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/GeneralBannerService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/GeneralBannerService.java @@ -27,13 +27,6 @@ public List findAll() { return bannerRepository.findAllByOrderByIdDesc(); } - @Override - @Transactional - public void update(Long bannerId, Banner updatedBanner) { - Banner banner = getBanner(bannerId); - banner.update(updatedBanner); - } - @Override @Transactional public void delete(Long bannerId) { diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/command/CreateBannerCommand.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/command/CreateBannerCommand.java index e5addfb3..6863fa13 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/command/CreateBannerCommand.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/command/CreateBannerCommand.java @@ -5,15 +5,15 @@ public record CreateBannerCommand( User user, - String webImageKey, - String mobileImageKey + String link, + String webImageId, + String mobileImageId ) { public Banner toEntity() { return Banner.builder() .user(user) - .webImageKey(webImageKey) - .mobileImageKey(mobileImageKey) + .link(link) .build(); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/AdminBannerListQuery.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/AdminBannerListQuery.java index d42a4a4b..7e007ea0 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/AdminBannerListQuery.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/AdminBannerListQuery.java @@ -5,15 +5,17 @@ public record AdminBannerListQuery( Long id, + String link, UploadedFileUrlQuery webImageUrlQuery, UploadedFileUrlQuery mobileImageUrlQuery ) { public static AdminBannerListQuery of( - Banner banner, UploadedFileUrlQuery webImageUrlQuery, + Banner banner, + UploadedFileUrlQuery webImageUrlQuery, UploadedFileUrlQuery mobileImageUrlQuery ) { - return new AdminBannerListQuery(banner.getId(), webImageUrlQuery, mobileImageUrlQuery); + return new AdminBannerListQuery(banner.getId(), banner.getLink(), webImageUrlQuery, mobileImageUrlQuery); } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/UserBannerListQuery.java b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/UserBannerListQuery.java index 5edf76d9..c4edba22 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/UserBannerListQuery.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/banner/service/dto/query/UserBannerListQuery.java @@ -5,6 +5,7 @@ public record UserBannerListQuery( Long id, + String link, UploadedFileUrlQuery webImageUrlQuery, UploadedFileUrlQuery mobileImageUrlQuery ) { @@ -14,7 +15,7 @@ public static UserBannerListQuery of( UploadedFileUrlQuery webImageUrlQuery, UploadedFileUrlQuery mobileImageUrlQuery ) { - return new UserBannerListQuery(banner.getId(), webImageUrlQuery, mobileImageUrlQuery); + return new UserBannerListQuery(banner.getId(), banner.getLink(), webImageUrlQuery, mobileImageUrlQuery); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/DomainType.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/DomainType.java index 044b8927..5a63f508 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/DomainType.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/DomainType.java @@ -7,5 +7,7 @@ public enum DomainType { NOTICE_IMAGE, NOTICE_FILE, DOCUMENT_FILE, - ACTIVITY_REPORT_IMAGE + ACTIVITY_REPORT_IMAGE, + BANNER_WEB_IMAGE, + BANNER_MOBILE_IMAGE, } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileCategory.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileCategory.java deleted file mode 100644 index ad231f9f..00000000 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileCategory.java +++ /dev/null @@ -1,12 +0,0 @@ -package ddingdong.ddingdongBE.domain.filemetadata.entity; - -public enum FileCategory { - CLUB_PROFILE_IMAGE, - CLUB_INTRODUCTION_IMAGE, - BANNER_WEB_IMAGE, - BANNER_MOBILE_IMAGE, - ACTIVITY_REPORT_IMAGE, - DOCUMENT_FILE, - NOTICE_IMAGE, - NOTICE_FILE -} diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileMetaData.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileMetaData.java index aca3eeb9..41303792 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileMetaData.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/entity/FileMetaData.java @@ -13,13 +13,11 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.SQLRestriction; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(name = "file_meta_data",indexes = {@Index(columnList = "domainType,entityId,fileStatus")}) -@SQLRestriction("file_status != 'DELETED'") public class FileMetaData extends BaseEntity { @Id @@ -41,20 +39,15 @@ public class FileMetaData extends BaseEntity { @Column(nullable = false) private FileStatus fileStatus; - @Enumerated(EnumType.STRING) - private FileCategory fileCategory; - @Builder private FileMetaData(UUID id, String fileKey, String fileName, DomainType domainType, Long entityId, - FileStatus fileStatus, - FileCategory fileCategory) { + FileStatus fileStatus) { this.id = id; this.fileKey = fileKey; this.fileName = fileName; this.domainType = domainType; this.entityId = entityId; this.fileStatus = fileStatus; - this.fileCategory = fileCategory; } public static FileMetaData createPending(UUID id, String fileKey, String fileName) { @@ -82,4 +75,8 @@ public boolean isCoupled() { public boolean isPending() { return this.fileStatus == FileStatus.PENDING; } + + public boolean isOwn(Long entityId) { + return this.entityId.equals(entityId); + } } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/repository/FileMetaDataRepository.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/repository/FileMetaDataRepository.java index 74052782..a10a419f 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/repository/FileMetaDataRepository.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/repository/FileMetaDataRepository.java @@ -12,16 +12,21 @@ public interface FileMetaDataRepository extends JpaRepository { @Query(""" - select fmd from FileMetaData fmd - where fmd.domainType = :domainType - and fmd.entityId = :entityId - and fmd.fileStatus = :fileStatus - and fmd.fileStatus != 'DELETED' - """) + select fmd from FileMetaData fmd + where fmd.domainType = :domainType + and fmd.entityId = :entityId + and fmd.fileStatus = :fileStatus + """) List findAllByDomainTypeAndEntityIdWithFileStatus( - @Param("domainType") DomainType domainType, - @Param("entityId") Long entityId, - @Param("fileStatus") FileStatus fileStatus + @Param("domainType") DomainType domainType, + @Param("entityId") Long entityId, + @Param("fileStatus") FileStatus fileStatus + ); + + @Query("select fmd from FileMetaData fmd where fmd.entityId = :entityId and fmd.fileStatus = :fileStatus") + List findAllByEntityIdWithFileStatus( + @Param("entityId") Long entityId, + @Param("fileStatus") FileStatus fileStatus ); @Query(value = """ @@ -31,8 +36,8 @@ List findAllByDomainTypeAndEntityIdWithFileStatus( and file_status != 'DELETED' """, nativeQuery = true) List findAllByDomainTypeAndEntityId( - @Param("domainType") DomainType domainType, - @Param("entityId") Long entityId + @Param("domainType") DomainType domainType, + @Param("entityId") Long entityId ); @Query(value = """ @@ -44,16 +49,18 @@ where id in (:ids) List findByIdIn(@Param("ids") List ids); @Query(""" - select fmd from FileMetaData fmd - where fmd.domainType = :domainType - and fmd.entityId = :entityId - and fmd.fileStatus = :fileStatus - and fmd.fileStatus != 'DELETED' - order by fmd.id asc - """) + select fmd from FileMetaData fmd + where fmd.domainType = :domainType + and fmd.entityId = :entityId + and fmd.fileStatus = :fileStatus + order by fmd.id asc + """) List findAllByDomainTypeAndEntityIdWithFileStatusOrderedAsc( - @Param("domainType") DomainType domainType, - @Param("entityId") Long entityId, - @Param("fileStatus") FileStatus fileStatus + @Param("domainType") DomainType domainType, + @Param("entityId") Long entityId, + @Param("fileStatus") FileStatus fileStatus ); + + @Query("SELECT f FROM FileMetaData f WHERE (f.domainType = 'BANNER_WEB_IMAGE' OR f.domainType = 'BANNER_MOBILE_IMAGE') AND f.entityId IN :entityIds AND f.fileStatus != 'DELETED'") + List findAllWithBannerByEntityIds(@Param("entityIds") List entityIds); } diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataService.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataService.java index 2bb421dd..1e58f3ad 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataService.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataService.java @@ -11,9 +11,13 @@ public interface FileMetaDataService { List getCoupledAllByDomainTypeAndEntityId(DomainType domainType, Long entityId); + List getCoupledAllByEntityId(Long entityId); + List getCoupledAllByDomainTypeAndEntityIdOrderedAsc(DomainType domainType, Long entityId); + List getCoupledAllByEntityIds(List entityIds); + void updateStatusToCoupled(List ids, DomainType domainType, Long entityId); void updateStatusToCoupled(String id, DomainType domainType, Long entityId); diff --git a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImpl.java b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImpl.java index b50ad12b..c3e7e627 100644 --- a/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImpl.java +++ b/src/main/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImpl.java @@ -7,7 +7,6 @@ import ddingdong.ddingdongBE.domain.filemetadata.entity.DomainType; import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; import ddingdong.ddingdongBE.domain.filemetadata.repository.FileMetaDataRepository; -import jakarta.persistence.EntityManager; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -22,7 +21,6 @@ public class FileMetaDataServiceImpl implements FileMetaDataService { private final FileMetaDataRepository fileMetaDataRepository; - private final EntityManager entityManager; @Override @Transactional @@ -36,6 +34,11 @@ public List getCoupledAllByDomainTypeAndEntityId(DomainType domain return fileMetaDataRepository.findAllByDomainTypeAndEntityIdWithFileStatus(domainType, entityId, COUPLED); } + @Override + public List getCoupledAllByEntityId(Long entityId) { + return fileMetaDataRepository.findAllByEntityIdWithFileStatus(entityId, COUPLED); + } + @Override public List getCoupledAllByDomainTypeAndEntityIdOrderedAsc(DomainType domainType, Long entityId) { @@ -43,6 +46,11 @@ public List getCoupledAllByDomainTypeAndEntityIdOrderedAsc(DomainT domainType, entityId, COUPLED); } + @Override + public List getCoupledAllByEntityIds(List entityIds) { + return fileMetaDataRepository.findAllWithBannerByEntityIds(entityIds); + } + @Transactional @Override public void updateStatusToCoupled(List ids, DomainType domainType, Long entityId) { @@ -50,16 +58,16 @@ public void updateStatusToCoupled(List ids, DomainType domainType, Long return; } List fileMetaDataIds = toUUIDs(ids); - List fileMetaDatas = fileMetaDataRepository.findByIdIn(fileMetaDataIds); - if (ids.size() != fileMetaDatas.size()) { + List fileMetaDataList = fileMetaDataRepository.findByIdIn(fileMetaDataIds); + if (ids.size() != fileMetaDataList.size()) { throw new ResourceNotFound("해당 FileMetaData(id: " + fileMetaDataIds + ")를 찾을 수 없습니다."); } - fileMetaDatas.stream() - .filter(FileMetaData::isPending) - .forEach(fileMetaData -> { - fileMetaData.updateCoupledEntityInfo(domainType, entityId); - fileMetaData.updateStatus(COUPLED); - }); + fileMetaDataList.stream() + .filter(FileMetaData::isPending) + .forEach(fileMetaData -> { + fileMetaData.updateCoupledEntityInfo(domainType, entityId); + fileMetaData.updateStatus(COUPLED); + }); } @Transactional @@ -100,17 +108,15 @@ public void update(List ids, DomainType domainType, Long entityId) { @Override public void updateStatusToDelete(DomainType domainType, Long entityId) { List fileMetaDatas = fileMetaDataRepository.findAllByDomainTypeAndEntityId(domainType, entityId); - fileMetaDatas.forEach(fileMetaData -> { - fileMetaData.updateStatus(DELETED); - }); + fileMetaDatas.forEach(fileMetaData -> fileMetaData.updateStatus(DELETED)); } private List getNewIds(List ids) { List fileMetaDatas = fileMetaDataRepository.findByIdIn(toUUIDs(ids)); return fileMetaDatas.stream() - .filter(FileMetaData::isPending) - .map(fileMetaData -> String.valueOf(fileMetaData.getId())) - .toList(); + .filter(FileMetaData::isPending) + .map(fileMetaData -> String.valueOf(fileMetaData.getId())) + .toList(); } private boolean isCoupled(String id) { @@ -124,19 +130,19 @@ private boolean isCoupled(String id) { private void deleteOldIds(List ids, DomainType domainType, Long entityId) { List fileMetaDatas = fileMetaDataRepository.findAllByDomainTypeAndEntityId(domainType, entityId); List deleteTarget = fileMetaDatas.stream() - .filter(fileMetaData -> !ids.contains(String.valueOf(fileMetaData.getId()))) - .toList(); + .filter(fileMetaData -> !ids.contains(String.valueOf(fileMetaData.getId()))) + .toList(); deleteTarget.forEach(target -> target.updateStatus(DELETED)); } private FileMetaData findById(UUID id) { return fileMetaDataRepository.findById(id) - .orElseThrow(() -> new ResourceNotFound("해당 FileMetaData(id: " + id + ")를 찾을 수 없습니다.")); + .orElseThrow(() -> new ResourceNotFound("해당 FileMetaData(id: " + id + ")를 찾을 수 없습니다.")); } private List toUUIDs(List ids) { return ids.stream() - .map(UUID::fromString) - .toList(); + .map(UUID::fromString) + .toList(); } } diff --git a/src/main/resources/db/migration/V28__alter_table_banner.sql b/src/main/resources/db/migration/V28__alter_table_banner.sql new file mode 100644 index 00000000..a17939d0 --- /dev/null +++ b/src/main/resources/db/migration/V28__alter_table_banner.sql @@ -0,0 +1,11 @@ +ALTER TABLE banner + ADD link VARCHAR(255) NULL; + +ALTER TABLE banner + DROP COLUMN mobile_image_key; + +ALTER TABLE banner + DROP COLUMN web_image_key; + +ALTER TABLE banner + DROP COLUMN file_category; diff --git a/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImplTest.java b/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImplTest.java index ddfd906a..54ebc9eb 100644 --- a/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImplTest.java +++ b/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeAdminBannerServiceImplTest.java @@ -1,6 +1,7 @@ package ddingdong.ddingdongBE.domain.banner.service; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import com.github.f4b6a3.uuid.UuidCreator; import com.navercorp.fixturemonkey.FixtureMonkey; @@ -10,12 +11,17 @@ import ddingdong.ddingdongBE.domain.banner.repository.BannerRepository; import ddingdong.ddingdongBE.domain.banner.service.dto.command.CreateBannerCommand; import ddingdong.ddingdongBE.domain.banner.service.dto.query.AdminBannerListQuery; +import ddingdong.ddingdongBE.domain.filemetadata.entity.DomainType; +import ddingdong.ddingdongBE.domain.filemetadata.entity.FileMetaData; +import ddingdong.ddingdongBE.domain.filemetadata.entity.FileStatus; import ddingdong.ddingdongBE.domain.filemetadata.repository.FileMetaDataRepository; import ddingdong.ddingdongBE.domain.user.entity.User; import ddingdong.ddingdongBE.domain.user.repository.UserRepository; +import jakarta.persistence.EntityManager; import java.util.Comparator; import java.util.List; import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,32 +38,69 @@ class FacadeAdminBannerServiceImplTest extends TestContainerSupport { private UserRepository userRepository; @Autowired private FileMetaDataRepository fileMetaDataRepository; + @Autowired + private EntityManager entityManager; private final FixtureMonkey fixtureMonkey = FixtureMonkeyFactory.getNotNullBuilderIntrospectorMonkey(); + + @BeforeEach + void resetAutoIncrement() { + entityManager.createNativeQuery("ALTER TABLE banner AUTO_INCREMENT = 1").executeUpdate(); + fileMetaDataRepository.deleteAll(); + bannerRepository.deleteAll(); + } + @DisplayName("어드민: Banner 생성") @Test void create() { //given - UUID webUUID = UuidCreator.getTimeOrderedEpoch(); - UUID mobileUUID = UuidCreator.getTimeOrderedEpoch(); - String webImageKey = "test/file/2024-01-01/" + webUUID.toString(); - String mobileImageKey = "test/file/2024-01-01/" + mobileUUID.toString(); + String link = "testLink"; + UUID webImageId = UuidCreator.getTimeOrderedEpoch(); + UUID mobileImageId = UuidCreator.getTimeOrderedEpoch(); User savedUser = userRepository.save(fixtureMonkey.giveMeOne(User.class)); - CreateBannerCommand command = new CreateBannerCommand(savedUser, webImageKey, mobileImageKey); + CreateBannerCommand command = new CreateBannerCommand( + savedUser, + link, + webImageId.toString(), + mobileImageId.toString() + ); + + fileMetaDataRepository.saveAll(List.of( + FileMetaData.builder() + .id(webImageId) + .fileKey("test") + .fileName("test") + .fileStatus(FileStatus.PENDING) + .build(), + FileMetaData.builder() + .id(mobileImageId) + .fileKey("test") + .fileName("test") + .fileStatus(FileStatus.PENDING) + .build() + ) + ); //when Long createdBannerId = facadeAdminBannerService.create(command); //then Banner createdBanner = bannerRepository.findById(createdBannerId).orElseThrow(); + List fileMetaDataList = fileMetaDataRepository.findAllByEntityIdWithFileStatus( + createdBannerId, FileStatus.COUPLED); assertThat(createdBanner) - .extracting("id", "user.id", "webImageKey", "mobileImageKey") + .extracting("id", "user.id", "link") .contains( createdBanner.getId(), savedUser.getId(), - webImageKey, - mobileImageKey + link + ); + assertThat(fileMetaDataList).hasSize(2) + .extracting(FileMetaData::getId, FileMetaData::getFileStatus) + .containsExactlyInAnyOrder( + tuple(webImageId, FileStatus.COUPLED), + tuple(mobileImageId, FileStatus.COUPLED) ); } @@ -66,21 +109,72 @@ void create() { void findAll() { //given User savedUser = userRepository.save(fixtureMonkey.giveMeOne(User.class)); - List banners = fixtureMonkey.giveMeBuilder(Banner.class) - .set("user", savedUser) - .set("deletedAt", null) - .set("webImageKey", "test/file/2024-01-01/test/uuid" ) - .set("mobileImageKey", "test/file/2024-01-01/test/uuid" ) - .sampleList(5); - bannerRepository.saveAll(banners); + bannerRepository.saveAll(List.of( + fixtureMonkey.giveMeBuilder(Banner.class) + .set("id", 1L) + .set("user", savedUser) + .set("deletedAt", null) + .sample(), + fixtureMonkey.giveMeBuilder(Banner.class) + .set("id", 2L) + .set("user", savedUser) + .set("deletedAt", null) + .sample() + )); + + FileMetaData fileMetaData1 = fixtureMonkey.giveMeBuilder(FileMetaData.class) + .set("entityId", 1L) + .set("fileKey", "/test/FILE/2024-01-01/cow/test") + .set("domainType", DomainType.BANNER_WEB_IMAGE) + .set("fileStatus", FileStatus.COUPLED) + .sample(); + FileMetaData fileMetaData2 = fixtureMonkey.giveMeBuilder(FileMetaData.class) + .set("entityId", 1L) + .set("fileKey", "/test/FILE/2024-01-01/cow/test") + .set("domainType", DomainType.BANNER_MOBILE_IMAGE) + .set("fileStatus", FileStatus.COUPLED) + .sample(); + FileMetaData fileMetaData3 = fixtureMonkey.giveMeBuilder(FileMetaData.class) + .set("entityId", 2L) + .set("fileKey", "/test/FILE/2024-01-01/cow/test") + .set("domainType", DomainType.BANNER_WEB_IMAGE) + .set("fileStatus", FileStatus.COUPLED) + .sample(); + FileMetaData fileMetaData4 = fixtureMonkey.giveMeBuilder(FileMetaData.class) + .set("entityId", 2L) + .set("fileKey", "/test/FILE/2024-01-01/cow/test") + .set("domainType", DomainType.BANNER_MOBILE_IMAGE) + .set("fileStatus", FileStatus.COUPLED) + .sample(); + fileMetaDataRepository.saveAll(List.of(fileMetaData1, fileMetaData2, fileMetaData3, fileMetaData4)); //when List result = facadeAdminBannerService.findAll(); //then assertThat(result) - .hasSize(5) - .isSortedAccordingTo(Comparator.comparing(AdminBannerListQuery::id).reversed()); + .hasSize(2) + .isSortedAccordingTo(Comparator.comparing(AdminBannerListQuery::id).reversed()) + .satisfies(queries -> { + AdminBannerListQuery firstBanner = queries.get(0); + AdminBannerListQuery secondBanner = queries.get(1); + + // id=2인 배너 검증 (역순이므로 첫 번째) + assertThat(firstBanner) + .satisfies(banner -> { + assertThat(banner.id()).isEqualTo(2L); + assertThat(banner.webImageUrlQuery()).isNotNull(); + assertThat(banner.mobileImageUrlQuery()).isNotNull(); + }); + + // id=1인 배너 검증 + assertThat(secondBanner) + .satisfies(banner -> { + assertThat(banner.id()).isEqualTo(1L); + assertThat(banner.webImageUrlQuery()).isNotNull(); + assertThat(banner.mobileImageUrlQuery()).isNotNull(); + }); + }); } @DisplayName("어드민: Banner 삭제") diff --git a/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImplTest.java b/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImplTest.java index f34b6e86..fec825ba 100644 --- a/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImplTest.java +++ b/src/test/java/ddingdong/ddingdongBE/domain/banner/service/FacadeUserBannerServiceImplTest.java @@ -37,9 +37,6 @@ void findAll() { User savedUser = userRepository.save(fixtureMonkey.giveMeOne(User.class)); List banners = fixtureMonkey.giveMeBuilder(Banner.class) .set("user", savedUser) - .set("deletedAt", null) - .set("webImageKey", "test/file/2024-01-01/" + savedUser.getAuthId() + "/uuid" ) - .set("mobileImageKey", "test/file/2024-01-01/" + savedUser.getAuthId() + "/uuid" ) .sampleList(5); bannerRepository.saveAll(banners); diff --git a/src/test/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImplTest.java b/src/test/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImplTest.java index ea90b715..c87bc773 100644 --- a/src/test/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImplTest.java +++ b/src/test/java/ddingdong/ddingdongBE/domain/filemetadata/service/FileMetaDataServiceImplTest.java @@ -141,9 +141,12 @@ void updateAllToActivatedAndAttached() { List result = fileMetaDataRepository.findAllByDomainTypeAndEntityIdWithFileStatus( domainType, entityId, FileStatus.COUPLED); + Optional deletedFileMetaData = fileMetaDataRepository.findById(id2); assertThat(result).hasSize(2) .extracting("id", "fileStatus") .contains(tuple(id1, FileStatus.COUPLED), tuple(id3, FileStatus.COUPLED)); + assertThat(deletedFileMetaData).isPresent(); + assertThat(deletedFileMetaData.get().getFileStatus()).isEqualTo(FileStatus.DELETED); } @DisplayName("FileMetaData 수정 - COUPLED & DELETED 기존 아이디를 그대로 입력할 경우") @@ -197,9 +200,10 @@ void updateAllToAttached() { .set("fileStatus", FileStatus.COUPLED) .sample() )); + //when fileMetaDataService.updateStatusToDelete(domainType, entityId); - em.flush(); + //then List result = fileMetaDataRepository.findByIdIn(List.of(id1, id2)); assertThat(result).isEmpty(); diff --git a/src/test/java/ddingdong/ddingdongBE/domain/fixzone/service/FacadeCentralFixZoneServiceImplTest.java b/src/test/java/ddingdong/ddingdongBE/domain/fixzone/service/FacadeCentralFixZoneServiceImplTest.java index 6e557fc1..68a469e6 100644 --- a/src/test/java/ddingdong/ddingdongBE/domain/fixzone/service/FacadeCentralFixZoneServiceImplTest.java +++ b/src/test/java/ddingdong/ddingdongBE/domain/fixzone/service/FacadeCentralFixZoneServiceImplTest.java @@ -263,10 +263,7 @@ void delete() { //then Optional result = fixZoneRepository.findById(savedFixZone.getId()); List fileMetaDataList = fileMetaDataRepository.findByIdIn(List.of(fileId1, fileId2)); - assertThat(result.isPresent()).isFalse(); + assertThat(result).isEmpty(); assertThat(fileMetaDataList).isEmpty(); -// assertThat(fileMetaDataList).hasSize(2) -// .extracting("fileStatus") -// .containsOnly(FileStatus.DELETED); } }