Skip to content

Commit

Permalink
Merge pull request #77 from YAPP-Github/feature/MAFOO-180
Browse files Browse the repository at this point in the history
[MAFOO-180] feat: 공유 앨범 상세 조회 API를 구현했어요
  • Loading branch information
gmkim20713 authored Nov 23, 2024
2 parents 153a726 + 73e26a6 commit 7bdf93a
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 48 deletions.
35 changes: 35 additions & 0 deletions photo-service/src/main/java/kr/mafoo/photo/api/SharedAlbumApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package kr.mafoo.photo.api;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import kr.mafoo.photo.annotation.RequestMemberId;
import kr.mafoo.photo.annotation.ULID;
import kr.mafoo.photo.controller.dto.response.SharedAlbumResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import reactor.core.publisher.Mono;

@Validated
@Tag(name = "공유 앨범 관련 API", description = "공유 앨범 상세 조회 API")
@RequestMapping("/v1/shared-albums")
public interface SharedAlbumApi {
@Operation(summary = "공유 앨범 상세 조회", description = "공유 앨범의 상세 정보를 조회합니다.")
@GetMapping("/{albumId}")
Mono<SharedAlbumResponse> getSharedAlbumOwnerAndMemberList(
@RequestMemberId
String memberId,

@ULID
@Parameter(description = "앨범 ID", example = "test_album_id")
@PathVariable
String albumId,

// Authorization Header를 받아올 목적
ServerHttpRequest serverHttpRequest
);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package kr.mafoo.photo.controller;

import kr.mafoo.photo.api.SharedAlbumApi;
import kr.mafoo.photo.controller.dto.response.SharedAlbumResponse;
import kr.mafoo.photo.service.SharedAlbumService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RequiredArgsConstructor
@RestController
public class SharedAlbumController implements SharedAlbumApi {

private final SharedAlbumService sharedAlbumService;

@Override
public Mono<SharedAlbumResponse> getSharedAlbumOwnerAndMemberList(
String memberId,
String albumId,
ServerHttpRequest serverHttpRequest
) {
String authorizationToken = serverHttpRequest.getHeaders().getFirst("Authorization");

return sharedAlbumService.findSharedAlbumOwnerAndMemberList(albumId, memberId, authorizationToken)
.flatMap(SharedAlbumResponse::fromDto);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package kr.mafoo.photo.controller.dto.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import kr.mafoo.photo.domain.enums.AlbumType;
import kr.mafoo.photo.domain.enums.PermissionLevel;
import kr.mafoo.photo.domain.enums.ShareStatus;
Expand All @@ -26,8 +28,21 @@ public record AlbumDetailResponse(
@Schema(description = "공유 받은 앨범 권한", example = "null")
PermissionLevel permissionLevel,

@Schema(description = "공유 받은 앨범 소유자 ID", example = "test_member_id")
String ownerMemberId,

@Schema(description = "공유 받은 앨범 소유자 이름", example = "시금치파슷하")
String ownerName,

@Schema(description = "공유 받은 앨범 소유자 프로필 사진 URL", example = "null")
String ownerProfileImageUrl
String ownerProfileImageUrl,

@Schema(description = "공유 받은 앨범 소유자 식별 번호", example = "0000")
String ownerSerialNumber,

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
@Schema(description = "생성 시간", example = "2021-08-01 00:00:00")
LocalDateTime createdAt
) {
public static AlbumDetailResponse fromDto(
AlbumDto dto
Expand All @@ -39,7 +54,11 @@ public static AlbumDetailResponse fromDto(
dto.photoCount().toString(),
dto.shareStatus(),
dto.permissionLevel(),
dto.ownerProfileImageUrl()
dto.ownerMemberId(),
dto.ownerName(),
dto.ownerProfileImageUrl(),
dto.ownerSerialNumber(),
dto.createdAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package kr.mafoo.photo.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import kr.mafoo.photo.domain.enums.AlbumType;
import kr.mafoo.photo.service.dto.SharedAlbumDto;
import reactor.core.publisher.Mono;

@Schema(description = "공유 앨범 응답")
public record SharedAlbumResponse(
@Schema(description = "앨범 ID", example = "test_album_id")
String albumId,

@Schema(description = "앨범 이름", example = "야뿌들")
String name,

@Schema(description = "앨범 종류", example = "HEART")
AlbumType type,

@Schema(description = "공유 앨범 소유자 ID", example = "test_member_id")
String ownerMemberId,

@Schema(description = "공유 앨범 소유자 이름", example = "시금치파슷하")
String ownerName,

@Schema(description = "공유 앨범 소유자 프로필 이미지 URL", example = "https://mafoo.kr/profile.jpg")
String ownerProfileImageUrl,

@Schema(description = "공유 앨범 소유자 식별 번호", example = "0000")
String ownerSerialNumber,

@Schema(description = "공유 앨범 사용자 정보 목록")
List<SharedMemberDetailResponse> sharedMembers
) {
public static Mono<SharedAlbumResponse> fromDto(
SharedAlbumDto dto
) {
return dto.sharedMemberDtoFlux()
.map(SharedMemberDetailResponse::fromDto)
.collectList()
.map(sharedMemberList -> new SharedAlbumResponse(
dto.albumId(),
dto.name(),
dto.type(),
dto.ownerMemberId(),
dto.ownerName(),
dto.ownerProfileImageUrl(),
dto.ownerSerialNumber(),
sharedMemberList
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import io.swagger.v3.oas.annotations.media.Schema;
import kr.mafoo.photo.domain.enums.PermissionLevel;
import kr.mafoo.photo.domain.enums.ShareStatus;
import kr.mafoo.photo.service.dto.SharedMemberDetailDto;
import kr.mafoo.photo.service.dto.SharedMemberDto;

@Schema(description = "공유 사용자 응답")
@Schema(description = "사용자 응답")
public record SharedMemberDetailResponse(
@Schema(description = "공유 사용자 ID", example = "test_shared_member_id")
String sharedMemberId,
Expand All @@ -16,29 +16,29 @@ public record SharedMemberDetailResponse(
@Schema(description = "권한 단계", example = "FULL_ACCESS")
PermissionLevel permissionLevel,

@Schema(description = "공유 대상 앨범 ID", example = "test_album_id")
String albumId,

@Schema(description = "공유 대상 사용자 ID", example = "test_member_id")
String memberId,

@Schema(description = "공유 대상 사용자 프로필 사진 URL", example = "test_member_profile_url")
@Schema(description = "사용자 이름", example = "시금치파슷하")
String name,

@Schema(description = "프로필 이미지 URL", example = "https://mafoo.kr/profile.jpg")
String profileImageUrl,

@Schema(description = "공유 대상 사용자 이름", example = "test_member_name")
String memberName
@Schema(description = "식별 번호", example = "0000")
String serialNumber
) {
public static SharedMemberDetailResponse fromDto(
SharedMemberDetailDto dto
SharedMemberDto dto
) {
return new SharedMemberDetailResponse(
dto.sharedMemberId(),
dto.shareStatus(),
dto.permissionLevel(),
dto.albumId(),
dto.memberId(),
dto.profileImageUrl(),
dto.memberName()
dto.name(),
dto.serialNumber()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public record SharedMemberResponse(
@Schema(description = "공유 대상 앨범 ID", example = "test_album_id")
String albumId,

@Schema(description = "공유 대상 사용자 ID", example = "test_album_id")
@Schema(description = "공유 대상 사용자 ID", example = "test_member_id")
String memberId
) {
public static SharedMemberResponse fromEntity(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package kr.mafoo.photo.domain.enums;

public enum ShareStatus {
PENDING,
ACCEPTED,
PENDING,
REJECTED
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@Repository
public interface SharedMemberRepository extends R2dbcRepository<SharedMemberEntity, String> {
Flux<SharedMemberEntity> findAllByAlbumId(String albumId);
Flux<SharedMemberEntity> findAllByAlbumIdAndShareStatusNot(String albumId, ShareStatus status);
Flux<SharedMemberEntity> findAllByMemberIdAndShareStatusNot(String memberId, ShareStatus status);
Mono<SharedMemberEntity> findByAlbumIdAndMemberId(String albumId, String memberId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package kr.mafoo.photo.service;

import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS;

import java.util.Comparator;
import kr.mafoo.photo.service.dto.SharedAlbumDto;
import kr.mafoo.photo.service.dto.SharedMemberDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RequiredArgsConstructor
@Service
public class SharedAlbumService {

private final SharedMemberQuery sharedMemberQuery;

private final AlbumPermissionVerifier albumPermissionVerifier;
private final MemberService memberService;

@Transactional(readOnly = true)
public Mono<SharedAlbumDto> findSharedAlbumOwnerAndMemberList(String albumId, String requestMemberId, String token) {
return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, VIEW_ACCESS)
.flatMap(album -> memberService.getMemberInfoById(album.getOwnerMemberId(), token)
.flatMap(ownerMember -> Mono.just(SharedAlbumDto.fromSharedAlbum(
album,
ownerMember,
findSharedAlbumMemberDetail(albumId, token)
)))
);
}

private Flux<SharedMemberDto> findSharedAlbumMemberDetail(String albumId, String token) {
return sharedMemberQuery.findAllByAlbumIdWhereStatusNotRejected(albumId)
.concatMap(sharedMember -> memberService.getMemberInfoById(sharedMember.getMemberId(), token)
.flatMap(memberInfo -> Mono.just(SharedMemberDto.fromSharedMember(sharedMember, memberInfo)))
).sort(Comparator.comparing(SharedMemberDto::shareStatus));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public class SharedMemberQuery {

private final SharedMemberRepository sharedMemberRepository;

public Flux<SharedMemberEntity> findAllByAlbumId(String albumId) {
return sharedMemberRepository.findAllByAlbumId(albumId)
public Flux<SharedMemberEntity> findAllByAlbumIdWhereStatusNotRejected(String albumId) {
return sharedMemberRepository.findAllByAlbumIdAndShareStatusNot(albumId, REJECTED)
.switchIfEmpty(Mono.error(new SharedMemberNotFoundException()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ public record AlbumDto(
Integer photoCount,
ShareStatus shareStatus,
PermissionLevel permissionLevel,
String ownerMemberId,
String ownerName,
String ownerProfileImageUrl,
String ownerSerialNumber,
LocalDateTime createdAt
) {
public static AlbumDto fromOwnedAlbum(
Expand All @@ -28,6 +31,9 @@ public static AlbumDto fromOwnedAlbum(
null,
null,
null,
null,
null,
null,
albumEntity.getCreatedAt()
);
}
Expand All @@ -44,7 +50,10 @@ public static AlbumDto fromSharedAlbum(
albumEntity.getPhotoCount(),
sharedMemberEntity.getShareStatus(),
sharedMemberEntity.getPermissionLevel(),
memberDto.memberId(),
memberDto.name(),
memberDto.profileImageUrl(),
memberDto.serialNumber(),
sharedMemberEntity.getCreatedAt()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package kr.mafoo.photo.service.dto;

import kr.mafoo.photo.domain.AlbumEntity;
import kr.mafoo.photo.domain.enums.AlbumType;
import reactor.core.publisher.Flux;

public record SharedAlbumDto(
String albumId,
String name,
AlbumType type,
String ownerMemberId,
String ownerName,
String ownerProfileImageUrl,
String ownerSerialNumber,
Flux<SharedMemberDto> sharedMemberDtoFlux
) {
public static SharedAlbumDto fromSharedAlbum(
AlbumEntity albumEntity,
MemberDto ownerMemberDto,
Flux<SharedMemberDto> sharedMemberDtoFlux
) {
return new SharedAlbumDto(
albumEntity.getAlbumId(),
albumEntity.getName(),
albumEntity.getType(),
ownerMemberDto.memberId(),
ownerMemberDto.name(),
ownerMemberDto.profileImageUrl(),
ownerMemberDto.serialNumber(),
sharedMemberDtoFlux
);
}
}

This file was deleted.

Loading

0 comments on commit 7bdf93a

Please sign in to comment.