diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/AlbumApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/AlbumApi.java index 239066b..1e9e525 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/api/AlbumApi.java +++ b/photo-service/src/main/java/kr/mafoo/photo/api/AlbumApi.java @@ -7,10 +7,11 @@ import kr.mafoo.photo.annotation.RequestMemberId; import kr.mafoo.photo.annotation.ULID; import kr.mafoo.photo.controller.dto.request.AlbumCreateRequest; -import kr.mafoo.photo.controller.dto.request.AlbumUpdateDisplayIndexRequest; import kr.mafoo.photo.controller.dto.request.AlbumUpdateNameAndTypeRequest; import kr.mafoo.photo.controller.dto.request.AlbumUpdateOwnershipRequest; +import kr.mafoo.photo.controller.dto.response.AlbumDetailResponse; import kr.mafoo.photo.controller.dto.response.AlbumResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; @@ -22,9 +23,12 @@ public interface AlbumApi { @Operation(summary = "사용자 별 앨범 목록 조회", description = "사용자 별 앨범 목록을 조회합니다.") @GetMapping - Flux getAlbumListByMember( + Flux getAlbumListByMember( @RequestMemberId - String memberId + String memberId, + + // Authorization Header를 받아올 목적 + ServerHttpRequest serverHttpRequest ); @Operation(summary = "앨범 단건 조회", description = "앨범 단건을 조회합니다.") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/AlbumController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/AlbumController.java index 0b5f298..d1893e6 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/AlbumController.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/AlbumController.java @@ -2,12 +2,13 @@ import kr.mafoo.photo.api.AlbumApi; import kr.mafoo.photo.controller.dto.request.AlbumCreateRequest; -import kr.mafoo.photo.controller.dto.request.AlbumUpdateDisplayIndexRequest; import kr.mafoo.photo.controller.dto.request.AlbumUpdateNameAndTypeRequest; import kr.mafoo.photo.controller.dto.request.AlbumUpdateOwnershipRequest; +import kr.mafoo.photo.controller.dto.response.AlbumDetailResponse; import kr.mafoo.photo.controller.dto.response.AlbumResponse; import kr.mafoo.photo.service.AlbumService; import lombok.RequiredArgsConstructor; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -19,12 +20,15 @@ public class AlbumController implements AlbumApi { private final AlbumService albumService; @Override - public Flux getAlbumListByMember( - String memberId + public Flux getAlbumListByMember( + String memberId, + ServerHttpRequest serverHttpRequest ) { + String authorizationToken = serverHttpRequest.getHeaders().getFirst("Authorization"); + return albumService - .findAlbumListByMemberId(memberId) - .map(AlbumResponse::fromEntity); + .findAlbumListByMemberId(memberId, authorizationToken) + .map(AlbumDetailResponse::fromDto); } @Override diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumDetailResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumDetailResponse.java new file mode 100644 index 0000000..c835318 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumDetailResponse.java @@ -0,0 +1,45 @@ +package kr.mafoo.photo.controller.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.domain.enums.AlbumType; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; +import kr.mafoo.photo.service.dto.AlbumDto; + +@Schema(description = "앨범 응답") +public record AlbumDetailResponse( + @Schema(description = "앨범 ID", example = "test_album_id") + String albumId, + + @Schema(description = "앨범 이름", example = "야뿌들") + String name, + + @Schema(description = "앨범 종류", example = "HEART") + AlbumType type, + + @Schema(description = "앨범 내 사진 수", example = "6") + String photoCount, + + @Schema(description = "공유 받은 앨범 상태", example = "null") + ShareStatus shareStatus, + + @Schema(description = "공유 받은 앨범 권한", example = "null") + PermissionLevel permissionLevel, + + @Schema(description = "공유 받은 앨범 소유자 프로필 사진 URL", example = "null") + String ownerProfileImageUrl +) { + public static AlbumDetailResponse fromDto( + AlbumDto dto + ) { + return new AlbumDetailResponse( + dto.albumId(), + dto.name(), + dto.type(), + dto.photoCount().toString(), + dto.shareStatus(), + dto.permissionLevel(), + dto.ownerProfileImageUrl() + ); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java index 70b8277..c3eb502 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java @@ -1,6 +1,7 @@ package kr.mafoo.photo.repository; import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.ShareStatus; import org.springframework.data.r2dbc.repository.R2dbcRepository; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; @@ -9,5 +10,6 @@ @Repository public interface SharedMemberRepository extends R2dbcRepository { Flux findAllByAlbumId(String albumId); + Flux findAllByMemberIdAndShareStatusNot(String memberId, ShareStatus status); Mono findByAlbumIdAndMemberId(String albumId, String memberId); } \ No newline at end of file diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java index 5491061..c907870 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java @@ -30,7 +30,7 @@ public Mono verifyOwnershipOrAccessPermission(String albumId, Strin .flatMap(sharedAlbumMember -> checkShareStatus(sharedAlbumMember.getShareStatus()) .then(checkAccessPermission(sharedAlbumMember.getPermissionLevel(), permissionLevel)) - ).then(albumQuery.findById(albumId)) // FIXME : findById 중복 실행 제거 필요 + ).then(albumQuery.findById(albumId)) ); } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java index f2b4ac8..2f272a3 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java @@ -5,6 +5,7 @@ import kr.mafoo.photo.repository.AlbumRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Service @@ -17,4 +18,9 @@ public Mono findById(String albumId) { return albumRepository.findById(albumId) .switchIfEmpty(Mono.error(new AlbumNotFoundException())); } + + public Flux findByMemberId(String memberId) { + return albumRepository.findAllByOwnerMemberIdOrderByDisplayIndex(memberId) + .switchIfEmpty(Mono.error(new AlbumNotFoundException())); + } } 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 e67ae67..12f660f 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 @@ -3,7 +3,11 @@ import static kr.mafoo.photo.domain.enums.PermissionLevel.FULL_ACCESS; import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; +import java.util.Comparator; import kr.mafoo.photo.domain.AlbumEntity; +import kr.mafoo.photo.exception.AlbumNotFoundException; +import kr.mafoo.photo.exception.SharedMemberNotFoundException; +import kr.mafoo.photo.service.dto.AlbumDto; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,15 +23,36 @@ public class AlbumService { private final AlbumPermissionVerifier albumPermissionVerifier; + private final SharedMemberQuery sharedMemberQuery; + private final MemberService memberService; + @Transactional(readOnly = true) - public Flux findAlbumListByMemberId(String memberId) { - return null; + public Flux findAlbumListByMemberId(String memberId, String token) { + return Flux.merge( + findOwnedAlbumListByMemberId(memberId), + findSharedAlbumListByMemberId(memberId, token) + ).sort(Comparator.comparing(AlbumDto::createdAt).reversed()); + } + + private Flux findOwnedAlbumListByMemberId(String memberId) { + return albumQuery.findByMemberId(memberId) + .onErrorResume(AlbumNotFoundException.class, ex -> Mono.empty()) + .map(AlbumDto::fromOwnedAlbum); + } + + private Flux findSharedAlbumListByMemberId(String memberId, String token) { + return sharedMemberQuery.findAllByMemberIdWhereStatusNotRejected(memberId) + .onErrorResume(SharedMemberNotFoundException.class, ex -> Mono.empty()) + .concatMap(sharedMember -> albumQuery.findById(sharedMember.getAlbumId()) + .flatMap(album -> memberService.getMemberInfoById(album.getOwnerMemberId(), token) + .flatMap(member -> Mono.just(AlbumDto.fromSharedAlbum(album, sharedMember, member))) + ) + ); } @Transactional(readOnly = true) public Mono findAlbumById(String albumId, String memberId) { - return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, memberId, VIEW_ACCESS) - .then(albumQuery.findById(albumId)); + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, memberId, VIEW_ACCESS); } @Transactional diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java index 4e9e610..9c9d8ea 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java @@ -1,5 +1,7 @@ package kr.mafoo.photo.service; +import static kr.mafoo.photo.domain.enums.ShareStatus.REJECTED; + import kr.mafoo.photo.domain.SharedMemberEntity; import kr.mafoo.photo.exception.SharedMemberDuplicatedException; import kr.mafoo.photo.exception.SharedMemberNotFoundException; @@ -20,6 +22,11 @@ public Flux findAllByAlbumId(String albumId) { .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); } + public Flux findAllByMemberIdWhereStatusNotRejected(String memberId) { + return sharedMemberRepository.findAllByMemberIdAndShareStatusNot(memberId, REJECTED) + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); + } + public Mono findBySharedMemberId(String sharedMemberId) { return sharedMemberRepository.findById(sharedMemberId) .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/dto/AlbumDto.java b/photo-service/src/main/java/kr/mafoo/photo/service/dto/AlbumDto.java new file mode 100644 index 0000000..6f77a42 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/dto/AlbumDto.java @@ -0,0 +1,51 @@ +package kr.mafoo.photo.service.dto; + +import java.time.LocalDateTime; +import kr.mafoo.photo.domain.AlbumEntity; +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.AlbumType; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; + +public record AlbumDto( + String albumId, + String name, + AlbumType type, + Integer photoCount, + ShareStatus shareStatus, + PermissionLevel permissionLevel, + String ownerProfileImageUrl, + LocalDateTime createdAt +) { + public static AlbumDto fromOwnedAlbum( + AlbumEntity albumEntity + ) { + return new AlbumDto( + albumEntity.getAlbumId(), + albumEntity.getName(), + albumEntity.getType(), + albumEntity.getPhotoCount(), + null, + null, + null, + albumEntity.getCreatedAt() + ); + } + + public static AlbumDto fromSharedAlbum( + AlbumEntity albumEntity, + SharedMemberEntity sharedMemberEntity, + MemberDto memberDto + ) { + return new AlbumDto( + albumEntity.getAlbumId(), + albumEntity.getName(), + albumEntity.getType(), + albumEntity.getPhotoCount(), + sharedMemberEntity.getShareStatus(), + sharedMemberEntity.getPermissionLevel(), + memberDto.profileImageUrl(), + sharedMemberEntity.getCreatedAt() + ); + } +}