From 9e9175c74c2c16613074f1a07252a6db2a86da56 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sat, 24 Aug 2024 22:30:24 +0900 Subject: [PATCH 01/29] feat: create permission entity * feat: create db migration v8 --- .../mafoo/photo/domain/PermissionEntity.java | 71 +++++++++++++++++++ .../kr/mafoo/photo/domain/PermissionType.java | 9 +++ .../repository/PermissionRepository.java | 7 ++ .../migration/V8__createPermissionTable.sql | 10 +++ 4 files changed, 97 insertions(+) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java create mode 100644 photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java new file mode 100644 index 00000000..cb3bcc52 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java @@ -0,0 +1,71 @@ +package kr.mafoo.photo.domain; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; + +import java.time.LocalDateTime; + +@Getter +@NoArgsConstructor +@Table("permission") +public class PermissionEntity implements Persistable { + @Id + @Column("id") + private String permissionId; + + @Column("type") + private PermissionType type; + + @Column("member_id") + private String memberId; + + @Column("album_id") + private String albumId; + + @CreatedDate + @Column("created_at") + private LocalDateTime createdAt; + + @LastModifiedDate + @Column("updated_at") + private LocalDateTime updatedAt; + + @Transient + private boolean isNew = false; + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + PermissionEntity that = (PermissionEntity) obj; + return permissionId.equals(that.permissionId); + } + + @Override + public int hashCode() { + return permissionId.hashCode(); + } + + @Override + public String getId() { + return permissionId; + } + + public static PermissionEntity newPermission(String permissionId, PermissionType type, String memberId, String albumId) { + PermissionEntity permission = new PermissionEntity(); + permission.permissionId = permissionId; + permission.type = type; + permission.memberId = memberId; + permission.albumId = albumId; + permission.isNew = true; + return permission; + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java new file mode 100644 index 00000000..b808daa1 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java @@ -0,0 +1,9 @@ +package kr.mafoo.photo.domain; + +public enum PermissionType { + FULL_ACCESS, + CAN_DOWNLOAD, + VIEW_ONLY, + ; +} + diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java new file mode 100644 index 00000000..80c05b6c --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.repository; + +import kr.mafoo.photo.domain.PermissionEntity; +import org.springframework.data.r2dbc.repository.R2dbcRepository; + +public interface PermissionRepository extends R2dbcRepository { +} \ No newline at end of file diff --git a/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql b/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql new file mode 100644 index 00000000..1dbcc421 --- /dev/null +++ b/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql @@ -0,0 +1,10 @@ +CREATE TABLE permission( + `id` CHAR(26) PRIMARY KEY NOT NULL COMMENT '권한아이디', + `type` VARCHAR(255) NOT NULL COMMENT '권한종류', + `member_id` CHAR(26) NOT NULL COMMENT '권한대상사용자아이디', + `album_id` CHAR(26) NULL COMMENT '권한대상앨범아이디', + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX `permission_idx1` (`member_id`), + INDEX `permission_idx2` (`album_id`) +); From e17b2e562da22a8b07aa2c5ea47e9b25e442370a Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sat, 24 Aug 2024 22:33:08 +0900 Subject: [PATCH 02/29] feat: create permission related domain exception * feat: create permission not found exception * feat: create cannot make permission myself exception --- .../exception/CannotMakePermissionMyselfException.java | 7 +++++++ .../src/main/java/kr/mafoo/photo/exception/ErrorCode.java | 3 +++ .../mafoo/photo/exception/PermissionNotFoundException.java | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java new file mode 100644 index 00000000..8e8d31c4 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class CannotMakePermissionMyselfException extends DomainException { + public CannotMakePermissionMyselfException() { + super(ErrorCode.CANNOT_MAKE_PERMISSION_MYSELF); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java index 97f350c5..7cadbdea 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java @@ -18,6 +18,9 @@ public enum ErrorCode { PHOTO_DISPLAY_INDEX_IS_SAME("PE0004", "옮기려는 대상 사진 인덱스가 같습니다"), PHOTO_DISPLAY_INDEX_NOT_VALID("PE0005", "옮기려는 대상 사진 인덱스가 유효하지 않습니다"), + PERMISSION_NOT_FOUND("PME0001", "권한을 찾을 수 없습니다"), + CANNOT_MAKE_PERMISSION_MYSELF("PM0002", "자기 자신의 권한을 생성할 수 없습니다"), + ; private final String code; private final String message; diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java new file mode 100644 index 00000000..a2a0bb9a --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class PermissionNotFoundException extends DomainException { + public PermissionNotFoundException() { + super(ErrorCode.PERMISSION_NOT_FOUND); + } +} From bd63448ce3619caa0e83827eb2557de7f25031fd Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sat, 24 Aug 2024 22:35:20 +0900 Subject: [PATCH 03/29] feat: implement permission related logics * feat: implement createNewPermissionBulk * feat: implement findAllByAlbumId * feat: implement deletePermissionById * feat: implement updatePermissionType --- .../dto/request/PermissionCreateRequest.java | 19 ++++ .../mafoo/photo/domain/PermissionEntity.java | 5 + .../repository/PermissionRepository.java | 2 + .../photo/service/PermissionService.java | 105 ++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java new file mode 100644 index 00000000..92eaa56b --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java @@ -0,0 +1,19 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.MatchEnum; +import kr.mafoo.photo.annotation.ULID; +import kr.mafoo.photo.domain.PermissionType; + +@Schema(description = "권한 n건 생성 요청") +public record PermissionCreateRequest( + + @ULID + @Schema(description = "권한 대상 사용자 아이디", example = "test_member_id") + String memberId, + + @MatchEnum(enumClass = PermissionType.class) + @Schema(description = "권한 종류", example = "FULL_ACCESS") + String type +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java index cb3bcc52..0393c5b9 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java @@ -59,6 +59,11 @@ public String getId() { return permissionId; } + public PermissionEntity updateType(String type) { + this.type = PermissionType.valueOf(type); + return this; + } + public static PermissionEntity newPermission(String permissionId, PermissionType type, String memberId, String albumId) { PermissionEntity permission = new PermissionEntity(); permission.permissionId = permissionId; diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java index 80c05b6c..fb92f564 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java @@ -2,6 +2,8 @@ import kr.mafoo.photo.domain.PermissionEntity; import org.springframework.data.r2dbc.repository.R2dbcRepository; +import reactor.core.publisher.Flux; public interface PermissionRepository extends R2dbcRepository { + Flux findAllByAlbumId(String albumId); } \ No newline at end of file diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java b/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java new file mode 100644 index 00000000..110088a5 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java @@ -0,0 +1,105 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.controller.dto.request.PermissionCreateRequest; +import kr.mafoo.photo.domain.PermissionEntity; +import kr.mafoo.photo.domain.PermissionType; +import kr.mafoo.photo.exception.AlbumNotFoundException; +import kr.mafoo.photo.exception.CannotMakePermissionMyselfException; +import kr.mafoo.photo.exception.PermissionNotFoundException; +import kr.mafoo.photo.repository.AlbumRepository; +import kr.mafoo.photo.repository.PermissionRepository; +import kr.mafoo.photo.util.IdGenerator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +@Service +public class PermissionService { + private final AlbumRepository albumRepository; + private final PermissionRepository permissionRepository; + + @Transactional + public Flux createNewPermissionBulk(List permissions, String albumId, String requestMemberId) { + return albumRepository + .findById(albumId) + .switchIfEmpty(Mono.error(new PermissionNotFoundException())) + .flatMapMany(albumEntity -> { + if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { + // 내 앨범이 아니면 그냥 없는 앨범 처리 + return Mono.error(new AlbumNotFoundException()); + } else { + return Flux.fromIterable(permissions) + .flatMap(permission -> + this.createNewPermission(albumId, permission.type(), permission.memberId(), requestMemberId) + ); + } + }); + } + + private Mono createNewPermission(String albumId, String permissionType, String permissionMemberId, String requestMemberId) { + if (permissionMemberId.equals(requestMemberId)) { + return Mono.error(new CannotMakePermissionMyselfException()); + } + + return permissionRepository.save(PermissionEntity.newPermission(IdGenerator.generate(), PermissionType.valueOf(permissionType), permissionMemberId, albumId)); + } + + @Transactional(readOnly = true) + public Flux findAllByAlbumId(String albumId, String requestMemberId) { + return albumRepository + .findById(albumId) + .switchIfEmpty(Mono.error(new PermissionNotFoundException())) + .flatMapMany(albumEntity -> { + if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { + // 내 앨범이 아니면 그냥 없는 앨범 처리 + return Mono.error(new AlbumNotFoundException()); + } else { + return permissionRepository.findAllByAlbumId(albumId); + } + }); + } + + @Transactional + public Mono deletePermissionById(String permissionId, String requestMemberId) { + return permissionRepository + .findById(permissionId) + .switchIfEmpty(Mono.error(new PermissionNotFoundException())) + .flatMap(permissionEntity -> albumRepository + .findById(permissionEntity.getAlbumId()) + .flatMap(albumEntity -> { + if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { + return Mono.error(new PermissionNotFoundException()); + } + + return permissionRepository.deleteById(permissionId); + }) + ); + + } + + @Transactional + public Mono updatePermissionType(String permissionId, String permissionType, String requestMemberId) { + return permissionRepository + .findById(permissionId) + .switchIfEmpty(Mono.error(new PermissionNotFoundException())) + .flatMap(permissionEntity -> albumRepository + .findById(permissionEntity.getAlbumId()) + .switchIfEmpty(Mono.error(new AlbumNotFoundException())) + .flatMap(albumEntity -> { + if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { + return Mono.error(new PermissionNotFoundException()); + } + + return permissionRepository.save(permissionEntity.updateType(permissionType)); + }) + ); + } + +} From 5cf0c932df2cac186f7abe24e280c90d463bab8f Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sat, 24 Aug 2024 22:36:08 +0900 Subject: [PATCH 04/29] feat: implement permission related apis --- .../kr/mafoo/photo/api/PermissionApi.java | 71 +++++++++++++++++++ .../controller/PermissionController.java | 57 +++++++++++++++ .../request/PermissionBulkCreateRequest.java | 17 +++++ .../request/PermissionTypeUpdateRequest.java | 13 ++++ .../dto/response/PermissionResponse.java | 31 ++++++++ 5 files changed, 189 insertions(+) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java new file mode 100644 index 00000000..327e2ca5 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java @@ -0,0 +1,71 @@ +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 jakarta.validation.Valid; +import kr.mafoo.photo.annotation.RequestMemberId; +import kr.mafoo.photo.annotation.ULID; +import kr.mafoo.photo.controller.dto.request.PermissionBulkCreateRequest; +import kr.mafoo.photo.controller.dto.request.PermissionTypeUpdateRequest; +import kr.mafoo.photo.controller.dto.response.PermissionResponse; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Validated +@Tag(name = "권한 관련 API", description = "권한 조회, 생성, 수정, 삭제 등 API") +@RequestMapping("/v1/permissions") +public interface PermissionApi { + @Operation(summary = "권한 조회", description = "권한 목록을 조회합니다.") + @GetMapping + Flux getPermissions( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "앨범 ID", example = "test_album_id") + @RequestParam + String albumId + ); + + @Operation(summary = "권한 n건 생성", description = "권한 여러 개를 생성합니다.") + @PostMapping("/bulk") + Flux createPermissionBulk( + @RequestMemberId + String memberId, + + @Valid + @RequestBody + PermissionBulkCreateRequest request + ); + + @Operation(summary = "권한 종류 수정", description = "권한의 종류를 수정합니다.") + @PatchMapping("/{permissionId}/type") + Mono updatePermissionType( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "권한 ID", example = "test_permission_id") + @PathVariable + String permissionId, + + @Valid + @RequestBody + PermissionTypeUpdateRequest request + ); + + @Operation(summary = "권한 삭제", description = "권한을 삭제합니다.") + @DeleteMapping("{permissionId}") + Mono deletePermission( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "권한 ID", example = "test_permission_id") + @PathVariable + String permissionId + ); +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java new file mode 100644 index 00000000..a185b63a --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java @@ -0,0 +1,57 @@ +package kr.mafoo.photo.controller; + +import kr.mafoo.photo.api.PermissionApi; +import kr.mafoo.photo.controller.dto.request.*; +import kr.mafoo.photo.controller.dto.response.PermissionResponse; +import kr.mafoo.photo.service.PermissionService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@RestController +public class PermissionController implements PermissionApi { + + private final PermissionService permissionService; + + @Override + public Flux getPermissions( + String memberId, + String albumId + ){ + return permissionService + .findAllByAlbumId(albumId, memberId) + .map(PermissionResponse::fromEntity); + } + + @Override + public Flux createPermissionBulk( + String memberId, + PermissionBulkCreateRequest request + ){ + return permissionService + .createNewPermissionBulk(request.permissions(), request.albumId(), memberId) + .map(PermissionResponse::fromEntity); + } + + @Override + public Mono updatePermissionType( + String memberId, + String permissionId, + PermissionTypeUpdateRequest request + ){ + return permissionService + .updatePermissionType(permissionId, request.type(), memberId) + .map(PermissionResponse::fromEntity); + } + + @Override + public Mono deletePermission( + String memberId, + String permissionId + ){ + return permissionService + .deletePermissionById(permissionId, memberId); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java new file mode 100644 index 00000000..c0cc3bce --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java @@ -0,0 +1,17 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.ULID; + +import java.util.List; + +@Schema(description = "권한 n건 생성 요청") +public record PermissionBulkCreateRequest( + + List permissions, + + @ULID + @Schema(description = "앨범 ID", example = "test_album_id") + String albumId +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java new file mode 100644 index 00000000..5bf905b0 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java @@ -0,0 +1,13 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.MatchEnum; +import kr.mafoo.photo.domain.PermissionType; + +@Schema(description = "권한 종류 수정 요청") +public record PermissionTypeUpdateRequest( + @MatchEnum(enumClass = PermissionType.class) + @Schema(description = "권한 종류", example = "FULL_ACCESS") + String type +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java new file mode 100644 index 00000000..0d7da787 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java @@ -0,0 +1,31 @@ +package kr.mafoo.photo.controller.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.domain.PermissionEntity; +import kr.mafoo.photo.domain.PermissionType; + +@Schema(description = "권한 응답") +public record PermissionResponse( + @Schema(description = "권한 ID", example = "test_permission_id") + String permissionId, + + @Schema(description = "권한 종류", example = "FULL_ACCESS") + PermissionType type, + + @Schema(description = "권한 대상 사용자", example = "test_member_id") + String memberId, + + @Schema(description = "권한 대상 앨범", example = "test_album_id") + String albumId +) { + public static PermissionResponse fromEntity( + PermissionEntity entity + ) { + return new PermissionResponse( + entity.getPermissionId(), + entity.getType(), + entity.getMemberId(), + entity.getAlbumId() + ); + } +} From 009f4615feb354a1c0343e90ed17954ada172069 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sat, 24 Aug 2024 22:36:45 +0900 Subject: [PATCH 05/29] docs: fix swagger schema tag --- .../controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java index 258c37c3..99cb7084 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import kr.mafoo.photo.annotation.ULID; -@Schema(description = "사진 앨범 수정 요청") +@Schema(description = "사진 n건 앨범 수정 요청") public record PhotoBulkUpdateAlbumIdRequest( @ArraySchema( From 7def256cb1f010a93033a56ef4ea2168ff2a6cfe Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sun, 25 Aug 2024 06:25:02 +0900 Subject: [PATCH 06/29] fix: fix db migration v8 --- .../main/resources/db/migration/V8__createPermissionTable.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql b/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql index 1dbcc421..31d69427 100644 --- a/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql +++ b/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql @@ -2,7 +2,7 @@ CREATE TABLE permission( `id` CHAR(26) PRIMARY KEY NOT NULL COMMENT '권한아이디', `type` VARCHAR(255) NOT NULL COMMENT '권한종류', `member_id` CHAR(26) NOT NULL COMMENT '권한대상사용자아이디', - `album_id` CHAR(26) NULL COMMENT '권한대상앨범아이디', + `album_id` CHAR(26) NOT NULL COMMENT '권한대상앨범아이디', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX `permission_idx1` (`member_id`), From 44c63c6132fd8785e02ee9c1bf0ae1085a520b43 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sun, 25 Aug 2024 06:26:04 +0900 Subject: [PATCH 07/29] feat: create permission related exceptions * feat: create PermissionAlreadyExistsException * feat: create PermissionNotAllowedException --- .../src/main/java/kr/mafoo/photo/exception/ErrorCode.java | 2 ++ .../photo/exception/PermissionAlreadyExistsException.java | 7 +++++++ .../photo/exception/PermissionNotAllowedException.java | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java index 7cadbdea..93b378fb 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java @@ -20,6 +20,8 @@ public enum ErrorCode { PERMISSION_NOT_FOUND("PME0001", "권한을 찾을 수 없습니다"), CANNOT_MAKE_PERMISSION_MYSELF("PM0002", "자기 자신의 권한을 생성할 수 없습니다"), + PERMISSION_NOT_ALLOWED("PE0003", "권한이 허용되지 않았습니다"), + PERMISSION_ALREADY_EXISTS("PE0004", "동일한 권한이 이미 존재합니다") ; private final String code; diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java new file mode 100644 index 00000000..be0c691c --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class PermissionAlreadyExistsException extends DomainException { + public PermissionAlreadyExistsException() { + super(ErrorCode.PERMISSION_ALREADY_EXISTS); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java new file mode 100644 index 00000000..40229f21 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class PermissionNotAllowedException extends DomainException { + public PermissionNotAllowedException() { + super(ErrorCode.PERMISSION_NOT_ALLOWED); + } +} From c792a0b6087935e526ae18eed986fde1b9d21be6 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Sun, 25 Aug 2024 06:27:27 +0900 Subject: [PATCH 08/29] feat: add permission checking logic for photo related apis --- .../photo/controller/AlbumController.java | 12 ++- .../repository/PermissionRepository.java | 5 + .../kr/mafoo/photo/service/AlbumService.java | 54 ++++++++--- .../photo/service/PermissionService.java | 18 +++- .../kr/mafoo/photo/service/PhotoService.java | 97 ++++++++----------- 5 files changed, 111 insertions(+), 75 deletions(-) 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 8e7f2e10..6f746e31 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 @@ -48,7 +48,11 @@ public Mono createAlbum( } @Override - public Mono updateAlbum(String memberId, String albumId, AlbumUpdateRequest request) { + public Mono updateAlbum( + String memberId, + String albumId, + AlbumUpdateRequest request + ) { AlbumType albumType = AlbumType.valueOf(request.type()); return albumService .updateAlbumName(albumId, request.name(), memberId) @@ -57,7 +61,11 @@ public Mono updateAlbum(String memberId, String albumId, AlbumUpd } @Override - public Mono updateAlbumDisplayIndex(String memberId, String albumId, AlbumUpdateDisplayIndexRequest request) { + public Mono updateAlbumDisplayIndex( + String memberId, + String albumId, + AlbumUpdateDisplayIndexRequest request + ) { return albumService .moveAlbumDisplayIndex(albumId, memberId, request.newDisplayIndex()) .map(AlbumResponse::fromEntity); diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java index fb92f564..00dd3281 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java @@ -1,9 +1,14 @@ package kr.mafoo.photo.repository; import kr.mafoo.photo.domain.PermissionEntity; +import kr.mafoo.photo.domain.PermissionType; import org.springframework.data.r2dbc.repository.R2dbcRepository; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; public interface PermissionRepository extends R2dbcRepository { Flux findAllByAlbumId(String albumId); + + Mono existsByAlbumIdAndMemberId(String albumId, String memberId); + Mono existsByAlbumIdAndMemberIdAndType(String albumId, String memberId, PermissionType type); } \ No newline at end of file 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 1b801897..9036049b 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 @@ -4,6 +4,7 @@ import kr.mafoo.photo.domain.AlbumType; import kr.mafoo.photo.exception.AlbumIndexIsSameException; import kr.mafoo.photo.exception.AlbumNotFoundException; +import kr.mafoo.photo.exception.PermissionNotAllowedException; import kr.mafoo.photo.repository.AlbumRepository; import kr.mafoo.photo.util.IdGenerator; import lombok.RequiredArgsConstructor; @@ -12,10 +13,13 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import static kr.mafoo.photo.domain.PermissionType.FULL_ACCESS; + @RequiredArgsConstructor @Service public class AlbumService { private final AlbumRepository albumRepository; + private final PermissionService permissionService; @Transactional public Mono createNewAlbum(String ownerMemberId, String albumName, AlbumType albumType) { @@ -114,22 +118,15 @@ public Mono updateAlbumType(String albumId, AlbumType albumType, St } @Transactional - public Mono increaseAlbumPhotoCount(String albumId, String requestMemberId) { + public Mono increaseAlbumPhotoCount(String albumId) { 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(); - } - }); + .flatMap(albumEntity -> albumRepository.save(albumEntity.increasePhotoCount()).then()); } @Transactional - public Mono decreaseAlbumPhotoCount(String albumId, String requestMemberId) { + public Mono decreaseAlbumPhotoCount(String albumId) { if (albumId == null) { return Mono.empty(); @@ -137,13 +134,44 @@ public Mono decreaseAlbumPhotoCount(String albumId, String requestMemberId return albumRepository .findById(albumId) + .switchIfEmpty(Mono.error(new AlbumNotFoundException())) + .flatMap(albumEntity -> albumRepository.save(albumEntity.decreasePhotoCount()).then()); + } + + public Mono checkAlbumFullAccessPermission(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()); + return permissionService.checkPermissionExistsByType(albumId, requestMemberId, FULL_ACCESS) + .flatMap(isPermitted -> { + if (!isPermitted) { + return Mono.error(new PermissionNotAllowedException()); + } else { + return Mono.just(albumEntity); + } + }); } else { - return albumRepository.save(albumEntity.decreasePhotoCount()).then(); + return Mono.just(albumEntity); + } + }); + } + + public Mono checkAlbumReadPermission(String albumId, String requestMemberId) { + return albumRepository.findById(albumId) + .switchIfEmpty(Mono.error(new AlbumNotFoundException())) + .flatMap(albumEntity -> { + if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { + return permissionService.checkPermissionExists(albumId, requestMemberId) + .flatMap(isPermitted -> { + if (!isPermitted) { + return Mono.error(new PermissionNotAllowedException()); + } else { + return Mono.just(albumEntity); + } + }); + } else { + return Mono.just(albumEntity); } }); } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java b/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java index 110088a5..ab0c90ea 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java @@ -5,6 +5,7 @@ import kr.mafoo.photo.domain.PermissionType; import kr.mafoo.photo.exception.AlbumNotFoundException; import kr.mafoo.photo.exception.CannotMakePermissionMyselfException; +import kr.mafoo.photo.exception.PermissionAlreadyExistsException; import kr.mafoo.photo.exception.PermissionNotFoundException; import kr.mafoo.photo.repository.AlbumRepository; import kr.mafoo.photo.repository.PermissionRepository; @@ -48,7 +49,14 @@ private Mono createNewPermission(String albumId, String permis return Mono.error(new CannotMakePermissionMyselfException()); } - return permissionRepository.save(PermissionEntity.newPermission(IdGenerator.generate(), PermissionType.valueOf(permissionType), permissionMemberId, albumId)); + return checkPermissionExists(albumId, permissionMemberId) + .flatMap(permissionExists -> { + if (!permissionExists) { + return permissionRepository.save(PermissionEntity.newPermission(IdGenerator.generate(), PermissionType.valueOf(permissionType), permissionMemberId, albumId)); + } else { + return Mono.error(new PermissionAlreadyExistsException()); + } + }); } @Transactional(readOnly = true) @@ -102,4 +110,12 @@ public Mono updatePermissionType(String permissionId, String p ); } + public Mono checkPermissionExists(String albumId, String requestMemberId) { + return permissionRepository.existsByAlbumIdAndMemberId(albumId, requestMemberId); + } + + public Mono checkPermissionExistsByType(String albumId, String requestMemberId, PermissionType type) { + return permissionRepository.existsByAlbumIdAndMemberIdAndType(albumId, requestMemberId, type); + } + } 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 01ca8d28..3723f57c 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 @@ -1,10 +1,8 @@ package kr.mafoo.photo.service; +import kr.mafoo.photo.domain.AlbumEntity; 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.exception.*; import kr.mafoo.photo.repository.AlbumRepository; import kr.mafoo.photo.repository.PhotoRepository; import kr.mafoo.photo.util.IdGenerator; @@ -38,18 +36,14 @@ public Mono createNewPhoto(String qrUrl, String requestMemberId) { ); } + @Transactional(readOnly = true) public Flux findAllByAlbumId(String albumId, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMapMany(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); - } - }); + return albumService.checkAlbumReadPermission(albumId, requestMemberId) + .flatMapMany(albumEntity -> handleFindAllByAlbumId(albumEntity.getId())); + } + + private Flux handleFindAllByAlbumId(String albumId) { + return photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); } @Transactional @@ -57,16 +51,15 @@ public Mono deletePhotoById(String photoId, String requestMemberId) { return photoRepository .findById(photoId) .switchIfEmpty(Mono.error(new PhotoNotFoundException())) - .flatMap(photoEntity -> { - 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)); - } - }); + .flatMap(photoEntity -> albumService + .checkAlbumFullAccessPermission(photoEntity.getAlbumId(), requestMemberId) + .flatMap(albumEntity -> handleDeletePhotoById(photoEntity))); + } + + private Mono handleDeletePhotoById(PhotoEntity photoEntity) { + return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId()) + .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) + .then(photoRepository.deleteById(photoEntity.getPhotoId())); } @Transactional @@ -84,52 +77,39 @@ public Mono updatePhotoAlbumId(String photoId, String albumId, Stri .switchIfEmpty(Mono.error(new PhotoNotFoundException())) .flatMap(photoEntity -> { - if (!photoEntity.hasOwnerMemberId()) { - photoRepository.save(photoEntity.updateOwnerMemberId(requestMemberId)); - } + if (photoEntity.getAlbumId() == null) { + if (!photoEntity.hasOwnerMemberId()) { + 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) - .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) - .then(albumService.increaseAlbumPhotoCount(albumId, requestMemberId)) - .then(photoRepository.save( - photoEntity - .updateAlbumId(albumId) - .updateDisplayIndex(albumEntity.getPhotoCount()) - )); - } - }); + return albumService.checkAlbumFullAccessPermission(albumId, requestMemberId) + .flatMap(albumEntity -> photoRepository.save(photoEntity.updateAlbumId(albumId))); } + + return albumService.checkAlbumFullAccessPermission(photoEntity.getAlbumId(), requestMemberId) + .flatMap(previousAlbum -> albumService.checkAlbumFullAccessPermission(albumId, requestMemberId) + .flatMap(newAlbum -> handleUpdatePhotoAlbumId(photoEntity, newAlbum))); }); } + private Mono handleUpdatePhotoAlbumId(PhotoEntity photoEntity, AlbumEntity albumEntity) { + return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId()) + .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) + .then(albumService.increaseAlbumPhotoCount(albumEntity.getId())) + .then(photoRepository.save( + photoEntity.updateAlbumId(albumEntity.getId()).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(photoEntity -> albumService.checkAlbumFullAccessPermission(photoEntity.getAlbumId(), requestMemberId) .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()); } @@ -147,7 +127,6 @@ public Mono updatePhotoDisplayIndex(String photoId, Integer newInde .pushDisplayIndexBetween(photoEntity.getAlbumId(), targetIndex, photoEntity.getDisplayIndex() - 1) .then(photoRepository.save(photoEntity.updateDisplayIndex(targetIndex))); } - })); } From 12b2041d671d9ccbd7e6601ec54cee4a4336bef0 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 14 Nov 2024 22:19:15 +0900 Subject: [PATCH 09/29] fix: change db migration ver. for permission table --- ...8__createPermissionTable.sql => V9__createPermissionTable.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename photo-service/src/main/resources/db/migration/{V8__createPermissionTable.sql => V9__createPermissionTable.sql} (100%) diff --git a/photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql b/photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql similarity index 100% rename from photo-service/src/main/resources/db/migration/V8__createPermissionTable.sql rename to photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql From 23b634a168c562071ab7639dae2db3e5774008bf Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 01:40:17 +0900 Subject: [PATCH 10/29] feat: create shared member entity and db migration v.9 --- .../photo/domain/SharedMemberEntity.java | 86 +++++++++++++++++++ .../photo/domain/enums/PermissionLevel.java | 15 ++++ .../mafoo/photo/domain/enums/ShareStatus.java | 8 ++ .../migration/V9__createPermissionTable.sql | 10 --- .../migration/V9__createSharedMemberTable.sql | 11 +++ 5 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/SharedMemberEntity.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/enums/PermissionLevel.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/enums/ShareStatus.java delete mode 100644 photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql create mode 100644 photo-service/src/main/resources/db/migration/V9__createSharedMemberTable.sql diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/SharedMemberEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/SharedMemberEntity.java new file mode 100644 index 00000000..35fc6a00 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/SharedMemberEntity.java @@ -0,0 +1,86 @@ +package kr.mafoo.photo.domain; + +import java.time.LocalDateTime; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; + +@Getter +@NoArgsConstructor +@Table("shared_member") +public class SharedMemberEntity implements Persistable { + @Id + @Column("id") + private String sharedMemberId; + + @Column("share_status") + private ShareStatus shareStatus; + + @Column("permission_level") + private PermissionLevel permissionLevel; + + @Column("member_id") + private String memberId; + + @Column("album_id") + private String albumId; + + @CreatedDate + @Column("created_at") + private LocalDateTime createdAt; + + @LastModifiedDate + @Column("updated_at") + private LocalDateTime updatedAt; + + @Transient + private boolean isNew = false; + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + SharedMemberEntity that = (SharedMemberEntity) obj; + return sharedMemberId.equals(that.sharedMemberId); + } + + @Override + public int hashCode() { + return sharedMemberId.hashCode(); + } + + @Override + public String getId() { + return sharedMemberId; + } + + public SharedMemberEntity updateShareStatus(ShareStatus shareStatus) { + this.shareStatus = shareStatus; + return this; + } + + public SharedMemberEntity updatePermissionLevel(PermissionLevel permissionLevel) { + this.permissionLevel = permissionLevel; + return this; + } + + public static SharedMemberEntity newSharedMember(String sharedMemberId, ShareStatus shareStatus, PermissionLevel permissionLevel, String memberId, String albumId) { + SharedMemberEntity sharedMember = new SharedMemberEntity(); + sharedMember.sharedMemberId = sharedMemberId; + sharedMember.shareStatus = shareStatus; + sharedMember.permissionLevel = permissionLevel; + sharedMember.memberId = memberId; + sharedMember.albumId = albumId; + sharedMember.isNew = true; + return sharedMember; + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/enums/PermissionLevel.java b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/PermissionLevel.java new file mode 100644 index 00000000..7944a315 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/PermissionLevel.java @@ -0,0 +1,15 @@ +package kr.mafoo.photo.domain.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PermissionLevel { + FULL_ACCESS(3), // 전체 권한 + DOWNLOAD_ACCESS(2), // 다운로드 권한 + VIEW_ACCESS(1), // 뷰 권한 + ; + + private final int tier; +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/enums/ShareStatus.java b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/ShareStatus.java new file mode 100644 index 00000000..685ad92e --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/ShareStatus.java @@ -0,0 +1,8 @@ +package kr.mafoo.photo.domain.enums; + +public enum ShareStatus { + PENDING, + ACCEPTED, + REJECTED +} + diff --git a/photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql b/photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql deleted file mode 100644 index 31d69427..00000000 --- a/photo-service/src/main/resources/db/migration/V9__createPermissionTable.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE permission( - `id` CHAR(26) PRIMARY KEY NOT NULL COMMENT '권한아이디', - `type` VARCHAR(255) NOT NULL COMMENT '권한종류', - `member_id` CHAR(26) NOT NULL COMMENT '권한대상사용자아이디', - `album_id` CHAR(26) NOT NULL COMMENT '권한대상앨범아이디', - `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - INDEX `permission_idx1` (`member_id`), - INDEX `permission_idx2` (`album_id`) -); diff --git a/photo-service/src/main/resources/db/migration/V9__createSharedMemberTable.sql b/photo-service/src/main/resources/db/migration/V9__createSharedMemberTable.sql new file mode 100644 index 00000000..6851515e --- /dev/null +++ b/photo-service/src/main/resources/db/migration/V9__createSharedMemberTable.sql @@ -0,0 +1,11 @@ +CREATE TABLE shared_member( + `id` CHAR(26) PRIMARY KEY NOT NULL COMMENT '공유사용자아이디', + `share_status` VARCHAR(255) NOT NULL COMMENT '공유상태', + `permission_level` VARCHAR(255) NOT NULL COMMENT '공유단계', + `member_id` CHAR(26) NOT NULL COMMENT '대상사용자아이디', + `album_id` CHAR(26) NOT NULL COMMENT '대상앨범아이디', + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX `shared_album_member_idx1` (`member_id`), + INDEX `shared_album_member_idx2` (`album_id`) +); From a8ee9314954da21dc33135fc878a776179e054ae Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 01:53:03 +0900 Subject: [PATCH 11/29] refactor: change package for domain related enums --- .../controller/dto/request/AlbumCreateRequest.java | 2 +- .../controller/dto/response/AlbumRawResponse.java | 2 +- .../photo/controller/dto/response/AlbumResponse.java | 2 +- .../photo/controller/dto/response/PhotoResponse.java | 2 +- .../controller/dto/response/PreSignedUrlResponse.java | 2 -- .../main/java/kr/mafoo/photo/domain/AlbumEntity.java | 1 + .../main/java/kr/mafoo/photo/domain/PhotoEntity.java | 1 + .../kr/mafoo/photo/domain/{ => enums}/AlbumType.java | 2 +- .../kr/mafoo/photo/domain/{ => enums}/BrandType.java | 10 ++++------ .../kr/mafoo/photo/repository/AlbumRepository.java | 2 +- .../kr/mafoo/photo/repository/PhotoRepository.java | 2 +- .../java/kr/mafoo/photo/service/AlbumAdminService.java | 2 +- .../main/java/kr/mafoo/photo/service/AlbumService.java | 5 ++++- .../java/kr/mafoo/photo/service/PhotoAdminService.java | 2 +- .../main/java/kr/mafoo/photo/service/PhotoService.java | 7 +++++-- .../main/java/kr/mafoo/photo/service/QrService.java | 2 +- .../main/java/kr/mafoo/photo/service/RecapService.java | 2 ++ 17 files changed, 27 insertions(+), 21 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/domain/{ => enums}/AlbumType.java (74%) rename photo-service/src/main/java/kr/mafoo/photo/domain/{ => enums}/BrandType.java (87%) diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumCreateRequest.java index bf4cf790..f308893e 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumCreateRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumCreateRequest.java @@ -3,7 +3,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import kr.mafoo.photo.annotation.MatchEnum; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import org.hibernate.validator.constraints.Length; @Schema(description = "앨범 생성 요청") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumRawResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumRawResponse.java index 25882123..000cfbea 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumRawResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumRawResponse.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import java.time.LocalDateTime; diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java index 446c64c8..ec92d886 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java @@ -2,7 +2,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; @Schema(description = "앨범 응답") public record AlbumResponse( diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java index 9ac00dbb..71ae531e 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java @@ -1,7 +1,7 @@ package kr.mafoo.photo.controller.dto.response; import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.domain.BrandType; +import kr.mafoo.photo.domain.enums.BrandType; import kr.mafoo.photo.domain.PhotoEntity; @Schema(description = "사진 응답") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PreSignedUrlResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PreSignedUrlResponse.java index bbd24b22..9accefd0 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PreSignedUrlResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PreSignedUrlResponse.java @@ -1,8 +1,6 @@ package kr.mafoo.photo.controller.dto.response; import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.domain.BrandType; -import kr.mafoo.photo.domain.PhotoEntity; @Schema(description = "Pre-signed Url 응답") public record PreSignedUrlResponse( 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 312addf0..5d8842a3 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 @@ -1,5 +1,6 @@ package kr.mafoo.photo.domain; +import kr.mafoo.photo.domain.enums.AlbumType; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; 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 5b446b32..08090a4a 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 @@ -1,5 +1,6 @@ package kr.mafoo.photo.domain; +import kr.mafoo.photo.domain.enums.BrandType; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumType.java b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/AlbumType.java similarity index 74% rename from photo-service/src/main/java/kr/mafoo/photo/domain/AlbumType.java rename to photo-service/src/main/java/kr/mafoo/photo/domain/enums/AlbumType.java index 31f1a91c..d2ecd336 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/AlbumType.java +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/AlbumType.java @@ -1,4 +1,4 @@ -package kr.mafoo.photo.domain; +package kr.mafoo.photo.domain.enums; public enum AlbumType { HEART, diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/BrandType.java b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/BrandType.java similarity index 87% rename from photo-service/src/main/java/kr/mafoo/photo/domain/BrandType.java rename to photo-service/src/main/java/kr/mafoo/photo/domain/enums/BrandType.java index af94b1cb..6c7418e2 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/BrandType.java +++ b/photo-service/src/main/java/kr/mafoo/photo/domain/enums/BrandType.java @@ -1,7 +1,9 @@ -package kr.mafoo.photo.domain; +package kr.mafoo.photo.domain.enums; import java.util.regex.Pattern; +import lombok.RequiredArgsConstructor; +@RequiredArgsConstructor public enum BrandType { LIFE_FOUR_CUTS(Pattern.compile("https://api\\.life4cut\\.net/.*")), PHOTOISM(Pattern.compile("https://qr\\.seobuk\\.kr/.*")), @@ -13,15 +15,11 @@ public enum BrandType { PHOTO_SIGNATURE(Pattern.compile("http://photoqr3\\.kr/.*")), PICDOT(Pattern.compile("https://picdot\\.kr/.*")), MAFOO(Pattern.compile("https://mafoo\\.kr/.*")), - EXTERNAL(Pattern.compile("https://mafoo")) + EXTERNAL(Pattern.compile("https://mafoo")), ; private final Pattern urlPattern; - private BrandType(Pattern urlPattern) { - this.urlPattern = urlPattern; - } - public boolean matches(String qrUrl) { return urlPattern.matcher(qrUrl).matches(); } diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/AlbumRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/AlbumRepository.java index 63420cfa..9d3b7add 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/AlbumRepository.java +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/AlbumRepository.java @@ -1,7 +1,7 @@ package kr.mafoo.photo.repository; import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import org.springframework.data.domain.Pageable; import org.springframework.data.r2dbc.repository.Modifying; import org.springframework.data.r2dbc.repository.Query; diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/PhotoRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/PhotoRepository.java index 127363b2..02b3244d 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/PhotoRepository.java +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/PhotoRepository.java @@ -1,6 +1,6 @@ package kr.mafoo.photo.repository; -import kr.mafoo.photo.domain.BrandType; +import kr.mafoo.photo.domain.enums.BrandType; import kr.mafoo.photo.domain.PhotoEntity; import org.springframework.data.domain.Pageable; import org.springframework.data.r2dbc.repository.Modifying; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumAdminService.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumAdminService.java index c311dd4b..094037d8 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumAdminService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumAdminService.java @@ -2,7 +2,7 @@ import kr.mafoo.photo.controller.dto.response.PageResponse; import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import kr.mafoo.photo.repository.AlbumRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; 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 7f2ee9a5..7e39d596 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 @@ -1,7 +1,10 @@ package kr.mafoo.photo.service; +import static kr.mafoo.photo.domain.enums.PermissionLevel.FULL_ACCESS; +import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; + import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import kr.mafoo.photo.exception.AlbumIndexIsSameException; import kr.mafoo.photo.exception.AlbumNotFoundException; import kr.mafoo.photo.exception.PermissionNotAllowedException; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoAdminService.java b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoAdminService.java index 99ac2937..53d6fefd 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoAdminService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoAdminService.java @@ -1,7 +1,7 @@ package kr.mafoo.photo.service; import kr.mafoo.photo.controller.dto.response.PageResponse; -import kr.mafoo.photo.domain.BrandType; +import kr.mafoo.photo.domain.enums.BrandType; import kr.mafoo.photo.domain.PhotoEntity; import kr.mafoo.photo.repository.PhotoRepository; import lombok.RequiredArgsConstructor; 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 130ddacb..2de40a03 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 @@ -1,7 +1,10 @@ package kr.mafoo.photo.service; -import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.BrandType; +import static kr.mafoo.photo.domain.enums.PermissionLevel.FULL_ACCESS; +import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; + +import kr.mafoo.photo.domain.enums.BrandType; +import kr.mafoo.photo.domain.enums.PermissionLevel; import kr.mafoo.photo.domain.PhotoEntity; import kr.mafoo.photo.exception.PhotoDisplayIndexIsSameException; import kr.mafoo.photo.exception.PhotoDisplayIndexNotValidException; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/QrService.java b/photo-service/src/main/java/kr/mafoo/photo/service/QrService.java index 20235d78..c79d9aec 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/QrService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/QrService.java @@ -1,6 +1,6 @@ package kr.mafoo.photo.service; -import kr.mafoo.photo.domain.BrandType; +import kr.mafoo.photo.domain.enums.BrandType; import kr.mafoo.photo.exception.PhotoBrandNotExistsException; import kr.mafoo.photo.service.dto.FileDto; import kr.mafoo.photo.service.vendors.*; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java b/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java index dd2bb1ec..c83603cc 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java @@ -1,5 +1,7 @@ package kr.mafoo.photo.service; +import static kr.mafoo.photo.domain.enums.PermissionLevel.DOWNLOAD_ACCESS; + import kr.mafoo.photo.domain.PhotoEntity; import kr.mafoo.photo.service.properties.RecapProperties; import kr.mafoo.photo.util.IdGenerator; From 752266513befa80e47d48e84247c72c71cd618b1 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 02:05:36 +0900 Subject: [PATCH 12/29] refactor: refactor package for RecapProperties --- .../src/main/java/kr/mafoo/photo/service/Graphics2dService.java | 2 +- .../main/java/kr/mafoo/photo/service/ObjectStorageService.java | 2 +- .../src/main/java/kr/mafoo/photo/service/RecapService.java | 2 +- .../photo/{service/properties => util}/RecapProperties.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/{service/properties => util}/RecapProperties.java (97%) diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/Graphics2dService.java b/photo-service/src/main/java/kr/mafoo/photo/service/Graphics2dService.java index bf651f40..822a9788 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/Graphics2dService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/Graphics2dService.java @@ -1,6 +1,6 @@ package kr.mafoo.photo.service; -import kr.mafoo.photo.service.properties.RecapProperties; +import kr.mafoo.photo.util.RecapProperties; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/ObjectStorageService.java b/photo-service/src/main/java/kr/mafoo/photo/service/ObjectStorageService.java index 8a77dc3d..f71aa718 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/ObjectStorageService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/ObjectStorageService.java @@ -8,7 +8,7 @@ import com.amazonaws.services.s3.model.PutObjectRequest; import kr.mafoo.photo.exception.PreSignedUrlBannedFileType; import kr.mafoo.photo.exception.PreSignedUrlExceedMaximum; -import kr.mafoo.photo.service.properties.RecapProperties; +import kr.mafoo.photo.util.RecapProperties; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Value; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java b/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java index c83603cc..2ba5142d 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/RecapService.java @@ -3,7 +3,7 @@ import static kr.mafoo.photo.domain.enums.PermissionLevel.DOWNLOAD_ACCESS; import kr.mafoo.photo.domain.PhotoEntity; -import kr.mafoo.photo.service.properties.RecapProperties; +import kr.mafoo.photo.util.RecapProperties; import kr.mafoo.photo.util.IdGenerator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/properties/RecapProperties.java b/photo-service/src/main/java/kr/mafoo/photo/util/RecapProperties.java similarity index 97% rename from photo-service/src/main/java/kr/mafoo/photo/service/properties/RecapProperties.java rename to photo-service/src/main/java/kr/mafoo/photo/util/RecapProperties.java index 1dbc1d66..f0fa138c 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/properties/RecapProperties.java +++ b/photo-service/src/main/java/kr/mafoo/photo/util/RecapProperties.java @@ -1,4 +1,4 @@ -package kr.mafoo.photo.service.properties; +package kr.mafoo.photo.util; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; From 99cf9d416c17db3542afd26ebb91e3e829ce0bb1 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 02:05:46 +0900 Subject: [PATCH 13/29] refactor: refactor package for FileDto --- .../src/main/java/kr/mafoo/photo/service/dto/FileDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/dto/FileDto.java b/photo-service/src/main/java/kr/mafoo/photo/service/dto/FileDto.java index 5dff696c..d33b2501 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/dto/FileDto.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/dto/FileDto.java @@ -1,6 +1,6 @@ package kr.mafoo.photo.service.dto; -import kr.mafoo.photo.domain.BrandType; +import kr.mafoo.photo.domain.enums.BrandType; public record FileDto ( BrandType type, From 34ac642f9a20c3dbbe0cb46532730659b291eb6f Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 02:42:56 +0900 Subject: [PATCH 14/29] feat: add shared member related exceptions --- .../mafoo/photo/exception/AlbumOwnerMismatchException.java | 7 +++++++ .../exception/CannotMakePermissionMyselfException.java | 7 ------- .../photo/exception/PermissionAlreadyExistsException.java | 7 ------- .../photo/exception/PermissionNotAllowedException.java | 7 ------- .../mafoo/photo/exception/PermissionNotFoundException.java | 7 ------- .../exception/PhotoOwnerAlreadyAssignedException.java | 7 +++++++ .../photo/exception/SharedMemberDuplicatedException.java | 7 +++++++ .../photo/exception/SharedMemberNotFoundException.java | 7 +++++++ .../exception/SharedMemberPermissionDeniedException.java | 7 +++++++ .../exception/SharedMemberStatusNotAcceptedException.java | 7 +++++++ 10 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/AlbumOwnerMismatchException.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/PhotoOwnerAlreadyAssignedException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberDuplicatedException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberNotFoundException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberPermissionDeniedException.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberStatusNotAcceptedException.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/AlbumOwnerMismatchException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/AlbumOwnerMismatchException.java new file mode 100644 index 00000000..228f9ed2 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/AlbumOwnerMismatchException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class AlbumOwnerMismatchException extends DomainException { + public AlbumOwnerMismatchException() { + super(ErrorCode.ALBUM_OWNER_MISMATCH); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java deleted file mode 100644 index 8e8d31c4..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/CannotMakePermissionMyselfException.java +++ /dev/null @@ -1,7 +0,0 @@ -package kr.mafoo.photo.exception; - -public class CannotMakePermissionMyselfException extends DomainException { - public CannotMakePermissionMyselfException() { - super(ErrorCode.CANNOT_MAKE_PERMISSION_MYSELF); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java deleted file mode 100644 index be0c691c..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionAlreadyExistsException.java +++ /dev/null @@ -1,7 +0,0 @@ -package kr.mafoo.photo.exception; - -public class PermissionAlreadyExistsException extends DomainException { - public PermissionAlreadyExistsException() { - super(ErrorCode.PERMISSION_ALREADY_EXISTS); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java deleted file mode 100644 index 40229f21..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotAllowedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package kr.mafoo.photo.exception; - -public class PermissionNotAllowedException extends DomainException { - public PermissionNotAllowedException() { - super(ErrorCode.PERMISSION_NOT_ALLOWED); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java deleted file mode 100644 index a2a0bb9a..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/PermissionNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package kr.mafoo.photo.exception; - -public class PermissionNotFoundException extends DomainException { - public PermissionNotFoundException() { - super(ErrorCode.PERMISSION_NOT_FOUND); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/PhotoOwnerAlreadyAssignedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/PhotoOwnerAlreadyAssignedException.java new file mode 100644 index 00000000..e464b2b1 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/PhotoOwnerAlreadyAssignedException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class PhotoOwnerAlreadyAssignedException extends DomainException { + public PhotoOwnerAlreadyAssignedException() { + super(ErrorCode.PHOTO_OWNER_ALREADY_ASSIGNED); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberDuplicatedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberDuplicatedException.java new file mode 100644 index 00000000..e046882b --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberDuplicatedException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class SharedMemberDuplicatedException extends DomainException { + public SharedMemberDuplicatedException() { + super(ErrorCode.SHARED_MEMBER_DUPLICATED); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberNotFoundException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberNotFoundException.java new file mode 100644 index 00000000..7f7ef23f --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberNotFoundException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class SharedMemberNotFoundException extends DomainException { + public SharedMemberNotFoundException() { + super(ErrorCode.SHARED_MEMBER_NOT_FOUND); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberPermissionDeniedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberPermissionDeniedException.java new file mode 100644 index 00000000..4ea2f390 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberPermissionDeniedException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class SharedMemberPermissionDeniedException extends DomainException { + public SharedMemberPermissionDeniedException() { + super(ErrorCode.SHARED_MEMBER_PERMISSION_DENIED); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberStatusNotAcceptedException.java b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberStatusNotAcceptedException.java new file mode 100644 index 00000000..89533cbe --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/SharedMemberStatusNotAcceptedException.java @@ -0,0 +1,7 @@ +package kr.mafoo.photo.exception; + +public class SharedMemberStatusNotAcceptedException extends DomainException { + public SharedMemberStatusNotAcceptedException() { + super(ErrorCode.SHARED_MEMBER_STATUS_NOT_ACCEPTED); + } +} From cf56693bd267a1996c76b6c3e44550a08bb46c70 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 02:44:19 +0900 Subject: [PATCH 15/29] feat: update error code enum for shared member exceptions --- .../main/java/kr/mafoo/photo/exception/ErrorCode.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java index 0d6da84d..2cae0faf 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java +++ b/photo-service/src/main/java/kr/mafoo/photo/exception/ErrorCode.java @@ -12,16 +12,19 @@ public enum ErrorCode { ALBUM_NOT_FOUND("AE0001", "앨범을 찾을 수 없습니다"), ALBUM_DISPLAY_INDEX_IS_SAME("AE0002", "옮기려는 대상 앨범 인덱스가 같습니다"), + ALBUM_OWNER_MISMATCH("AE0003", "앨범의 소유자가 아닙니다"), + PHOTO_NOT_FOUND("PE0001", "사진을 찾을 수 없습니다"), PHOTO_BRAND_NOT_EXISTS("PE0002", "사진 브랜드가 존재하지 않습니다"), PHOTO_QR_URL_EXPIRED("PE0003", "사진 저장을 위한 QR URL이 만료되었습니다"), PHOTO_DISPLAY_INDEX_IS_SAME("PE0004", "옮기려는 대상 사진 인덱스가 같습니다"), PHOTO_DISPLAY_INDEX_NOT_VALID("PE0005", "옮기려는 대상 사진 인덱스가 유효하지 않습니다"), + PHOTO_OWNER_ALREADY_ASSIGNED("PE0006", "이미 소유자가 존재하는 사진입니다"), - PERMISSION_NOT_FOUND("PME0001", "권한을 찾을 수 없습니다"), - CANNOT_MAKE_PERMISSION_MYSELF("PM0002", "자기 자신의 권한을 생성할 수 없습니다"), - PERMISSION_NOT_ALLOWED("PE0003", "권한이 허용되지 않았습니다"), - PERMISSION_ALREADY_EXISTS("PE0004", "동일한 권한이 이미 존재합니다") + SHARED_MEMBER_NOT_FOUND("SE0001", "공유 사용자를 찾을 수 없습니다"), + SHARED_MEMBER_DUPLICATED("SE0002", "동일한 공유 사용자가 존재합니다"), + SHARED_MEMBER_STATUS_NOT_ACCEPTED("SE0003", "공유 요청이 수락되지 않았습니다"), + SHARED_MEMBER_PERMISSION_DENIED("SE0004", "공유 사용자의 권한이 충족되지 않습니다"), PRE_SIGNED_URL_EXCEED_MAXIMUM("OE0001", "한 번에 생성할 수 있는 Pre-signed url 최대치를 초과했습니다"), PRE_SIGNED_URL_BANNED_FILE_TYPE("OE0002", "Pre-signed url 발급이 허용되지 않는 파일 형식입니다"), From 853e9f1550dc08a4396c4f113569adeb21b8e8e7 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 02:55:13 +0900 Subject: [PATCH 16/29] feat: implement share member apis and related dtos --- .../kr/mafoo/photo/api/PermissionApi.java | 71 ---------- .../kr/mafoo/photo/api/SharedMemberApi.java | 89 +++++++++++++ .../controller/PermissionController.java | 57 --------- .../request/PermissionBulkCreateRequest.java | 17 --- .../dto/request/PermissionCreateRequest.java | 19 --- .../request/PermissionTypeUpdateRequest.java | 13 -- .../request/SharedMemberCreateRequest.java | 22 ++++ .../SharedMemberUpdatePermissionRequest.java | 13 ++ .../SharedMemberUpdateStatusRequest.java | 13 ++ .../dto/response/PermissionResponse.java | 31 ----- .../response/SharedMemberDetailResponse.java | 37 ++++++ .../dto/response/SharedMemberResponse.java | 36 ++++++ .../mafoo/photo/domain/PermissionEntity.java | 76 ----------- .../kr/mafoo/photo/domain/PermissionType.java | 9 -- .../repository/PermissionRepository.java | 14 -- .../photo/service/PermissionService.java | 121 ------------------ 16 files changed, 210 insertions(+), 428 deletions(-) delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberCreateRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java delete mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java deleted file mode 100644 index 327e2ca5..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/api/PermissionApi.java +++ /dev/null @@ -1,71 +0,0 @@ -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 jakarta.validation.Valid; -import kr.mafoo.photo.annotation.RequestMemberId; -import kr.mafoo.photo.annotation.ULID; -import kr.mafoo.photo.controller.dto.request.PermissionBulkCreateRequest; -import kr.mafoo.photo.controller.dto.request.PermissionTypeUpdateRequest; -import kr.mafoo.photo.controller.dto.response.PermissionResponse; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Validated -@Tag(name = "권한 관련 API", description = "권한 조회, 생성, 수정, 삭제 등 API") -@RequestMapping("/v1/permissions") -public interface PermissionApi { - @Operation(summary = "권한 조회", description = "권한 목록을 조회합니다.") - @GetMapping - Flux getPermissions( - @RequestMemberId - String memberId, - - @ULID - @Parameter(description = "앨범 ID", example = "test_album_id") - @RequestParam - String albumId - ); - - @Operation(summary = "권한 n건 생성", description = "권한 여러 개를 생성합니다.") - @PostMapping("/bulk") - Flux createPermissionBulk( - @RequestMemberId - String memberId, - - @Valid - @RequestBody - PermissionBulkCreateRequest request - ); - - @Operation(summary = "권한 종류 수정", description = "권한의 종류를 수정합니다.") - @PatchMapping("/{permissionId}/type") - Mono updatePermissionType( - @RequestMemberId - String memberId, - - @ULID - @Parameter(description = "권한 ID", example = "test_permission_id") - @PathVariable - String permissionId, - - @Valid - @RequestBody - PermissionTypeUpdateRequest request - ); - - @Operation(summary = "권한 삭제", description = "권한을 삭제합니다.") - @DeleteMapping("{permissionId}") - Mono deletePermission( - @RequestMemberId - String memberId, - - @ULID - @Parameter(description = "권한 ID", example = "test_permission_id") - @PathVariable - String permissionId - ); -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java new file mode 100644 index 00000000..c3d49017 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java @@ -0,0 +1,89 @@ +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 jakarta.validation.Valid; +import kr.mafoo.photo.annotation.RequestMemberId; +import kr.mafoo.photo.annotation.ULID; +import kr.mafoo.photo.controller.dto.request.SharedMemberCreateRequest; +import kr.mafoo.photo.controller.dto.request.SharedMemberUpdatePermissionRequest; +import kr.mafoo.photo.controller.dto.request.SharedMemberUpdateStatusRequest; +import kr.mafoo.photo.controller.dto.response.SharedMemberDetailResponse; +import kr.mafoo.photo.controller.dto.response.SharedMemberResponse; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Validated +@Tag(name = "공유 사용자 관련 API", description = "공유 사용자 조회, 생성, 수정, 삭제 등 API") +@RequestMapping("/v1/shared-members") +public interface SharedMemberApi { + @Operation(summary = "공유 사용자 조회", description = "앨범 별 공유 사용자 목록을 조회합니다.") + @GetMapping + Flux getSharedMemberListByAlbum( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "앨범 ID", example = "test_album_id") + @RequestParam + String albumId + ); + + @Operation(summary = "공유 사용자 생성", description = "공유 사용자를 생성합니다.") + @PostMapping + Mono createSharedMember( + @RequestMemberId + String memberId, + + @Valid + @RequestBody + SharedMemberCreateRequest request + ); + + @Operation(summary = "공유 사용자 상태 수정", description = "공유 사용자의 상태를 수정합니다.") + @PatchMapping("/{sharedMemberId}/status") + Mono updateSharedMemberStatus( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "공유 사용자 ID", example = "test_shared_member_id") + @PathVariable + String sharedMemberId, + + @Valid + @RequestBody + SharedMemberUpdateStatusRequest request + ); + + @Operation(summary = "공유 사용자 권한 수정", description = "공유 사용자의 권한을 수정합니다.") + @PatchMapping("/{sharedMemberId}/permission") + Mono updateSharedMemberPermission( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "공유 사용자 ID", example = "test_shared_member_id") + @PathVariable + String sharedMemberId, + + @Valid + @RequestBody + SharedMemberUpdatePermissionRequest request + ); + + @Operation(summary = "공유 사용자 삭제", description = "공유 사용자를 삭제합니다.") + @DeleteMapping("{sharedMemberId}") + Mono deleteSharedMember( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "공유 사용자 ID", example = "test_shared_member_id") + @PathVariable + String sharedMemberId + ); +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java deleted file mode 100644 index a185b63a..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/PermissionController.java +++ /dev/null @@ -1,57 +0,0 @@ -package kr.mafoo.photo.controller; - -import kr.mafoo.photo.api.PermissionApi; -import kr.mafoo.photo.controller.dto.request.*; -import kr.mafoo.photo.controller.dto.response.PermissionResponse; -import kr.mafoo.photo.service.PermissionService; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@RequiredArgsConstructor -@RestController -public class PermissionController implements PermissionApi { - - private final PermissionService permissionService; - - @Override - public Flux getPermissions( - String memberId, - String albumId - ){ - return permissionService - .findAllByAlbumId(albumId, memberId) - .map(PermissionResponse::fromEntity); - } - - @Override - public Flux createPermissionBulk( - String memberId, - PermissionBulkCreateRequest request - ){ - return permissionService - .createNewPermissionBulk(request.permissions(), request.albumId(), memberId) - .map(PermissionResponse::fromEntity); - } - - @Override - public Mono updatePermissionType( - String memberId, - String permissionId, - PermissionTypeUpdateRequest request - ){ - return permissionService - .updatePermissionType(permissionId, request.type(), memberId) - .map(PermissionResponse::fromEntity); - } - - @Override - public Mono deletePermission( - String memberId, - String permissionId - ){ - return permissionService - .deletePermissionById(permissionId, memberId); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java deleted file mode 100644 index c0cc3bce..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionBulkCreateRequest.java +++ /dev/null @@ -1,17 +0,0 @@ -package kr.mafoo.photo.controller.dto.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.annotation.ULID; - -import java.util.List; - -@Schema(description = "권한 n건 생성 요청") -public record PermissionBulkCreateRequest( - - List permissions, - - @ULID - @Schema(description = "앨범 ID", example = "test_album_id") - String albumId -) { -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java deleted file mode 100644 index 92eaa56b..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionCreateRequest.java +++ /dev/null @@ -1,19 +0,0 @@ -package kr.mafoo.photo.controller.dto.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.annotation.MatchEnum; -import kr.mafoo.photo.annotation.ULID; -import kr.mafoo.photo.domain.PermissionType; - -@Schema(description = "권한 n건 생성 요청") -public record PermissionCreateRequest( - - @ULID - @Schema(description = "권한 대상 사용자 아이디", example = "test_member_id") - String memberId, - - @MatchEnum(enumClass = PermissionType.class) - @Schema(description = "권한 종류", example = "FULL_ACCESS") - String type -) { -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java deleted file mode 100644 index 5bf905b0..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PermissionTypeUpdateRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package kr.mafoo.photo.controller.dto.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.annotation.MatchEnum; -import kr.mafoo.photo.domain.PermissionType; - -@Schema(description = "권한 종류 수정 요청") -public record PermissionTypeUpdateRequest( - @MatchEnum(enumClass = PermissionType.class) - @Schema(description = "권한 종류", example = "FULL_ACCESS") - String type -) { -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberCreateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberCreateRequest.java new file mode 100644 index 00000000..7e2463a8 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberCreateRequest.java @@ -0,0 +1,22 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.MatchEnum; +import kr.mafoo.photo.annotation.ULID; +import kr.mafoo.photo.domain.enums.PermissionLevel; + +@Schema(description = "공유 사용자 생성 요청") +public record SharedMemberCreateRequest( + + @Schema(description = "공유 대상 앨범 ID", example = "test_album_id") + String albumId, + + @ULID + @Schema(description = "공유 대상 사용자 ID", example = "test_member_id") + String memberId, + + @MatchEnum(enumClass = PermissionLevel.class) + @Schema(description = "권한 단계", example = "FULL_ACCESS") + String permissionLevel +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java new file mode 100644 index 00000000..fe6fd007 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java @@ -0,0 +1,13 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.MatchEnum; +import kr.mafoo.photo.domain.enums.PermissionLevel; + +@Schema(description = "공유 사용자 권한 수정 요청") +public record SharedMemberUpdatePermissionRequest( + @MatchEnum(enumClass = PermissionLevel.class) + @Schema(description = "권한 단계", example = "FULL_ACCESS") + String permissionLevel +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java new file mode 100644 index 00000000..0582f6da --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java @@ -0,0 +1,13 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.MatchEnum; +import kr.mafoo.photo.domain.enums.ShareStatus; + +@Schema(description = "공유 사용자 상태 수정 요청") +public record SharedMemberUpdateStatusRequest( + @MatchEnum(enumClass = ShareStatus.class) + @Schema(description = "공유 상태", example = "PENDING") + String shareStatus +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java deleted file mode 100644 index 0d7da787..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PermissionResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package kr.mafoo.photo.controller.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.domain.PermissionEntity; -import kr.mafoo.photo.domain.PermissionType; - -@Schema(description = "권한 응답") -public record PermissionResponse( - @Schema(description = "권한 ID", example = "test_permission_id") - String permissionId, - - @Schema(description = "권한 종류", example = "FULL_ACCESS") - PermissionType type, - - @Schema(description = "권한 대상 사용자", example = "test_member_id") - String memberId, - - @Schema(description = "권한 대상 앨범", example = "test_album_id") - String albumId -) { - public static PermissionResponse fromEntity( - PermissionEntity entity - ) { - return new PermissionResponse( - entity.getPermissionId(), - entity.getType(), - entity.getMemberId(), - entity.getAlbumId() - ); - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java new file mode 100644 index 00000000..4b4f7815 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java @@ -0,0 +1,37 @@ +package kr.mafoo.photo.controller.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; + +@Schema(description = "공유 사용자 응답") +public record SharedMemberDetailResponse( + @Schema(description = "공유 사용자 ID", example = "test_shared_member_id") + String sharedMemberId, + + @Schema(description = "공유 상태", example = "PENDING") + ShareStatus shareStatus, + + @Schema(description = "권한 단계", example = "FULL_ACCESS") + PermissionLevel permissionLevel, + + @Schema(description = "공유 대상 앨범", example = "test_album_id") + String albumId, + + @Schema(description = "공유 대상 사용자 정보") + MemberResponse memberInfo +) { + public static SharedMemberDetailResponse fromEntity( + SharedMemberEntity entity, + MemberResponse memberResponse + ) { + return new SharedMemberDetailResponse( + entity.getSharedMemberId(), + entity.getShareStatus(), + entity.getPermissionLevel(), + entity.getAlbumId(), + memberResponse + ); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java new file mode 100644 index 00000000..009e7e7a --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java @@ -0,0 +1,36 @@ +package kr.mafoo.photo.controller.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; + +@Schema(description = "공유 사용자 응답") +public record SharedMemberResponse( + @Schema(description = "공유 사용자 ID", example = "test_shared_member_id") + String sharedMemberId, + + @Schema(description = "공유 상태", example = "PENDING") + ShareStatus shareStatus, + + @Schema(description = "권한 단계", example = "FULL_ACCESS") + PermissionLevel permissionLevel, + + @Schema(description = "공유 대상 앨범", example = "test_album_id") + String albumId, + + @Schema(description = "공유 대상 사용자", example = "test_album_id") + String memberId +) { + public static SharedMemberResponse fromEntity( + SharedMemberEntity entity + ) { + return new SharedMemberResponse( + entity.getSharedMemberId(), + entity.getShareStatus(), + entity.getPermissionLevel(), + entity.getAlbumId(), + entity.getMemberId() + ); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java deleted file mode 100644 index 0393c5b9..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionEntity.java +++ /dev/null @@ -1,76 +0,0 @@ -package kr.mafoo.photo.domain; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.annotation.Transient; -import org.springframework.data.domain.Persistable; -import org.springframework.data.relational.core.mapping.Column; -import org.springframework.data.relational.core.mapping.Table; - -import java.time.LocalDateTime; - -@Getter -@NoArgsConstructor -@Table("permission") -public class PermissionEntity implements Persistable { - @Id - @Column("id") - private String permissionId; - - @Column("type") - private PermissionType type; - - @Column("member_id") - private String memberId; - - @Column("album_id") - private String albumId; - - @CreatedDate - @Column("created_at") - private LocalDateTime createdAt; - - @LastModifiedDate - @Column("updated_at") - private LocalDateTime updatedAt; - - @Transient - private boolean isNew = false; - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - - PermissionEntity that = (PermissionEntity) obj; - return permissionId.equals(that.permissionId); - } - - @Override - public int hashCode() { - return permissionId.hashCode(); - } - - @Override - public String getId() { - return permissionId; - } - - public PermissionEntity updateType(String type) { - this.type = PermissionType.valueOf(type); - return this; - } - - public static PermissionEntity newPermission(String permissionId, PermissionType type, String memberId, String albumId) { - PermissionEntity permission = new PermissionEntity(); - permission.permissionId = permissionId; - permission.type = type; - permission.memberId = memberId; - permission.albumId = albumId; - permission.isNew = true; - return permission; - } -} diff --git a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java b/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java deleted file mode 100644 index b808daa1..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/domain/PermissionType.java +++ /dev/null @@ -1,9 +0,0 @@ -package kr.mafoo.photo.domain; - -public enum PermissionType { - FULL_ACCESS, - CAN_DOWNLOAD, - VIEW_ONLY, - ; -} - diff --git a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java b/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java deleted file mode 100644 index 00dd3281..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/repository/PermissionRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package kr.mafoo.photo.repository; - -import kr.mafoo.photo.domain.PermissionEntity; -import kr.mafoo.photo.domain.PermissionType; -import org.springframework.data.r2dbc.repository.R2dbcRepository; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public interface PermissionRepository extends R2dbcRepository { - Flux findAllByAlbumId(String albumId); - - Mono existsByAlbumIdAndMemberId(String albumId, String memberId); - Mono existsByAlbumIdAndMemberIdAndType(String albumId, String memberId, PermissionType type); -} \ No newline at end of file diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java b/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java deleted file mode 100644 index ab0c90ea..00000000 --- a/photo-service/src/main/java/kr/mafoo/photo/service/PermissionService.java +++ /dev/null @@ -1,121 +0,0 @@ -package kr.mafoo.photo.service; - -import kr.mafoo.photo.controller.dto.request.PermissionCreateRequest; -import kr.mafoo.photo.domain.PermissionEntity; -import kr.mafoo.photo.domain.PermissionType; -import kr.mafoo.photo.exception.AlbumNotFoundException; -import kr.mafoo.photo.exception.CannotMakePermissionMyselfException; -import kr.mafoo.photo.exception.PermissionAlreadyExistsException; -import kr.mafoo.photo.exception.PermissionNotFoundException; -import kr.mafoo.photo.repository.AlbumRepository; -import kr.mafoo.photo.repository.PermissionRepository; -import kr.mafoo.photo.util.IdGenerator; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.List; - -@Slf4j -@RequiredArgsConstructor -@Service -public class PermissionService { - private final AlbumRepository albumRepository; - private final PermissionRepository permissionRepository; - - @Transactional - public Flux createNewPermissionBulk(List permissions, String albumId, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new PermissionNotFoundException())) - .flatMapMany(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return Flux.fromIterable(permissions) - .flatMap(permission -> - this.createNewPermission(albumId, permission.type(), permission.memberId(), requestMemberId) - ); - } - }); - } - - private Mono createNewPermission(String albumId, String permissionType, String permissionMemberId, String requestMemberId) { - if (permissionMemberId.equals(requestMemberId)) { - return Mono.error(new CannotMakePermissionMyselfException()); - } - - return checkPermissionExists(albumId, permissionMemberId) - .flatMap(permissionExists -> { - if (!permissionExists) { - return permissionRepository.save(PermissionEntity.newPermission(IdGenerator.generate(), PermissionType.valueOf(permissionType), permissionMemberId, albumId)); - } else { - return Mono.error(new PermissionAlreadyExistsException()); - } - }); - } - - @Transactional(readOnly = true) - public Flux findAllByAlbumId(String albumId, String requestMemberId) { - return albumRepository - .findById(albumId) - .switchIfEmpty(Mono.error(new PermissionNotFoundException())) - .flatMapMany(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 앨범이 아니면 그냥 없는 앨범 처리 - return Mono.error(new AlbumNotFoundException()); - } else { - return permissionRepository.findAllByAlbumId(albumId); - } - }); - } - - @Transactional - public Mono deletePermissionById(String permissionId, String requestMemberId) { - return permissionRepository - .findById(permissionId) - .switchIfEmpty(Mono.error(new PermissionNotFoundException())) - .flatMap(permissionEntity -> albumRepository - .findById(permissionEntity.getAlbumId()) - .flatMap(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - return Mono.error(new PermissionNotFoundException()); - } - - return permissionRepository.deleteById(permissionId); - }) - ); - - } - - @Transactional - public Mono updatePermissionType(String permissionId, String permissionType, String requestMemberId) { - return permissionRepository - .findById(permissionId) - .switchIfEmpty(Mono.error(new PermissionNotFoundException())) - .flatMap(permissionEntity -> albumRepository - .findById(permissionEntity.getAlbumId()) - .switchIfEmpty(Mono.error(new AlbumNotFoundException())) - .flatMap(albumEntity -> { - if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { - return Mono.error(new PermissionNotFoundException()); - } - - return permissionRepository.save(permissionEntity.updateType(permissionType)); - }) - ); - } - - public Mono checkPermissionExists(String albumId, String requestMemberId) { - return permissionRepository.existsByAlbumIdAndMemberId(albumId, requestMemberId); - } - - public Mono checkPermissionExistsByType(String albumId, String requestMemberId, PermissionType type) { - return permissionRepository.existsByAlbumIdAndMemberIdAndType(albumId, requestMemberId, type); - } - -} From 376852cc64b429dea78508cfb55ca3fc07004be7 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 03:58:53 +0900 Subject: [PATCH 17/29] feat: implement share member service --- .../repository/SharedMemberRepository.java | 13 ++++ .../photo/service/AlbumPermissionQuery.java | 48 ++++++++++++ .../kr/mafoo/photo/service/AlbumQuery.java | 20 +++++ .../kr/mafoo/photo/service/MemberService.java | 22 +++--- .../photo/service/SharedMemberCommend.java | 44 +++++++++++ .../photo/service/SharedMemberQuery.java | 49 ++++++++++++ .../photo/service/SharedMemberService.java | 74 +++++++++++++++++++ .../service/dto/SharedMemberDetailDto.java | 30 ++++++++ 8 files changed, 291 insertions(+), 9 deletions(-) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/dto/SharedMemberDetailDto.java 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 new file mode 100644 index 00000000..70b8277d --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/repository/SharedMemberRepository.java @@ -0,0 +1,13 @@ +package kr.mafoo.photo.repository; + +import kr.mafoo.photo.domain.SharedMemberEntity; +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Repository +public interface SharedMemberRepository extends R2dbcRepository { + Flux findAllByAlbumId(String albumId); + Mono findByAlbumIdAndMemberId(String albumId, String memberId); +} \ No newline at end of file diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java new file mode 100644 index 00000000..153762a6 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java @@ -0,0 +1,48 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.AlbumEntity; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.exception.AlbumOwnerMismatchException; +import kr.mafoo.photo.exception.SharedMemberPermissionDeniedException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +@RequiredArgsConstructor +public class AlbumPermissionQuery { + + private final AlbumQuery albumQuery; + private final SharedMemberQuery sharedMemberQuery; + + public Mono verifyOwnershipOrAccessPermission(String albumId, String requestMemberId, PermissionLevel permissionLevel) { + return verifyOwnership(albumId, requestMemberId) + .onErrorResume(AlbumOwnerMismatchException.class, ex -> + sharedMemberQuery.findByAlbumIdAndMemberId(albumId, requestMemberId) + .flatMap(sharedAlbumMember -> + checkAccessPermission(sharedAlbumMember.getPermissionLevel(), permissionLevel) + ).then(albumQuery.findById(albumId)) + ); + } + + public Mono verifyOwnership(String albumId, String requestMemberId) { + return albumQuery.findById(albumId) + .flatMap(album -> checkOwnership(album.getOwnerMemberId(), requestMemberId) + .thenReturn(album) + ); + } + + private Mono checkOwnership(String ownerMemberId, String requestMemberId) { + if (!ownerMemberId.equals(requestMemberId)) { + return Mono.error(new AlbumOwnerMismatchException()); + } + return Mono.empty(); + } + + private Mono checkAccessPermission(PermissionLevel currentLevel, PermissionLevel requiredLevel) { + if (currentLevel.getTier() < requiredLevel.getTier()) { + return Mono.error(new SharedMemberPermissionDeniedException()); + } + return Mono.empty(); + } +} 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 new file mode 100644 index 00000000..f2b4ac86 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumQuery.java @@ -0,0 +1,20 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.AlbumEntity; +import kr.mafoo.photo.exception.AlbumNotFoundException; +import kr.mafoo.photo.repository.AlbumRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +@RequiredArgsConstructor +public class AlbumQuery { + + private final AlbumRepository albumRepository; + + public Mono findById(String albumId) { + return albumRepository.findById(albumId) + .switchIfEmpty(Mono.error(new AlbumNotFoundException())); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java index 4fc6bfc1..91969388 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java @@ -1,13 +1,12 @@ package kr.mafoo.photo.service; -import kr.mafoo.photo.exception.MafooUserApiFailed; import kr.mafoo.photo.service.dto.MemberDto; +import kr.mafoo.photo.exception.MafooUserApiFailed; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.ClientResponse; @RequiredArgsConstructor @Service @@ -18,14 +17,19 @@ public class MemberService { private final WebClient client; - public Mono getMemberInfo(String authorizationToken) { + public Mono getMemberInfoByToken(String authorizationToken) { return client - .get() - .uri(endpoint + "/user/v1/me") - .header("Authorization", "Bearer " + authorizationToken) - .retrieve() - .onStatus(status -> !status.is2xxSuccessful(), (res) -> Mono.error(new MafooUserApiFailed())) - .bodyToMono(MemberDto.class); + .get() + .uri(endpoint + "/user/v1/me") + .header("Authorization", "Bearer " + authorizationToken) + .retrieve() + .onStatus(status -> !status.is2xxSuccessful(), (res) -> Mono.error(new MafooUserApiFailed())) + .bodyToMono(MemberDto.class); + } + + public Mono getMemberInfoById(String memberId, String authorizationToken) { + // TODO : API 구현 후 연결 필요 + return Mono.empty(); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java new file mode 100644 index 00000000..034c5f07 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java @@ -0,0 +1,44 @@ +package kr.mafoo.photo.service; + +import static kr.mafoo.photo.domain.enums.ShareStatus.PENDING; + +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.ShareStatus; +import kr.mafoo.photo.repository.SharedMemberRepository; +import kr.mafoo.photo.util.IdGenerator; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class SharedMemberCommend { + + private final SharedMemberRepository sharedMemberRepository; + + public Mono addSharedMember(String albumId, String permissionLevel, String sharingMemberId) { + return sharedMemberRepository.save( + SharedMemberEntity.newSharedMember( + IdGenerator.generate(), PENDING, PermissionLevel.valueOf(permissionLevel), sharingMemberId, albumId + ) + ); + } + + public Mono removeSharedMember(SharedMemberEntity sharedMember) { + return sharedMemberRepository.delete(sharedMember); + } + + public Mono modifySharedMemberShareStatus(SharedMemberEntity sharedMember, String newShareStatus) { + return sharedMemberRepository.save(sharedMember.updateShareStatus( + ShareStatus.valueOf(newShareStatus) + )); + } + + public Mono modifySharedMemberPermissionLevel(SharedMemberEntity sharedMember, String newPermissionLevel) { + return sharedMemberRepository.save(sharedMember.updatePermissionLevel( + PermissionLevel.valueOf(newPermissionLevel) + )); + } + +} 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 new file mode 100644 index 00000000..bd80cd46 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberQuery.java @@ -0,0 +1,49 @@ +package kr.mafoo.photo.service; + +import static kr.mafoo.photo.domain.enums.ShareStatus.ACCEPTED; + +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.ShareStatus; +import kr.mafoo.photo.exception.SharedMemberNotFoundException; +import kr.mafoo.photo.exception.SharedMemberStatusNotAcceptedException; +import kr.mafoo.photo.repository.SharedMemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class SharedMemberQuery { + + private final SharedMemberRepository sharedMemberRepository; + + public Flux findAllByAlbumId(String albumId) { + return sharedMemberRepository.findAllByAlbumId(albumId) + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); + } + + public Mono findBySharedMemberId(String sharedMemberId) { + return sharedMemberRepository.findById(sharedMemberId) + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())) + .flatMap(sharedMemberEntity -> verifyStatus(sharedMemberEntity.getShareStatus()) + .thenReturn(sharedMemberEntity) + ); + } + + public Mono findByAlbumIdAndMemberId(String albumId, String memberId) { + return sharedMemberRepository.findByAlbumIdAndMemberId(albumId, memberId) + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())) + .flatMap(sharedMemberEntity -> verifyStatus(sharedMemberEntity.getShareStatus()) + .thenReturn(sharedMemberEntity) + ); + } + + private Mono verifyStatus(ShareStatus status) { + if (!status.equals(ACCEPTED)) { + return Mono.error(new SharedMemberStatusNotAcceptedException()); + } + return Mono.empty(); + } + +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java new file mode 100644 index 00000000..73d14899 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java @@ -0,0 +1,74 @@ +package kr.mafoo.photo.service; + +import static kr.mafoo.photo.domain.enums.PermissionLevel.FULL_ACCESS; +import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; + +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.exception.SharedMemberDuplicatedException; +import kr.mafoo.photo.service.dto.SharedMemberDetailDto; +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 SharedMemberService { + + private final SharedMemberQuery sharedMemberQuery; + private final SharedMemberCommend sharedMemberCommend; + + private final AlbumPermissionQuery albumPermissionQuery; + private final MemberService memberService; + + @Transactional(readOnly = true) + public Flux findSharedMemberDetailListByAlbumId(String albumId, String requestMemberId, String token) { + return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, VIEW_ACCESS) + .thenMany(sharedMemberQuery.findAllByAlbumId(albumId)) + .flatMap(sharedMemberEntity -> memberService.getMemberInfoById(sharedMemberEntity.getMemberId(), token) + .map(memberDto -> SharedMemberDetailDto.from(sharedMemberEntity, memberDto)) + ); + } + + @Transactional + public Mono addSharedMember(String albumId, String permissionLevel, String sharingMemberId, String requestMemberId) { + return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .then(sharedMemberQuery.findByAlbumIdAndMemberId(albumId, sharingMemberId) + .switchIfEmpty( + sharedMemberCommend.addSharedMember(albumId, permissionLevel, sharingMemberId) + ) + .flatMap(existingMember -> Mono.error(new SharedMemberDuplicatedException())) + ); + } + + @Transactional + public Mono removeSharedMember(String sharedMemberId, String requestMemberId) { + return sharedMemberQuery.findBySharedMemberId(sharedMemberId) + .flatMap(sharedMember -> { + if (sharedMember.getMemberId().equals(requestMemberId)) { + return sharedMemberCommend.removeSharedMember(sharedMember); + } else { + return albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) + .then(sharedMemberCommend.removeSharedMember(sharedMember)); + } + }); + } + + @Transactional + public Mono modifySharedMemberShareStatus(String sharedMemberId, String newShareStatus, String requestMemberId) { + return sharedMemberQuery.findBySharedMemberId(sharedMemberId) + .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) + .then(sharedMemberCommend.modifySharedMemberShareStatus(sharedMember, newShareStatus)) + ); + } + + @Transactional + public Mono modifySharedMemberPermissionLevel(String sharedMemberId, String newPermissionLevel, String requestMemberId) { + return sharedMemberQuery.findBySharedMemberId(sharedMemberId) + .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) + .then(sharedMemberCommend.modifySharedMemberPermissionLevel(sharedMember, newPermissionLevel)) + ); + } + +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/dto/SharedMemberDetailDto.java b/photo-service/src/main/java/kr/mafoo/photo/service/dto/SharedMemberDetailDto.java new file mode 100644 index 00000000..72f3882a --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/dto/SharedMemberDetailDto.java @@ -0,0 +1,30 @@ +package kr.mafoo.photo.service.dto; + +import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; + +public record SharedMemberDetailDto( + String sharedMemberId, + ShareStatus shareStatus, + PermissionLevel permissionLevel, + String albumId, + String memberId, + String profileImageUrl, + String memberName +) { + public static SharedMemberDetailDto from( + SharedMemberEntity sharedMemberEntity, + MemberDto memberDto + ) { + return new SharedMemberDetailDto( + sharedMemberEntity.getSharedMemberId(), + sharedMemberEntity.getShareStatus(), + sharedMemberEntity.getPermissionLevel(), + sharedMemberEntity.getAlbumId(), + memberDto.memberId(), + memberDto.profileImageUrl(), + memberDto.name() + ); + } +} From 45eb5128be1d46e56da743848ab2bcb14314875d Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 04:00:56 +0900 Subject: [PATCH 18/29] feat: implement share member controller --- .../kr/mafoo/photo/api/SharedMemberApi.java | 6 +- .../controller/SharedMemberController.java | 70 +++++++++++++++++++ .../response/SharedMemberDetailResponse.java | 31 ++++---- .../dto/response/SharedMemberResponse.java | 4 +- 4 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java index c3d49017..905a8400 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java +++ b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java @@ -11,6 +11,7 @@ import kr.mafoo.photo.controller.dto.request.SharedMemberUpdateStatusRequest; import kr.mafoo.photo.controller.dto.response.SharedMemberDetailResponse; import kr.mafoo.photo.controller.dto.response.SharedMemberResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; @@ -29,7 +30,10 @@ Flux getSharedMemberListByAlbum( @ULID @Parameter(description = "앨범 ID", example = "test_album_id") @RequestParam - String albumId + String albumId, + + // Authorization Header를 받아올 목적 + ServerHttpRequest serverHttpRequest ); @Operation(summary = "공유 사용자 생성", description = "공유 사용자를 생성합니다.") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java new file mode 100644 index 00000000..e48d129f --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java @@ -0,0 +1,70 @@ +package kr.mafoo.photo.controller; + +import kr.mafoo.photo.api.SharedMemberApi; +import kr.mafoo.photo.controller.dto.request.SharedMemberCreateRequest; +import kr.mafoo.photo.controller.dto.request.SharedMemberUpdatePermissionRequest; +import kr.mafoo.photo.controller.dto.request.SharedMemberUpdateStatusRequest; +import kr.mafoo.photo.controller.dto.response.SharedMemberDetailResponse; +import kr.mafoo.photo.controller.dto.response.SharedMemberResponse; +import kr.mafoo.photo.service.SharedMemberService; +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; + +@RequiredArgsConstructor +@RestController +public class SharedMemberController implements SharedMemberApi { + + private final SharedMemberService sharedMemberService; + + @Override + public Flux getSharedMemberListByAlbum( + String memberId, + String albumId, + ServerHttpRequest serverHttpRequest + ){ + String authorizationToken = serverHttpRequest.getHeaders().getFirst("Authorization"); + + return sharedMemberService.findSharedMemberDetailListByAlbumId(albumId, memberId, authorizationToken) + .map(SharedMemberDetailResponse::fromDto); + } + + @Override + public Mono createSharedMember( + String memberId, + SharedMemberCreateRequest request + ){ + return sharedMemberService.addSharedMember(request.albumId(), request.permissionLevel(), request.memberId(), memberId) + .map(SharedMemberResponse::fromEntity); + } + + @Override + public Mono updateSharedMemberStatus( + String memberId, + String sharedMemberId, + SharedMemberUpdateStatusRequest request + ){ + return sharedMemberService.modifySharedMemberShareStatus(sharedMemberId, request.shareStatus(), memberId) + .map(SharedMemberResponse::fromEntity); + } + + @Override + public Mono updateSharedMemberPermission( + String memberId, + String sharedMemberId, + SharedMemberUpdatePermissionRequest request + ){ + return sharedMemberService.modifySharedMemberPermissionLevel(sharedMemberId, request.permissionLevel(), memberId) + .map(SharedMemberResponse::fromEntity); + } + + @Override + public Mono deleteSharedMember( + String memberId, + String sharedMemberId + ){ + return sharedMemberService.removeSharedMember(memberId, sharedMemberId); + } +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java index 4b4f7815..69b49e9f 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberDetailResponse.java @@ -1,9 +1,9 @@ package kr.mafoo.photo.controller.dto.response; import io.swagger.v3.oas.annotations.media.Schema; -import kr.mafoo.photo.domain.SharedMemberEntity; import kr.mafoo.photo.domain.enums.PermissionLevel; import kr.mafoo.photo.domain.enums.ShareStatus; +import kr.mafoo.photo.service.dto.SharedMemberDetailDto; @Schema(description = "공유 사용자 응답") public record SharedMemberDetailResponse( @@ -16,22 +16,29 @@ public record SharedMemberDetailResponse( @Schema(description = "권한 단계", example = "FULL_ACCESS") PermissionLevel permissionLevel, - @Schema(description = "공유 대상 앨범", example = "test_album_id") + @Schema(description = "공유 대상 앨범 ID", example = "test_album_id") String albumId, - @Schema(description = "공유 대상 사용자 정보") - MemberResponse memberInfo + @Schema(description = "공유 대상 사용자 ID", example = "test_member_id") + String memberId, + + @Schema(description = "공유 대상 사용자 프로필 사진 URL", example = "test_member_profile_url") + String profileImageUrl, + + @Schema(description = "공유 대상 사용자 이름", example = "test_member_name") + String memberName ) { - public static SharedMemberDetailResponse fromEntity( - SharedMemberEntity entity, - MemberResponse memberResponse + public static SharedMemberDetailResponse fromDto( + SharedMemberDetailDto dto ) { return new SharedMemberDetailResponse( - entity.getSharedMemberId(), - entity.getShareStatus(), - entity.getPermissionLevel(), - entity.getAlbumId(), - memberResponse + dto.sharedMemberId(), + dto.shareStatus(), + dto.permissionLevel(), + dto.albumId(), + dto.memberId(), + dto.profileImageUrl(), + dto.memberName() ); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java index 009e7e7a..ec2f7337 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/SharedMemberResponse.java @@ -16,10 +16,10 @@ public record SharedMemberResponse( @Schema(description = "권한 단계", example = "FULL_ACCESS") PermissionLevel permissionLevel, - @Schema(description = "공유 대상 앨범", example = "test_album_id") + @Schema(description = "공유 대상 앨범 ID", example = "test_album_id") String albumId, - @Schema(description = "공유 대상 사용자", example = "test_album_id") + @Schema(description = "공유 대상 사용자 ID", example = "test_album_id") String memberId ) { public static SharedMemberResponse fromEntity( From fe35ce14ba497b2b00aa44cdc6a2b77272a17663 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 04:21:04 +0900 Subject: [PATCH 19/29] fix: typo 'commend' as 'command' --- ...edMemberCommend.java => SharedMemberCommand.java} | 2 +- .../kr/mafoo/photo/service/SharedMemberService.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/service/{SharedMemberCommend.java => SharedMemberCommand.java} (97%) diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommand.java similarity index 97% rename from photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java rename to photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommand.java index 034c5f07..13bfe550 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommend.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberCommand.java @@ -13,7 +13,7 @@ @RequiredArgsConstructor @Service -public class SharedMemberCommend { +public class SharedMemberCommand { private final SharedMemberRepository sharedMemberRepository; diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java index 73d14899..153210ca 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java @@ -17,7 +17,7 @@ public class SharedMemberService { private final SharedMemberQuery sharedMemberQuery; - private final SharedMemberCommend sharedMemberCommend; + private final SharedMemberCommand sharedMemberCommand; private final AlbumPermissionQuery albumPermissionQuery; private final MemberService memberService; @@ -36,7 +36,7 @@ public Mono addSharedMember(String albumId, String permissio return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) .then(sharedMemberQuery.findByAlbumIdAndMemberId(albumId, sharingMemberId) .switchIfEmpty( - sharedMemberCommend.addSharedMember(albumId, permissionLevel, sharingMemberId) + sharedMemberCommand.addSharedMember(albumId, permissionLevel, sharingMemberId) ) .flatMap(existingMember -> Mono.error(new SharedMemberDuplicatedException())) ); @@ -47,10 +47,10 @@ public Mono removeSharedMember(String sharedMemberId, String requestMember return sharedMemberQuery.findBySharedMemberId(sharedMemberId) .flatMap(sharedMember -> { if (sharedMember.getMemberId().equals(requestMemberId)) { - return sharedMemberCommend.removeSharedMember(sharedMember); + return sharedMemberCommand.removeSharedMember(sharedMember); } else { return albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) - .then(sharedMemberCommend.removeSharedMember(sharedMember)); + .then(sharedMemberCommand.removeSharedMember(sharedMember)); } }); } @@ -59,7 +59,7 @@ public Mono removeSharedMember(String sharedMemberId, String requestMember public Mono modifySharedMemberShareStatus(String sharedMemberId, String newShareStatus, String requestMemberId) { return sharedMemberQuery.findBySharedMemberId(sharedMemberId) .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) - .then(sharedMemberCommend.modifySharedMemberShareStatus(sharedMember, newShareStatus)) + .then(sharedMemberCommand.modifySharedMemberShareStatus(sharedMember, newShareStatus)) ); } @@ -67,7 +67,7 @@ public Mono modifySharedMemberShareStatus(String sharedMembe public Mono modifySharedMemberPermissionLevel(String sharedMemberId, String newPermissionLevel, String requestMemberId) { return sharedMemberQuery.findBySharedMemberId(sharedMemberId) .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) - .then(sharedMemberCommend.modifySharedMemberPermissionLevel(sharedMember, newPermissionLevel)) + .then(sharedMemberCommand.modifySharedMemberPermissionLevel(sharedMember, newPermissionLevel)) ); } From 61ca37250c9dffb06b68b1cdd2175f092a5810d6 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 12:17:42 +0900 Subject: [PATCH 20/29] refactor: re-arrange album & photo entity --- .../main/java/kr/mafoo/photo/domain/AlbumEntity.java | 12 ++++++++++-- .../main/java/kr/mafoo/photo/domain/PhotoEntity.java | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) 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 5d8842a3..535587c5 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 @@ -3,7 +3,6 @@ import kr.mafoo.photo.domain.enums.AlbumType; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.LastModifiedDate; @@ -15,7 +14,6 @@ import java.time.LocalDateTime; @Getter -@Setter @NoArgsConstructor @Table("album") public class AlbumEntity implements Persistable { @@ -68,6 +66,16 @@ public String getId() { return albumId; } + public AlbumEntity updateOwnerMemberId(String newOwnerMemberId) { + this.ownerMemberId = newOwnerMemberId; + return this; + } + + public AlbumEntity updateDisplayIndex(int newDisplayIndex) { + this.displayIndex = newDisplayIndex; + return this; + } + public AlbumEntity updateName(String newName) { this.name = newName; 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 08090a4a..90b4b801 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 @@ -36,9 +36,11 @@ public class PhotoEntity implements Persistable { @Column("display_index") private Integer displayIndex; + @CreatedDate @Column("created_at") private LocalDateTime createdAt; + @LastModifiedDate @Column("updated_at") private LocalDateTime updatedAt; @@ -92,8 +94,6 @@ public static PhotoEntity newPhoto(String photoId, String photoUrl, BrandType br photo.albumId = albumId; photo.displayIndex = displayIndex; photo.isNew = true; - photo.createdAt = LocalDateTime.now(); - photo.updatedAt = LocalDateTime.now(); return photo; } } From 9992fd5b514ce0d288449922dddb2aeac93279b4 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 13:45:04 +0900 Subject: [PATCH 21/29] fix: fix shared member related apis --- .../kr/mafoo/photo/api/SharedMemberApi.java | 41 ++++++------------- .../controller/SharedMemberController.java | 15 ------- .../SharedMemberUpdatePermissionRequest.java | 2 +- .../SharedMemberUpdateStatusRequest.java | 2 +- .../photo/service/SharedMemberQuery.java | 21 +--------- .../photo/service/SharedMemberService.java | 39 ++++++++++-------- 6 files changed, 37 insertions(+), 83 deletions(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java index 905a8400..cff69074 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java +++ b/photo-service/src/main/java/kr/mafoo/photo/api/SharedMemberApi.java @@ -9,32 +9,15 @@ import kr.mafoo.photo.controller.dto.request.SharedMemberCreateRequest; import kr.mafoo.photo.controller.dto.request.SharedMemberUpdatePermissionRequest; import kr.mafoo.photo.controller.dto.request.SharedMemberUpdateStatusRequest; -import kr.mafoo.photo.controller.dto.response.SharedMemberDetailResponse; import kr.mafoo.photo.controller.dto.response.SharedMemberResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Validated -@Tag(name = "공유 사용자 관련 API", description = "공유 사용자 조회, 생성, 수정, 삭제 등 API") +@Tag(name = "공유 사용자 관련 API", description = "공유 사용자 조회, 생성, 변경, 삭제 등 API") @RequestMapping("/v1/shared-members") public interface SharedMemberApi { - @Operation(summary = "공유 사용자 조회", description = "앨범 별 공유 사용자 목록을 조회합니다.") - @GetMapping - Flux getSharedMemberListByAlbum( - @RequestMemberId - String memberId, - - @ULID - @Parameter(description = "앨범 ID", example = "test_album_id") - @RequestParam - String albumId, - - // Authorization Header를 받아올 목적 - ServerHttpRequest serverHttpRequest - ); @Operation(summary = "공유 사용자 생성", description = "공유 사용자를 생성합니다.") @PostMapping @@ -47,23 +30,23 @@ Mono createSharedMember( SharedMemberCreateRequest request ); - @Operation(summary = "공유 사용자 상태 수정", description = "공유 사용자의 상태를 수정합니다.") + @Operation(summary = "공유 사용자 상태 변경", description = "공유 사용자의 상태를 변경합니다.") @PatchMapping("/{sharedMemberId}/status") Mono updateSharedMemberStatus( - @RequestMemberId - String memberId, + @RequestMemberId + String memberId, - @ULID - @Parameter(description = "공유 사용자 ID", example = "test_shared_member_id") - @PathVariable - String sharedMemberId, + @ULID + @Parameter(description = "공유 사용자 ID", example = "test_shared_member_id") + @PathVariable + String sharedMemberId, - @Valid - @RequestBody - SharedMemberUpdateStatusRequest request + @Valid + @RequestBody + SharedMemberUpdateStatusRequest request ); - @Operation(summary = "공유 사용자 권한 수정", description = "공유 사용자의 권한을 수정합니다.") + @Operation(summary = "공유 사용자 권한 변경", description = "공유 사용자의 권한을 변경합니다.") @PatchMapping("/{sharedMemberId}/permission") Mono updateSharedMemberPermission( @RequestMemberId diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java index e48d129f..eb731c7f 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java @@ -4,13 +4,10 @@ import kr.mafoo.photo.controller.dto.request.SharedMemberCreateRequest; import kr.mafoo.photo.controller.dto.request.SharedMemberUpdatePermissionRequest; import kr.mafoo.photo.controller.dto.request.SharedMemberUpdateStatusRequest; -import kr.mafoo.photo.controller.dto.response.SharedMemberDetailResponse; import kr.mafoo.photo.controller.dto.response.SharedMemberResponse; import kr.mafoo.photo.service.SharedMemberService; 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; @RequiredArgsConstructor @@ -19,18 +16,6 @@ public class SharedMemberController implements SharedMemberApi { private final SharedMemberService sharedMemberService; - @Override - public Flux getSharedMemberListByAlbum( - String memberId, - String albumId, - ServerHttpRequest serverHttpRequest - ){ - String authorizationToken = serverHttpRequest.getHeaders().getFirst("Authorization"); - - return sharedMemberService.findSharedMemberDetailListByAlbumId(albumId, memberId, authorizationToken) - .map(SharedMemberDetailResponse::fromDto); - } - @Override public Mono createSharedMember( String memberId, diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java index fe6fd007..b3ecf650 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdatePermissionRequest.java @@ -4,7 +4,7 @@ import kr.mafoo.photo.annotation.MatchEnum; import kr.mafoo.photo.domain.enums.PermissionLevel; -@Schema(description = "공유 사용자 권한 수정 요청") +@Schema(description = "공유 사용자 권한 변경 요청") public record SharedMemberUpdatePermissionRequest( @MatchEnum(enumClass = PermissionLevel.class) @Schema(description = "권한 단계", example = "FULL_ACCESS") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java index 0582f6da..339c2786 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/SharedMemberUpdateStatusRequest.java @@ -4,7 +4,7 @@ import kr.mafoo.photo.annotation.MatchEnum; import kr.mafoo.photo.domain.enums.ShareStatus; -@Schema(description = "공유 사용자 상태 수정 요청") +@Schema(description = "공유 사용자 상태 변경 요청") public record SharedMemberUpdateStatusRequest( @MatchEnum(enumClass = ShareStatus.class) @Schema(description = "공유 상태", example = "PENDING") 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 bd80cd46..068e55c0 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,11 +1,7 @@ package kr.mafoo.photo.service; -import static kr.mafoo.photo.domain.enums.ShareStatus.ACCEPTED; - import kr.mafoo.photo.domain.SharedMemberEntity; -import kr.mafoo.photo.domain.enums.ShareStatus; import kr.mafoo.photo.exception.SharedMemberNotFoundException; -import kr.mafoo.photo.exception.SharedMemberStatusNotAcceptedException; import kr.mafoo.photo.repository.SharedMemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -25,25 +21,12 @@ public Flux findAllByAlbumId(String albumId) { public Mono findBySharedMemberId(String sharedMemberId) { return sharedMemberRepository.findById(sharedMemberId) - .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())) - .flatMap(sharedMemberEntity -> verifyStatus(sharedMemberEntity.getShareStatus()) - .thenReturn(sharedMemberEntity) - ); + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); } public Mono findByAlbumIdAndMemberId(String albumId, String memberId) { return sharedMemberRepository.findByAlbumIdAndMemberId(albumId, memberId) - .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())) - .flatMap(sharedMemberEntity -> verifyStatus(sharedMemberEntity.getShareStatus()) - .thenReturn(sharedMemberEntity) - ); - } - - private Mono verifyStatus(ShareStatus status) { - if (!status.equals(ACCEPTED)) { - return Mono.error(new SharedMemberStatusNotAcceptedException()); - } - return Mono.empty(); + .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java index 153210ca..47a9f8b9 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java @@ -1,15 +1,16 @@ package kr.mafoo.photo.service; import static kr.mafoo.photo.domain.enums.PermissionLevel.FULL_ACCESS; -import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; +import static kr.mafoo.photo.domain.enums.ShareStatus.PENDING; import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.domain.enums.ShareStatus; import kr.mafoo.photo.exception.SharedMemberDuplicatedException; -import kr.mafoo.photo.service.dto.SharedMemberDetailDto; +import kr.mafoo.photo.exception.SharedMemberNotFoundException; +import kr.mafoo.photo.exception.SharedMemberPermissionDeniedException; 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 @@ -20,22 +21,12 @@ public class SharedMemberService { private final SharedMemberCommand sharedMemberCommand; private final AlbumPermissionQuery albumPermissionQuery; - private final MemberService memberService; - - @Transactional(readOnly = true) - public Flux findSharedMemberDetailListByAlbumId(String albumId, String requestMemberId, String token) { - return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, VIEW_ACCESS) - .thenMany(sharedMemberQuery.findAllByAlbumId(albumId)) - .flatMap(sharedMemberEntity -> memberService.getMemberInfoById(sharedMemberEntity.getMemberId(), token) - .map(memberDto -> SharedMemberDetailDto.from(sharedMemberEntity, memberDto)) - ); - } @Transactional public Mono addSharedMember(String albumId, String permissionLevel, String sharingMemberId, String requestMemberId) { return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) .then(sharedMemberQuery.findByAlbumIdAndMemberId(albumId, sharingMemberId) - .switchIfEmpty( + .onErrorResume(SharedMemberNotFoundException.class, ex -> sharedMemberCommand.addSharedMember(albumId, permissionLevel, sharingMemberId) ) .flatMap(existingMember -> Mono.error(new SharedMemberDuplicatedException())) @@ -46,7 +37,7 @@ public Mono addSharedMember(String albumId, String permissio public Mono removeSharedMember(String sharedMemberId, String requestMemberId) { return sharedMemberQuery.findBySharedMemberId(sharedMemberId) .flatMap(sharedMember -> { - if (sharedMember.getMemberId().equals(requestMemberId)) { + if (isSharedMemberSelfRequest(sharedMember, requestMemberId) && !isPendingStatus(sharedMember.getShareStatus())) { return sharedMemberCommand.removeSharedMember(sharedMember); } else { return albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) @@ -58,9 +49,13 @@ public Mono removeSharedMember(String sharedMemberId, String requestMember @Transactional public Mono modifySharedMemberShareStatus(String sharedMemberId, String newShareStatus, String requestMemberId) { return sharedMemberQuery.findBySharedMemberId(sharedMemberId) - .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) - .then(sharedMemberCommand.modifySharedMemberShareStatus(sharedMember, newShareStatus)) - ); + .flatMap(sharedMember -> { + if (isSharedMemberSelfRequest(sharedMember, requestMemberId) && isPendingStatus(sharedMember.getShareStatus())) { + return sharedMemberCommand.modifySharedMemberShareStatus(sharedMember, newShareStatus); + } else { + return Mono.error(new SharedMemberPermissionDeniedException()); + } + }); } @Transactional @@ -71,4 +66,12 @@ public Mono modifySharedMemberPermissionLevel(String sharedM ); } + private boolean isSharedMemberSelfRequest(SharedMemberEntity sharedMember, String requestMemberId) { + return sharedMember.getMemberId().equals(requestMemberId); + } + + private boolean isPendingStatus(ShareStatus status) { + return status.equals(PENDING); + } + } From f473280231fbfdc246a5bcc8ce2024c9702501bb Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 14:36:02 +0900 Subject: [PATCH 22/29] feat: add permission checking logic for album apis --- .../java/kr/mafoo/photo/api/AlbumApi.java | 33 +++- .../photo/controller/AlbumController.java | 43 +++-- ...ava => AlbumUpdateNameAndTypeRequest.java} | 8 +- .../request/AlbumUpdateOwnershipRequest.java | 12 ++ .../dto/response/AlbumResponse.java | 2 +- .../kr/mafoo/photo/service/AlbumCommand.java | 38 +++++ .../photo/service/AlbumPermissionQuery.java | 2 +- .../kr/mafoo/photo/service/AlbumService.java | 161 +++--------------- 8 files changed, 130 insertions(+), 169 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/{AlbumUpdateRequest.java => AlbumUpdateNameAndTypeRequest.java} (69%) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateOwnershipRequest.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java 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 3a1213c6..76828012 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 @@ -8,7 +8,8 @@ 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.AlbumUpdateRequest; +import kr.mafoo.photo.controller.dto.request.AlbumUpdateNameAndTypeRequest; +import kr.mafoo.photo.controller.dto.request.AlbumUpdateOwnershipRequest; import kr.mafoo.photo.controller.dto.response.AlbumResponse; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -16,12 +17,12 @@ import reactor.core.publisher.Mono; @Validated -@Tag(name = "앨범 관련 API", description = "앨범 조회, 생성, 수정, 삭제 등 API") +@Tag(name = "앨범 관련 API", description = "앨범 조회, 생성, 변경, 삭제 등 API") @RequestMapping("/v1/albums") public interface AlbumApi { - @Operation(summary = "앨범 n건 조회", description = "앨범 목록을 조회합니다.") + @Operation(summary = "사용자 별 앨범 목록 조회", description = "사용자 별 앨범 목록을 조회합니다.") @GetMapping - Flux getAlbums( + Flux getAlbumListByMember( @RequestMemberId String memberId ); @@ -49,9 +50,9 @@ Mono createAlbum( AlbumCreateRequest request ); - @Operation(summary = "앨범 변경", description = "앨범의 속성을 변경합니다.") + @Operation(summary = "앨범 속성(이름, 종류) 변경", description = "앨범의 속성(이름, 종류)을 변경합니다.") @PutMapping("/{albumId}") - Mono updateAlbum( + Mono updateAlbumNameAndType( @RequestMemberId String memberId, @@ -62,10 +63,10 @@ Mono updateAlbum( @Valid @RequestBody - AlbumUpdateRequest request + AlbumUpdateNameAndTypeRequest request ); - @Operation(summary = "앨범 표기 순서 변경", description = "앨범의 표기 순서를 변경합니다.") + @Operation(summary = "[DEPRECATED] 앨범 표시 순서 변경", description = "앨범의 표시 순서를 변경합니다.") @PatchMapping("/{albumId}/display-index") Mono updateAlbumDisplayIndex( @RequestMemberId @@ -81,6 +82,22 @@ Mono updateAlbumDisplayIndex( AlbumUpdateDisplayIndexRequest request ); + @Operation(summary = "앨범 소유자 변경", description = "앨범의 소유자를 변경합니다.") + @PatchMapping("/{albumId}/display-index") + Mono updateAlbumOwnerShip( + @RequestMemberId + String memberId, + + @ULID + @Parameter(description = "앨범 ID", example = "test_album_id") + @PathVariable + String albumId, + + @Valid + @RequestBody + AlbumUpdateOwnershipRequest request + ); + @Operation(summary = "앨범 삭제", description = "앨범을 삭제합니다.") @DeleteMapping("/{albumId}") Mono deleteAlbum( 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 6f746e31..ddba6c92 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 @@ -3,9 +3,9 @@ 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.AlbumUpdateRequest; +import kr.mafoo.photo.controller.dto.request.AlbumUpdateNameAndTypeRequest; +import kr.mafoo.photo.controller.dto.request.AlbumUpdateOwnershipRequest; import kr.mafoo.photo.controller.dto.response.AlbumResponse; -import kr.mafoo.photo.domain.AlbumType; import kr.mafoo.photo.service.AlbumService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.RestController; @@ -15,14 +15,15 @@ @RequiredArgsConstructor @RestController public class AlbumController implements AlbumApi { + private final AlbumService albumService; @Override - public Flux getAlbums( + public Flux getAlbumListByMember( String memberId ) { return albumService - .findAllByOwnerMemberId(memberId) + .findAlbumListByMemberId(memberId) .map(AlbumResponse::fromEntity); } @@ -32,7 +33,7 @@ public Mono getAlbum( String albumId ) { return albumService - .findByAlbumId(albumId, memberId) + .findAlbumById(albumId, memberId) .map(AlbumResponse::fromEntity); } @@ -41,36 +42,42 @@ public Mono createAlbum( String memberId, AlbumCreateRequest request ){ - AlbumType type = AlbumType.valueOf(request.type()); return albumService - .createNewAlbum(memberId, request.name(), type) + .addAlbum(memberId, request.name(), request.type()) .map(AlbumResponse::fromEntity); } + // tmp. deprecated @Override - public Mono updateAlbum( + public Mono updateAlbumDisplayIndex( String memberId, String albumId, - AlbumUpdateRequest request + AlbumUpdateDisplayIndexRequest request ) { - AlbumType albumType = AlbumType.valueOf(request.type()); - return albumService - .updateAlbumName(albumId, request.name(), memberId) - .then(albumService.updateAlbumType(albumId, albumType, memberId)) - .map(AlbumResponse::fromEntity); + return Mono.empty(); } @Override - public Mono updateAlbumDisplayIndex( + public Mono updateAlbumNameAndType( String memberId, String albumId, - AlbumUpdateDisplayIndexRequest request + AlbumUpdateNameAndTypeRequest request ) { return albumService - .moveAlbumDisplayIndex(albumId, memberId, request.newDisplayIndex()) + .modifyAlbumNameAndType(albumId, request.name(), request.type(), memberId) .map(AlbumResponse::fromEntity); } + @Override + public Mono updateAlbumOwnerShip( + String memberId, + String albumId, + AlbumUpdateOwnershipRequest request + ) { + return albumService + .modifyAlbumOwnership(albumId, request.newOwnerMemberId(), memberId) + .map(AlbumResponse::fromEntity); + } @Override public Mono deleteAlbum( @@ -78,7 +85,7 @@ public Mono deleteAlbum( String albumId ){ return albumService - .deleteAlbumById(albumId, memberId); + .removeAlbum(albumId, memberId); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateNameAndTypeRequest.java similarity index 69% rename from photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateRequest.java rename to photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateNameAndTypeRequest.java index d54470d7..23af45fe 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateNameAndTypeRequest.java @@ -3,18 +3,18 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import kr.mafoo.photo.annotation.MatchEnum; -import kr.mafoo.photo.domain.AlbumType; +import kr.mafoo.photo.domain.enums.AlbumType; import org.hibernate.validator.constraints.Length; -@Schema(description = "앨범 수정 요청") -public record AlbumUpdateRequest( +@Schema(description = "앨범 속성 변경 요청") +public record AlbumUpdateNameAndTypeRequest( @NotBlank @Length(min = 1, max = 100) @Schema(description = "앨범 이름", example = "시금치파슷하") String name, @MatchEnum(enumClass = AlbumType.class) - @Schema(description = "앨범 타입") + @Schema(description = "앨범 종류", example = "HEART") String type ) { } diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateOwnershipRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateOwnershipRequest.java new file mode 100644 index 00000000..4c99f010 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/AlbumUpdateOwnershipRequest.java @@ -0,0 +1,12 @@ +package kr.mafoo.photo.controller.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import kr.mafoo.photo.annotation.ULID; + +@Schema(description = "앨범 소유자 변경 요청") +public record AlbumUpdateOwnershipRequest( + @ULID + @Schema(description = "사용자 ID", example = "test_member_id") + String newOwnerMemberId +) { +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java index ec92d886..4688f41c 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/AlbumResponse.java @@ -12,7 +12,7 @@ public record AlbumResponse( @Schema(description = "앨범 이름", example = "야뿌들") String name, - @Schema(description = "앨범 종류", example = "TYPE_B") + @Schema(description = "앨범 종류", example = "HEART") AlbumType type, @Schema(description = "앨범 내 사진 수", example = "6") diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java new file mode 100644 index 00000000..ac8758f3 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java @@ -0,0 +1,38 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.AlbumEntity; +import kr.mafoo.photo.domain.enums.AlbumType; +import kr.mafoo.photo.repository.AlbumRepository; +import kr.mafoo.photo.util.IdGenerator; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +@RequiredArgsConstructor +public class AlbumCommand { + + private final AlbumRepository albumRepository; + + public Mono addAlbum(String albumName, String albumType, String ownerMemberId) { + return albumRepository.save( + AlbumEntity.newAlbum(IdGenerator.generate(), albumName, AlbumType.valueOf(albumType), ownerMemberId) + ); + } + + public Mono modifyAlbumNameAndType(AlbumEntity album, String newAlbumName, String newAlbumType) { + return albumRepository.save(album + .updateName(newAlbumName) + .updateType(AlbumType.valueOf(newAlbumType)) + ); + } + + public Mono modifyAlbumOwnership(AlbumEntity album, String newOwnerMemberId) { + return albumRepository.save(album.updateOwnerMemberId(newOwnerMemberId)); + } + + public Mono removeAlbum(AlbumEntity album) { + return albumRepository.delete(album); + } + +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java index 153762a6..731fa302 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java @@ -21,7 +21,7 @@ public Mono verifyOwnershipOrAccessPermission(String albumId, Strin sharedMemberQuery.findByAlbumIdAndMemberId(albumId, requestMemberId) .flatMap(sharedAlbumMember -> checkAccessPermission(sharedAlbumMember.getPermissionLevel(), permissionLevel) - ).then(albumQuery.findById(albumId)) + ).then(albumQuery.findById(albumId)) // TODO : findById 중복 실행 제거 필요 ); } 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 7e39d596..fbabbc22 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 @@ -4,168 +4,55 @@ import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; import kr.mafoo.photo.domain.AlbumEntity; -import kr.mafoo.photo.domain.enums.AlbumType; -import kr.mafoo.photo.exception.AlbumIndexIsSameException; -import kr.mafoo.photo.exception.AlbumNotFoundException; -import kr.mafoo.photo.exception.PermissionNotAllowedException; -import kr.mafoo.photo.repository.AlbumRepository; -import kr.mafoo.photo.util.IdGenerator; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import static kr.mafoo.photo.domain.PermissionType.FULL_ACCESS; - @RequiredArgsConstructor @Service public class AlbumService { - private final AlbumRepository albumRepository; - private final PermissionService permissionService; - - @Transactional - public Mono createNewAlbum(String ownerMemberId, String albumName, AlbumType albumType) { - AlbumEntity albumEntity = AlbumEntity.newAlbum(IdGenerator.generate(), albumName, albumType, ownerMemberId); - return albumRepository - .pushDisplayIndex(ownerMemberId) //전부 인덱스 한칸 밀기 - .then(albumRepository.save(albumEntity)); - } - @Transactional - public Mono moveAlbumDisplayIndex(String albumId, String requestMemberId, Integer displayIndex) { - return findByAlbumId(albumId, requestMemberId) - .flatMap(album -> { - Integer currentDisplayIndex = album.getDisplayIndex(); - Mono pushAlbumIndexPublisher; - if(displayIndex < currentDisplayIndex) { - pushAlbumIndexPublisher = albumRepository - .pushDisplayIndexBetween(requestMemberId, displayIndex, currentDisplayIndex -1); - } else if(displayIndex > currentDisplayIndex) { - pushAlbumIndexPublisher = albumRepository - .popDisplayIndexBetween(requestMemberId, currentDisplayIndex + 1, displayIndex); - } else { - pushAlbumIndexPublisher = Mono.error(new AlbumIndexIsSameException()); - } - return pushAlbumIndexPublisher.then(Mono.defer(() -> { - album.setDisplayIndex(displayIndex); - return albumRepository.save(album); - })); - }); - } + private final AlbumQuery albumQuery; + private final AlbumCommand albumCommand; - public Flux findAllByOwnerMemberId(String ownerMemberId) { - return albumRepository.findAllByOwnerMemberIdOrderByDisplayIndex(ownerMemberId); - } + private final AlbumPermissionQuery albumPermissionQuery; - public Mono findByAlbumId(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 Mono.just(albumEntity); - } - }); + @Transactional(readOnly = true) + public Flux findAlbumListByMemberId(String memberId) { + return null; } - @Transactional - public Mono deleteAlbumById(String albumId, String requestMemberId) { - return findByAlbumId(albumId, requestMemberId) - .flatMap(albumEntity -> - albumRepository - .deleteById(albumId) - .then(albumRepository.popDisplayIndexBetween( - requestMemberId, albumEntity.getDisplayIndex(), Integer.MAX_VALUE)) - ); + @Transactional(readOnly = true) + public Mono findAlbumById(String albumId, String memberId) { + return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, memberId, VIEW_ACCESS) + .then(albumQuery.findById(albumId)); } @Transactional - public Mono updateAlbumName(String albumId, String albumName, String requestMemberId) { - return findByAlbumId(albumId, requestMemberId) - .flatMap(albumEntity -> albumRepository.save(albumEntity.updateName(albumName))); + public Mono addAlbum(String albumName, String albumType, String requestMemberId) { + return albumCommand.addAlbum(albumName, albumType, requestMemberId); } @Transactional - public Mono updateAlbumType(String albumId, AlbumType albumType, String requestMemberId) { - return findByAlbumId(albumId, requestMemberId) - .flatMap(albumEntity -> albumRepository.save(albumEntity.updateType(albumType))); + public Mono modifyAlbumNameAndType(String albumId, String newAlbumName, String newAlbumType, String requestMemberId) { + return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .flatMap(album -> albumCommand.modifyAlbumNameAndType(album, newAlbumName, newAlbumType)); } @Transactional -// public Mono increaseAlbumPhotoCount(String albumId) { -// return albumRepository -// .findById(albumId) -// .switchIfEmpty(Mono.error(new AlbumNotFoundException())) -// .flatMap(albumEntity -> albumRepository.save(albumEntity.increasePhotoCount()).then()); -// } - -// @Transactional -// public Mono decreaseAlbumPhotoCount(String albumId) { - -// if (albumId == null) { -// return Mono.empty(); -// } - -// return albumRepository -// .findById(albumId) -// .switchIfEmpty(Mono.error(new AlbumNotFoundException())) -// .flatMap(albumEntity -> albumRepository.save(albumEntity.decreasePhotoCount()).then()); -// } - -// public Mono checkAlbumFullAccessPermission(String albumId, String requestMemberId) { -// return albumRepository.findById(albumId) -// .switchIfEmpty(Mono.error(new AlbumNotFoundException())) -// .flatMap(albumEntity -> { -// if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { -// return permissionService.checkPermissionExistsByType(albumId, requestMemberId, FULL_ACCESS) -// .flatMap(isPermitted -> { -// if (!isPermitted) { -// return Mono.error(new PermissionNotAllowedException()); -// } else { -// return Mono.just(albumEntity); -// } -// }); -// } else { -// return Mono.just(albumEntity); -// } -// }); -// } - -// public Mono checkAlbumReadPermission(String albumId, String requestMemberId) { -// return albumRepository.findById(albumId) -// .switchIfEmpty(Mono.error(new AlbumNotFoundException())) -// .flatMap(albumEntity -> { -// if (!albumEntity.getOwnerMemberId().equals(requestMemberId)) { -// return permissionService.checkPermissionExists(albumId, requestMemberId) -// .flatMap(isPermitted -> { -// if (!isPermitted) { -// return Mono.error(new PermissionNotAllowedException()); -// } else { -// return Mono.just(albumEntity); -// } -// }); -// } else { -// return Mono.just(albumEntity); -// } -// }); - - @Transactional - public Mono increaseAlbumPhotoCount(String albumId, int count, String requestMemberId) { - return findByAlbumId(albumId, requestMemberId) - .flatMap(albumEntity -> albumRepository.save(albumEntity.increasePhotoCount(count))); + public Mono modifyAlbumOwnership(String albumId, String newOwnerMemberId, String requestMemberId) { + return albumPermissionQuery.verifyOwnership(albumId, requestMemberId) + .flatMap(album -> albumCommand.modifyAlbumOwnership(album, newOwnerMemberId) + // TODO : 앨범 내부 사진 소유자를 새로운 앨범 소유자로 변경 + ); } @Transactional - 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))); - + public Mono removeAlbum(String albumId, String requestMemberId) { + return albumPermissionQuery.verifyOwnership(albumId, requestMemberId) + .flatMap(albumCommand::removeAlbum); } -} +} \ No newline at end of file From 21471725bafb44eac6d985288d27d19e2cee848e Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 19:12:10 +0900 Subject: [PATCH 23/29] fix: share member api related errors --- .../controller/SharedMemberController.java | 2 +- .../mafoo/photo/service/SharedMemberQuery.java | 7 +++++++ .../photo/service/SharedMemberService.java | 17 ++++++----------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java index eb731c7f..02ee4df0 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/SharedMemberController.java @@ -50,6 +50,6 @@ public Mono deleteSharedMember( String memberId, String sharedMemberId ){ - return sharedMemberService.removeSharedMember(memberId, sharedMemberId); + return sharedMemberService.removeSharedMember(sharedMemberId, memberId); } } 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 068e55c0..4e9e6106 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,6 +1,7 @@ package kr.mafoo.photo.service; import kr.mafoo.photo.domain.SharedMemberEntity; +import kr.mafoo.photo.exception.SharedMemberDuplicatedException; import kr.mafoo.photo.exception.SharedMemberNotFoundException; import kr.mafoo.photo.repository.SharedMemberRepository; import lombok.RequiredArgsConstructor; @@ -29,4 +30,10 @@ public Mono findByAlbumIdAndMemberId(String albumId, String .switchIfEmpty(Mono.error(new SharedMemberNotFoundException())); } + public Mono checkDuplicateByAlbumIdAndMemberId(String albumId, String memberId) { + return sharedMemberRepository.findByAlbumIdAndMemberId(albumId, memberId) + .switchIfEmpty(Mono.empty()) + .flatMap(existingMember -> Mono.error(new SharedMemberDuplicatedException())); + } + } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java index 47a9f8b9..e5042970 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/SharedMemberService.java @@ -5,8 +5,6 @@ import kr.mafoo.photo.domain.SharedMemberEntity; import kr.mafoo.photo.domain.enums.ShareStatus; -import kr.mafoo.photo.exception.SharedMemberDuplicatedException; -import kr.mafoo.photo.exception.SharedMemberNotFoundException; import kr.mafoo.photo.exception.SharedMemberPermissionDeniedException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -20,16 +18,13 @@ public class SharedMemberService { private final SharedMemberQuery sharedMemberQuery; private final SharedMemberCommand sharedMemberCommand; - private final AlbumPermissionQuery albumPermissionQuery; + private final AlbumPermissionVerifier albumPermissionVerifier; @Transactional public Mono addSharedMember(String albumId, String permissionLevel, String sharingMemberId, String requestMemberId) { - return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) - .then(sharedMemberQuery.findByAlbumIdAndMemberId(albumId, sharingMemberId) - .onErrorResume(SharedMemberNotFoundException.class, ex -> - sharedMemberCommand.addSharedMember(albumId, permissionLevel, sharingMemberId) - ) - .flatMap(existingMember -> Mono.error(new SharedMemberDuplicatedException())) + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .then(sharedMemberQuery.checkDuplicateByAlbumIdAndMemberId(albumId, sharingMemberId) + .then(sharedMemberCommand.addSharedMember(albumId, permissionLevel, sharingMemberId)) ); } @@ -40,7 +35,7 @@ public Mono removeSharedMember(String sharedMemberId, String requestMember if (isSharedMemberSelfRequest(sharedMember, requestMemberId) && !isPendingStatus(sharedMember.getShareStatus())) { return sharedMemberCommand.removeSharedMember(sharedMember); } else { - return albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) + return albumPermissionVerifier.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) .then(sharedMemberCommand.removeSharedMember(sharedMember)); } }); @@ -61,7 +56,7 @@ public Mono modifySharedMemberShareStatus(String sharedMembe @Transactional public Mono modifySharedMemberPermissionLevel(String sharedMemberId, String newPermissionLevel, String requestMemberId) { return sharedMemberQuery.findBySharedMemberId(sharedMemberId) - .flatMap(sharedMember -> albumPermissionQuery.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) + .flatMap(sharedMember -> albumPermissionVerifier.verifyOwnership(sharedMember.getAlbumId(), requestMemberId) .then(sharedMemberCommand.modifySharedMemberPermissionLevel(sharedMember, newPermissionLevel)) ); } From 78f2de0b39f1682c0baf16b9a5593c16d9a6c9cc Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 19:17:04 +0900 Subject: [PATCH 24/29] fix: fix album permission verifier errors --- ...uery.java => AlbumPermissionVerifier.java} | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/service/{AlbumPermissionQuery.java => AlbumPermissionVerifier.java} (61%) diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java similarity index 61% rename from photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java rename to photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java index 731fa302..54910612 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionQuery.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumPermissionVerifier.java @@ -1,27 +1,36 @@ package kr.mafoo.photo.service; +import static kr.mafoo.photo.domain.enums.ShareStatus.ACCEPTED; + import kr.mafoo.photo.domain.AlbumEntity; import kr.mafoo.photo.domain.enums.PermissionLevel; +import kr.mafoo.photo.domain.enums.ShareStatus; import kr.mafoo.photo.exception.AlbumOwnerMismatchException; +import kr.mafoo.photo.exception.SharedMemberNotFoundException; import kr.mafoo.photo.exception.SharedMemberPermissionDeniedException; +import kr.mafoo.photo.exception.SharedMemberStatusNotAcceptedException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @Service @RequiredArgsConstructor -public class AlbumPermissionQuery { +public class AlbumPermissionVerifier { private final AlbumQuery albumQuery; private final SharedMemberQuery sharedMemberQuery; public Mono verifyOwnershipOrAccessPermission(String albumId, String requestMemberId, PermissionLevel permissionLevel) { return verifyOwnership(albumId, requestMemberId) - .onErrorResume(AlbumOwnerMismatchException.class, ex -> + .onErrorResume(AlbumOwnerMismatchException.class, ownerEx -> sharedMemberQuery.findByAlbumIdAndMemberId(albumId, requestMemberId) + .onErrorResume(SharedMemberNotFoundException.class, sharedEx -> + Mono.error(new SharedMemberPermissionDeniedException()) + ) .flatMap(sharedAlbumMember -> - checkAccessPermission(sharedAlbumMember.getPermissionLevel(), permissionLevel) - ).then(albumQuery.findById(albumId)) // TODO : findById 중복 실행 제거 필요 + checkShareStatus(sharedAlbumMember.getShareStatus()) + .then(checkAccessPermission(sharedAlbumMember.getPermissionLevel(), permissionLevel)) + ).then(albumQuery.findById(albumId)) // FIXME : findById 중복 실행 제거 필요 ); } @@ -39,6 +48,13 @@ private Mono checkOwnership(String ownerMemberId, String requestMemberId) return Mono.empty(); } + private Mono checkShareStatus(ShareStatus status) { + if (!status.equals(ACCEPTED)) { + return Mono.error(new SharedMemberStatusNotAcceptedException()); + } + return Mono.empty(); + } + private Mono checkAccessPermission(PermissionLevel currentLevel, PermissionLevel requiredLevel) { if (currentLevel.getTier() < requiredLevel.getTier()) { return Mono.error(new SharedMemberPermissionDeniedException()); From 7b2ed7ba24478e5c7c719c15bdbc2c979573d359 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 19:36:03 +0900 Subject: [PATCH 25/29] feat: add permission checking logic for album apis --- .../java/kr/mafoo/photo/api/AlbumApi.java | 32 +++++++++---------- .../photo/controller/AlbumController.java | 16 +++++----- .../kr/mafoo/photo/service/AlbumCommand.java | 8 +++++ .../kr/mafoo/photo/service/AlbumService.java | 10 +++--- 4 files changed, 37 insertions(+), 29 deletions(-) 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 76828012..239066b2 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 @@ -66,24 +66,24 @@ Mono updateAlbumNameAndType( AlbumUpdateNameAndTypeRequest request ); - @Operation(summary = "[DEPRECATED] 앨범 표시 순서 변경", description = "앨범의 표시 순서를 변경합니다.") - @PatchMapping("/{albumId}/display-index") - Mono updateAlbumDisplayIndex( - @RequestMemberId - String memberId, - - @ULID - @Parameter(description = "앨범 ID", example = "test_album_id") - @PathVariable - String albumId, - - @Valid - @RequestBody - AlbumUpdateDisplayIndexRequest request - ); +// @Operation(summary = "[DEPRECATED] 앨범 표시 순서 변경", description = "앨범의 표시 순서를 변경합니다.") +// @PatchMapping("/{albumId}/display-index") +// Mono updateAlbumDisplayIndex( +// @RequestMemberId +// String memberId, +// +// @ULID +// @Parameter(description = "앨범 ID", example = "test_album_id") +// @PathVariable +// String albumId, +// +// @Valid +// @RequestBody +// AlbumUpdateDisplayIndexRequest request +// ); @Operation(summary = "앨범 소유자 변경", description = "앨범의 소유자를 변경합니다.") - @PatchMapping("/{albumId}/display-index") + @PatchMapping("/{albumId}/ownership") Mono updateAlbumOwnerShip( @RequestMemberId String memberId, 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 ddba6c92..0b5f2986 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 @@ -48,14 +48,14 @@ public Mono createAlbum( } // tmp. deprecated - @Override - public Mono updateAlbumDisplayIndex( - String memberId, - String albumId, - AlbumUpdateDisplayIndexRequest request - ) { - return Mono.empty(); - } +// @Override +// public Mono updateAlbumDisplayIndex( +// String memberId, +// String albumId, +// AlbumUpdateDisplayIndexRequest request +// ) { +// return Mono.empty(); +// } @Override public Mono updateAlbumNameAndType( diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java index ac8758f3..743b15c7 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/AlbumCommand.java @@ -31,6 +31,14 @@ public Mono modifyAlbumOwnership(AlbumEntity album, String newOwner return albumRepository.save(album.updateOwnerMemberId(newOwnerMemberId)); } + public Mono increaseAlbumPhotoCount(AlbumEntity album, int count) { + return albumRepository.save(album.increasePhotoCount(count)); + } + + public Mono decreaseAlbumPhotoCount(AlbumEntity album, int count) { + return albumRepository.save(album.decreasePhotoCount(count)); + } + public Mono removeAlbum(AlbumEntity album) { return albumRepository.delete(album); } 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 fbabbc22..e67ae67a 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 @@ -17,7 +17,7 @@ public class AlbumService { private final AlbumQuery albumQuery; private final AlbumCommand albumCommand; - private final AlbumPermissionQuery albumPermissionQuery; + private final AlbumPermissionVerifier albumPermissionVerifier; @Transactional(readOnly = true) public Flux findAlbumListByMemberId(String memberId) { @@ -26,7 +26,7 @@ public Flux findAlbumListByMemberId(String memberId) { @Transactional(readOnly = true) public Mono findAlbumById(String albumId, String memberId) { - return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, memberId, VIEW_ACCESS) + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, memberId, VIEW_ACCESS) .then(albumQuery.findById(albumId)); } @@ -37,13 +37,13 @@ public Mono addAlbum(String albumName, String albumType, String req @Transactional public Mono modifyAlbumNameAndType(String albumId, String newAlbumName, String newAlbumType, String requestMemberId) { - return albumPermissionQuery.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) .flatMap(album -> albumCommand.modifyAlbumNameAndType(album, newAlbumName, newAlbumType)); } @Transactional public Mono modifyAlbumOwnership(String albumId, String newOwnerMemberId, String requestMemberId) { - return albumPermissionQuery.verifyOwnership(albumId, requestMemberId) + return albumPermissionVerifier.verifyOwnership(albumId, requestMemberId) .flatMap(album -> albumCommand.modifyAlbumOwnership(album, newOwnerMemberId) // TODO : 앨범 내부 사진 소유자를 새로운 앨범 소유자로 변경 ); @@ -51,7 +51,7 @@ public Mono modifyAlbumOwnership(String albumId, String newOwnerMem @Transactional public Mono removeAlbum(String albumId, String requestMemberId) { - return albumPermissionQuery.verifyOwnership(albumId, requestMemberId) + return albumPermissionVerifier.verifyOwnership(albumId, requestMemberId) .flatMap(albumCommand::removeAlbum); } From 6d792d45ca95e4f2e11a4e6b7e0494d9789d1d25 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 20:47:38 +0900 Subject: [PATCH 26/29] feat: add permission checking logic for photo apis --- .../java/kr/mafoo/photo/api/PhotoApi.java | 22 +- .../photo/controller/PhotoController.java | 36 +-- ...> PhotoCreateBulkWithFileUrlsRequest.java} | 2 +- ....java => PhotoCreateWithQrUrlRequest.java} | 2 +- ...Request.java => PhotoSetAlbumRequest.java} | 4 +- ....java => PhotoUpdateBulkAlbumRequest.java} | 2 +- .../dto/response/PhotoResponse.java | 8 +- .../kr/mafoo/photo/service/PhotoCommand.java | 48 ++++ .../service/PhotoPermissionVerifier.java | 23 ++ .../kr/mafoo/photo/service/PhotoQuery.java | 39 +++ .../kr/mafoo/photo/service/PhotoService.java | 252 ++++++------------ 11 files changed, 234 insertions(+), 204 deletions(-) rename photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/{PhotoFileUrlUploadRequest.java => PhotoCreateBulkWithFileUrlsRequest.java} (92%) rename photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/{PhotoQrUploadRequest.java => PhotoCreateWithQrUrlRequest.java} (87%) rename photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/{PhotoUpdateAlbumIdRequest.java => PhotoSetAlbumRequest.java} (72%) rename photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/{PhotoBulkUpdateAlbumIdRequest.java => PhotoUpdateBulkAlbumRequest.java} (93%) create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/PhotoCommand.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/PhotoPermissionVerifier.java create mode 100644 photo-service/src/main/java/kr/mafoo/photo/service/PhotoQuery.java diff --git a/photo-service/src/main/java/kr/mafoo/photo/api/PhotoApi.java b/photo-service/src/main/java/kr/mafoo/photo/api/PhotoApi.java index 843c5cb6..9f344515 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/api/PhotoApi.java +++ b/photo-service/src/main/java/kr/mafoo/photo/api/PhotoApi.java @@ -21,7 +21,7 @@ public interface PhotoApi { @Operation(summary = "사진 조회", description = "사진 목록을 조회합니다.") @GetMapping - Flux getPhotos( + Flux getPhotoListByAlbum( @RequestMemberId String memberId, @@ -37,35 +37,35 @@ Flux getPhotos( @Operation(summary = "(수정 이전) QR 사진 업로드", description = "QR을 사용해 사진을 업로드합니다.") @PostMapping(value = "") - Mono uploadQrPhotoOriginal( + Mono createPhotoWithQrUrlOriginal( @RequestMemberId String memberId, @Valid @RequestBody - PhotoQrUploadRequest request + PhotoCreateWithQrUrlRequest request ); @Operation(summary = "QR 사진 업로드", description = "QR을 사용해 사진을 업로드합니다.") @PostMapping(value = "/qr") - Mono uploadQrPhoto( + Mono createPhotoWithQrUrl( @RequestMemberId String memberId, @Valid @RequestBody - PhotoQrUploadRequest request + PhotoCreateWithQrUrlRequest request ); @Operation(summary = "파일(url) 사진 n건 업로드", description = "파일(url)을 사용해 사진을 업로드합니다.") @PostMapping(value = "/file-urls") - Flux uploadFileUrlPhoto( + Flux createPhotoBulkWithFileUrls( @RequestMemberId String memberId, @Valid @RequestBody - PhotoFileUrlUploadRequest request + PhotoCreateBulkWithFileUrlsRequest request ); @Operation(summary = "사진 파일로 업로드", description = "사진을 직접 업로드합니다.") @@ -78,9 +78,9 @@ Flux uploadPhoto( Flux request ); - @Operation(summary = "사진 앨범 단건 수정", description = "사진 한 개를 다른 앨범으로 이동시킵니다.") + @Operation(summary = "사진 앨범 설정", description = "사진의 초기 앨범 정보를 설정합니다.") @PatchMapping(value = "/{photoId}/album") - Mono updatePhotoAlbum( + Mono setPhotoAlbum( @RequestMemberId String memberId, @@ -91,7 +91,7 @@ Mono updatePhotoAlbum( @Valid @RequestBody - PhotoUpdateAlbumIdRequest request + PhotoSetAlbumRequest request ); @Operation(summary = "사진 앨범 n건 수정", description = "사진 여러 개를 다른 앨범으로 이동시킵니다.") @@ -102,7 +102,7 @@ Flux updatePhotoBulkAlbum( @Valid @RequestBody - PhotoBulkUpdateAlbumIdRequest request + PhotoUpdateBulkAlbumRequest request ); @Operation(summary = "사진 표시 순서 변경", description = "사진의 표시 순서를 변경합니다.") 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 7859d638..26d7ce0e 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 @@ -17,43 +17,43 @@ public class PhotoController implements PhotoApi { private final PhotoService photoService; @Override - public Flux getPhotos( + public Flux getPhotoListByAlbum( String memberId, String albumId, String sort ){ return photoService - .findAllByAlbumId(albumId, memberId, sort) + .findPhotoListByAlbumId(albumId, memberId, sort) .map(PhotoResponse::fromEntity); } @Override - public Mono uploadQrPhotoOriginal( + public Mono createPhotoWithQrUrlOriginal( String memberId, - PhotoQrUploadRequest request + PhotoCreateWithQrUrlRequest request ){ return photoService - .createNewPhotoByQrUrl(request.qrUrl(), memberId) + .addPhotoWithQrUrl(request.qrUrl()) .map(PhotoResponse::fromEntity); } @Override - public Mono uploadQrPhoto( + public Mono createPhotoWithQrUrl( String memberId, - PhotoQrUploadRequest request + PhotoCreateWithQrUrlRequest request ){ return photoService - .createNewPhotoByQrUrl(request.qrUrl(), memberId) + .addPhotoWithQrUrl(request.qrUrl()) .map(PhotoResponse::fromEntity); } @Override - public Flux uploadFileUrlPhoto( + public Flux createPhotoBulkWithFileUrls( String memberId, - PhotoFileUrlUploadRequest request + PhotoCreateBulkWithFileUrlsRequest request ){ return photoService - .createNewPhotoFileUrls(request.fileUrls(), request.albumId(), memberId) + .addPhotoBulkWithFileUrls(request.fileUrls(), request.albumId(), memberId) .map(PhotoResponse::fromEntity); } @@ -65,23 +65,23 @@ public Flux uploadPhoto(String memberId, Flux request) } @Override - public Mono updatePhotoAlbum( + public Mono setPhotoAlbum( String memberId, String photoId, - PhotoUpdateAlbumIdRequest request + PhotoSetAlbumRequest request ){ return photoService - .updatePhotoAlbumId(photoId, request.albumId(), memberId) + .initPhotoAlbumId(photoId, request.albumId(), memberId) .map(PhotoResponse::fromEntity); } @Override public Flux updatePhotoBulkAlbum( String memberId, - PhotoBulkUpdateAlbumIdRequest request + PhotoUpdateBulkAlbumRequest request ){ return photoService - .updatePhotoBulkAlbumId(request.photoIds(), request.albumId(), memberId) + .modifyPhotoBulkAlbumId(request.photoIds(), request.albumId(), memberId) .map(PhotoResponse::fromEntity); } @@ -92,7 +92,7 @@ public Mono updatePhotoDisplayIndex( PhotoUpdateDisplayIndexRequest request ) { return photoService - .updatePhotoDisplayIndex(photoId, request.newDisplayIndex(), memberId) + .modifyPhotoDisplayIndex(photoId, request.newDisplayIndex(), memberId) .map(PhotoResponse::fromEntity); } @@ -102,6 +102,6 @@ public Mono deletePhoto( String photoId ){ return photoService - .deletePhotoById(photoId, memberId); + .removePhoto(photoId, memberId); } } 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/PhotoCreateBulkWithFileUrlsRequest.java similarity index 92% rename from photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoFileUrlUploadRequest.java rename to photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoCreateBulkWithFileUrlsRequest.java index 442e8b9a..a7c686b6 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/PhotoCreateBulkWithFileUrlsRequest.java @@ -5,7 +5,7 @@ import kr.mafoo.photo.annotation.ULID; @Schema(description = "파일(url) 사진 n건 업로드 요청") -public record PhotoFileUrlUploadRequest( +public record PhotoCreateBulkWithFileUrlsRequest( @ArraySchema( schema = @Schema(description = "파일 URL 목록"), arraySchema = @Schema(example = "[\"file_url_1\", \"file_url_2\", \"file_url_3\"]") diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoQrUploadRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoCreateWithQrUrlRequest.java similarity index 87% rename from photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoQrUploadRequest.java rename to photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoCreateWithQrUrlRequest.java index 62322971..080bb7fb 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoQrUploadRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoCreateWithQrUrlRequest.java @@ -4,7 +4,7 @@ import org.hibernate.validator.constraints.URL; @Schema(description = "QR 사진 업로드 요청") -public record PhotoQrUploadRequest( +public record PhotoCreateWithQrUrlRequest( @URL @Schema(description = "QR URL", example = "qr_url") String qrUrl diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateAlbumIdRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoSetAlbumRequest.java similarity index 72% rename from photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateAlbumIdRequest.java rename to photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoSetAlbumRequest.java index 81ab4847..9a4b4825 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateAlbumIdRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoSetAlbumRequest.java @@ -3,8 +3,8 @@ import io.swagger.v3.oas.annotations.media.Schema; import kr.mafoo.photo.annotation.ULID; -@Schema(description = "사진 앨범 수정 요청") -public record PhotoUpdateAlbumIdRequest( +@Schema(description = "사진 앨범 설정 요청") +public record PhotoSetAlbumRequest( @ULID @Schema(description = "앨범 ID", example = "test_album_id") String albumId diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateBulkAlbumRequest.java similarity index 93% rename from photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java rename to photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateBulkAlbumRequest.java index 99cb7084..a70a17b7 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoBulkUpdateAlbumIdRequest.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/request/PhotoUpdateBulkAlbumRequest.java @@ -5,7 +5,7 @@ import kr.mafoo.photo.annotation.ULID; @Schema(description = "사진 n건 앨범 수정 요청") -public record PhotoBulkUpdateAlbumIdRequest( +public record PhotoUpdateBulkAlbumRequest( @ArraySchema( schema = @Schema(description = "사진 ID 목록"), diff --git a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java index 71ae531e..0e453853 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java +++ b/photo-service/src/main/java/kr/mafoo/photo/controller/dto/response/PhotoResponse.java @@ -16,10 +16,7 @@ public record PhotoResponse( BrandType brand, @Schema(description = "앨범 ID", example = "test_album_id") - String albumId, - - @Schema(description = "앨범 생성일") - String createdAt + String albumId ) { public static PhotoResponse fromEntity( PhotoEntity entity @@ -28,8 +25,7 @@ public static PhotoResponse fromEntity( entity.getPhotoId(), entity.getPhotoUrl(), entity.getBrand(), - entity.getAlbumId(), - entity.getCreatedAt().toString() + entity.getAlbumId() ); } } diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoCommand.java b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoCommand.java new file mode 100644 index 00000000..51b01858 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoCommand.java @@ -0,0 +1,48 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.PhotoEntity; +import kr.mafoo.photo.domain.enums.BrandType; +import kr.mafoo.photo.repository.PhotoRepository; +import kr.mafoo.photo.util.IdGenerator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Slf4j +@RequiredArgsConstructor +@Service +public class PhotoCommand { + + private final PhotoRepository photoRepository; + + public Mono addPhotoWithoutOwnerAndAlbum(String photoUrl, BrandType type) { + return photoRepository.save( + PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, type, null, 0, null) + ); + } + + public Mono addPhoto(String fileLink, BrandType type, String albumId, Integer displayIndex, String ownerMemberId) { + return photoRepository.save( + PhotoEntity.newPhoto(IdGenerator.generate(), fileLink, type, albumId, displayIndex, ownerMemberId) + ); + } + + public Mono modifyPhotoAlbumId(PhotoEntity photo, String albumId, Integer newDisplayIndex, String ownerMemberId) { + return photoRepository.save( + photo.updateAlbumId(albumId) + .updateOwnerMemberId(ownerMemberId) + .updateDisplayIndex(newDisplayIndex) + ); + } + + public Mono removePhoto(PhotoEntity photo) { + return popDisplayIndexGreaterThan(photo.getAlbumId(), photo.getDisplayIndex()) + .then(photoRepository.delete(photo)); + } + + public Mono popDisplayIndexGreaterThan(String albumId, int startIndex) { + return photoRepository.popDisplayIndexGreaterThan(albumId, startIndex); + } + +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoPermissionVerifier.java b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoPermissionVerifier.java new file mode 100644 index 00000000..e21a5f34 --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoPermissionVerifier.java @@ -0,0 +1,23 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.PhotoEntity; +import kr.mafoo.photo.domain.enums.PermissionLevel; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +@RequiredArgsConstructor +public class PhotoPermissionVerifier { + + private final PhotoQuery photoQuery; + private final AlbumPermissionVerifier albumPermissionVerifier; + + public Mono verifyAccessPermission(String photoId, String requestMemberId, PermissionLevel permissionLevel) { + return photoQuery.findByPhotoId(photoId) + .flatMap(photo -> albumPermissionVerifier.verifyOwnershipOrAccessPermission(photo.getAlbumId(), requestMemberId, permissionLevel) + .thenReturn(photo) + ); + } + +} diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/PhotoQuery.java b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoQuery.java new file mode 100644 index 00000000..2d918d2d --- /dev/null +++ b/photo-service/src/main/java/kr/mafoo/photo/service/PhotoQuery.java @@ -0,0 +1,39 @@ +package kr.mafoo.photo.service; + +import kr.mafoo.photo.domain.PhotoEntity; +import kr.mafoo.photo.exception.PhotoNotFoundException; +import kr.mafoo.photo.repository.PhotoRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +@RequiredArgsConstructor +@Service +public class PhotoQuery { + + private final PhotoRepository photoRepository; + + public Flux findAllByAlbumIdOrderByCreatedAtAsc(String albumId) { + return photoRepository.findAllByAlbumIdOrderByCreatedAtAsc(albumId) + .switchIfEmpty(Mono.error(new PhotoNotFoundException())); + } + + public Flux findAllByAlbumIdOrderByCreatedAtDesc(String albumId) { + return photoRepository.findAllByAlbumIdOrderByCreatedAtDesc(albumId) + .switchIfEmpty(Mono.error(new PhotoNotFoundException())); + } + + public Flux findAllByAlbumIdOrderByDisplayIndexDesc(String albumId) { + return photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId) + .switchIfEmpty(Mono.error(new PhotoNotFoundException())); + } + + public Mono findByPhotoId(String photoId) { + return photoRepository.findById(photoId) + .switchIfEmpty(Mono.error(new PhotoNotFoundException())); + } + +} 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 2de40a03..d7fc0cc4 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 @@ -4,11 +4,9 @@ import static kr.mafoo.photo.domain.enums.PermissionLevel.VIEW_ACCESS; import kr.mafoo.photo.domain.enums.BrandType; -import kr.mafoo.photo.domain.enums.PermissionLevel; import kr.mafoo.photo.domain.PhotoEntity; import kr.mafoo.photo.exception.PhotoDisplayIndexIsSameException; import kr.mafoo.photo.exception.PhotoDisplayIndexNotValidException; -import kr.mafoo.photo.exception.PhotoNotFoundException; import kr.mafoo.photo.repository.PhotoRepository; import kr.mafoo.photo.util.IdGenerator; import lombok.RequiredArgsConstructor; @@ -25,51 +23,67 @@ import java.util.concurrent.atomic.AtomicInteger; - @Slf4j @RequiredArgsConstructor @Service public class PhotoService { - private final PhotoRepository photoRepository; - private final AlbumService albumService; + private final PhotoQuery photoQuery; + private final PhotoCommand photoCommand; + + private final PhotoPermissionVerifier photoPermissionVerifier; + + private final AlbumQuery albumQuery; + private final AlbumCommand albumCommand; + + private final AlbumPermissionVerifier albumPermissionVerifier; + private final QrService qrService; private final ObjectStorageService objectStorageService; - @Transactional - public Mono createNewPhotoByQrUrl(String qrUrl, String requestMemberId) { - return qrService - .getFileFromQrUrl(qrUrl) - .flatMap(fileDto -> objectStorageService.uploadFile(fileDto.fileByte()) - .flatMap(photoUrl -> createNewPhoto(photoUrl, fileDto.type(), requestMemberId)) - ); - } + // FIXME : 추후 제거 필요 + private final PhotoRepository photoRepository; - @Transactional - public Flux createNewPhotoFileUrls(String[] fileUrls, String albumId, String requestMemberId) { - return albumService.findByAlbumId(albumId, requestMemberId) - .flatMapMany(albumEntity -> { - AtomicInteger displayIndex = new AtomicInteger(albumEntity.getPhotoCount()); + @Transactional(readOnly = true) + public Flux findPhotoListByAlbumId(String albumId, String requestMemberId, String sort) { + String sortMethod = (sort == null) ? "CUSTOM" : sort.toUpperCase(); - return Flux.fromArray(fileUrls) - .concatMap(fileUrl -> - createNewPhotoFileUrl(fileUrl, BrandType.EXTERNAL, albumId, displayIndex.getAndIncrement(), requestMemberId) - ); - }); + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, VIEW_ACCESS) + .thenMany( + switch (sortMethod) { + case "ASC" -> photoQuery.findAllByAlbumIdOrderByCreatedAtAsc(albumId); + case "DESC" -> photoQuery.findAllByAlbumIdOrderByCreatedAtDesc(albumId); + case "CUSTOM" -> photoQuery.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); + default -> photoQuery.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); + } + ); } - 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)); - }); + @Transactional + public Mono addPhotoWithQrUrl(String qrUrl) { + return qrService + .getFileFromQrUrl(qrUrl) + .flatMap(fileDto -> objectStorageService.uploadFile(fileDto.fileByte()) + .flatMap(photoUrl -> photoCommand.addPhotoWithoutOwnerAndAlbum(photoUrl, fileDto.type())) + ); } - private Mono createNewPhoto(String photoUrl, BrandType type, String requestMemberId) { - PhotoEntity photoEntity = PhotoEntity.newPhoto(IdGenerator.generate(), photoUrl, type, null, 0, requestMemberId); - return photoRepository.save(photoEntity); + @Transactional + public Flux addPhotoBulkWithFileUrls(String[] fileUrls, String albumId, String requestMemberId) { + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .flatMapMany(album -> { + AtomicInteger displayIndex = new AtomicInteger(album.getPhotoCount()); + + return Flux.fromArray(fileUrls) + .concatMap(fileUrl -> objectStorageService.setObjectPublicRead(fileUrl) + .flatMap(fileLink -> photoCommand.addPhoto(fileLink, BrandType.EXTERNAL, albumId, displayIndex.getAndIncrement(), album.getOwnerMemberId())) + ) + .collectList() + .flatMapMany(addedPhotos -> + albumCommand.increaseAlbumPhotoCount(album, addedPhotos.size()) + .thenMany(Flux.fromIterable(addedPhotos)) + ); + }); } @Transactional @@ -98,146 +112,46 @@ public Flux uploadPhoto(Flux files, String requestMemberI ).sequential(); } -// @Transactional(readOnly = true) -// public Flux findAllByAlbumId(String albumId, String requestMemberId) { -// return albumService.checkAlbumReadPermission(albumId, requestMemberId) -// .flatMapMany(albumEntity -> handleFindAllByAlbumId(albumEntity.getId())); -// } - -// private Flux handleFindAllByAlbumId(String albumId) { -// return photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); - - public Flux findAllByAlbumId(String albumId, String requestMemberId, String sort) { - String sortMethod = (sort == null) ? "CUSTOM" : sort.toUpperCase(); - - return albumService.findByAlbumId(albumId, requestMemberId) - .thenMany( - switch (sortMethod) { - case "ASC" -> photoRepository.findAllByAlbumIdOrderByCreatedAtAsc(albumId); - case "DESC" -> photoRepository.findAllByAlbumIdOrderByCreatedAtDesc(albumId); - default -> photoRepository.findAllByAlbumIdOrderByDisplayIndexDesc(albumId); - } - ); - } - - public Mono findByPhotoId(String photoId, String requestMemberId) { - return photoRepository - .findById(photoId) - .switchIfEmpty(Mono.error(new PhotoNotFoundException())) -// .flatMap(photoEntity -> albumService -// .checkAlbumFullAccessPermission(photoEntity.getAlbumId(), requestMemberId) -// .flatMap(albumEntity -> handleDeletePhotoById(photoEntity))); -// } - -// private Mono handleDeletePhotoById(PhotoEntity photoEntity) { -// return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId()) -// .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) -// .then(photoRepository.deleteById(photoEntity.getPhotoId())); - - .flatMap(photoEntity -> { - if (!photoEntity.hasOwnerMemberId()) { - return photoRepository.save(photoEntity.updateOwnerMemberId(requestMemberId)); - } - else if (!photoEntity.getOwnerMemberId().equals(requestMemberId)) { - // 내 사진이 아니면 그냥 없는 사진 처리 - return Mono.error(new PhotoNotFoundException()); - } else { - 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)) - ); + public Mono initPhotoAlbumId(String photoId, String albumId, String requestMemberId) { + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .flatMap(album -> albumCommand.increaseAlbumPhotoCount(album, 1)) + .flatMap(album -> photoQuery.findByPhotoId(photoId) + .flatMap(photo -> photoCommand.modifyPhotoAlbumId(photo, albumId, album.getPhotoCount()-1, album.getOwnerMemberId())) + ); } @Transactional - public Flux updatePhotoBulkAlbumId(String[] photoIds, String albumId, String requestMemberId) { - return Flux.fromArray(photoIds) - .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.getAlbumId() == null) { -// if (!photoEntity.hasOwnerMemberId()) { -// photoEntity.updateOwnerMemberId(requestMemberId); -// } - -// return albumService.checkAlbumFullAccessPermission(albumId, requestMemberId) -// .flatMap(albumEntity -> photoRepository.save(photoEntity.updateAlbumId(albumId))); -// } - -// return albumService.checkAlbumFullAccessPermission(photoEntity.getAlbumId(), requestMemberId) -// .flatMap(previousAlbum -> albumService.checkAlbumFullAccessPermission(albumId, requestMemberId) -// .flatMap(newAlbum -> handleUpdatePhotoAlbumId(photoEntity, newAlbum))); -// }); - 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, 1, requestMemberId)) - .then(photoRepository.save( - photoEntity - .updateAlbumId(albumId) - .updateDisplayIndex(albumEntity.getPhotoCount()) - )) + public Flux modifyPhotoBulkAlbumId(String[] photoIds, String albumId, String requestMemberId) { + return albumPermissionVerifier.verifyOwnershipOrAccessPermission(albumId, requestMemberId, FULL_ACCESS) + .flatMapMany(newAlbum -> { + AtomicInteger displayIndex = new AtomicInteger(newAlbum.getPhotoCount()); + + return Flux.fromArray(photoIds) + .concatMap(photoId -> photoQuery.findByPhotoId(photoId) + .flatMap(photo -> albumPermissionVerifier.verifyOwnershipOrAccessPermission(photo.getAlbumId(), requestMemberId, FULL_ACCESS) + .flatMap(oldAlbum -> albumCommand.decreaseAlbumPhotoCount(oldAlbum, 1)) + .then(photoCommand.popDisplayIndexGreaterThan(photo.getAlbumId(), photo.getDisplayIndex()) + .thenReturn(photo) ) - ); - } - - private Mono handleUpdatePhotoAlbumId(PhotoEntity photoEntity, AlbumEntity albumEntity) { - return albumService.decreaseAlbumPhotoCount(photoEntity.getAlbumId()) - .then(photoRepository.popDisplayIndexGreaterThan(photoEntity.getAlbumId(), photoEntity.getDisplayIndex())) - .then(albumService.increaseAlbumPhotoCount(albumEntity.getId())) - .then(photoRepository.save( - photoEntity.updateAlbumId(albumEntity.getId()).updateDisplayIndex(albumEntity.getPhotoCount()) - )); + ) + .flatMap(photo -> photoCommand.modifyPhotoAlbumId(photo, albumId, displayIndex.getAndIncrement(), newAlbum.getOwnerMemberId()) + ) + ) + .collectList() + .flatMapMany(addedPhotos -> + albumCommand.increaseAlbumPhotoCount(newAlbum, addedPhotos.size()) + .thenMany(Flux.fromIterable(addedPhotos)) + ); + }); } + // FIXME : 추후 수정 필요 @Transactional - public Mono updatePhotoDisplayIndex(String photoId, Integer newIndex, String requestMemberId) { -// return photoRepository -// .findById(photoId) -// .switchIfEmpty(Mono.error(new PhotoNotFoundException())) -// .flatMap(photoEntity -> albumService.checkAlbumFullAccessPermission(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))); -// } -// })); - return findByPhotoId(photoId, requestMemberId) + public Mono modifyPhotoDisplayIndex(String photoId, Integer newIndex, String requestMemberId) { + return photoPermissionVerifier.verifyAccessPermission(photoId, requestMemberId, FULL_ACCESS) .flatMap(photoEntity -> - albumService.findByAlbumId(photoEntity.getAlbumId(), requestMemberId) + albumPermissionVerifier.verifyOwnershipOrAccessPermission(photoEntity.getAlbumId(), requestMemberId, FULL_ACCESS) .flatMap(albumEntity -> { int targetIndex = albumEntity.getPhotoCount() - newIndex - 1; @@ -262,4 +176,14 @@ public Mono updatePhotoDisplayIndex(String photoId, Integer newInde ); } + @Transactional + public Mono removePhoto(String photoId, String requestMemberId) { + return photoPermissionVerifier.verifyAccessPermission(photoId, requestMemberId, FULL_ACCESS) + .flatMap(photo -> photoCommand.removePhoto(photo) + .then(albumQuery.findById(photo.getAlbumId()) + .flatMap(album -> albumCommand.decreaseAlbumPhotoCount(album, 1)) + ).then() + ); + } + } From c170592856d07e7f788a25e5f21c02bdde06b822 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 21:30:41 +0900 Subject: [PATCH 27/29] feat: add serial number field for member entity --- .../kr/mafoo/photo/service/dto/MemberDto.java | 3 ++- .../controller/dto/response/MemberResponse.java | 8 ++++++-- .../java/kr/mafoo/user/domain/MemberEntity.java | 3 +++ .../db/migration/V3__add_serial_number_field.sql | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 user-service/src/main/resources/db/migration/V3__add_serial_number_field.sql diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/dto/MemberDto.java b/photo-service/src/main/java/kr/mafoo/photo/service/dto/MemberDto.java index 116f5ddb..f7315eff 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/dto/MemberDto.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/dto/MemberDto.java @@ -3,6 +3,7 @@ public record MemberDto( String memberId, String name, - String profileImageUrl + String profileImageUrl, + String serialNumber ) { } diff --git a/user-service/src/main/java/kr/mafoo/user/controller/dto/response/MemberResponse.java b/user-service/src/main/java/kr/mafoo/user/controller/dto/response/MemberResponse.java index 3bab5448..298cc88a 100644 --- a/user-service/src/main/java/kr/mafoo/user/controller/dto/response/MemberResponse.java +++ b/user-service/src/main/java/kr/mafoo/user/controller/dto/response/MemberResponse.java @@ -12,13 +12,17 @@ public record MemberResponse( String name, @Schema(description = "프로필 이미지 URL", example = "https://mafoo.kr/profile.jpg") - String profileImageUrl + String profileImageUrl, + + @Schema(description = "식별 번호", example = "0000") + String serialNumber ) { public static MemberResponse fromEntity(MemberEntity memberEntity) { return new MemberResponse( memberEntity.getId(), memberEntity.getName(), - memberEntity.getProfileImageUrl() + memberEntity.getProfileImageUrl(), + String.format("%04d", memberEntity.getSerialNumber()) ); } } diff --git a/user-service/src/main/java/kr/mafoo/user/domain/MemberEntity.java b/user-service/src/main/java/kr/mafoo/user/domain/MemberEntity.java index fc1ee2bb..2b826359 100644 --- a/user-service/src/main/java/kr/mafoo/user/domain/MemberEntity.java +++ b/user-service/src/main/java/kr/mafoo/user/domain/MemberEntity.java @@ -23,6 +23,9 @@ public class MemberEntity implements Persistable { @Column("name") private String name; + @Column("serial_number") + private Integer serialNumber; + @Column("created_at") private LocalDateTime createdAt; diff --git a/user-service/src/main/resources/db/migration/V3__add_serial_number_field.sql b/user-service/src/main/resources/db/migration/V3__add_serial_number_field.sql new file mode 100644 index 00000000..5a466467 --- /dev/null +++ b/user-service/src/main/resources/db/migration/V3__add_serial_number_field.sql @@ -0,0 +1,15 @@ +ALTER TABLE member + ADD serial_number INT UNSIGNED NULL AFTER member_id; + + +SET @row_number = 0; + +UPDATE member +SET serial_number = (@row_number := @row_number + 1) + ORDER BY created_at; + + +SELECT MAX(serial_number) + 1 INTO @next_serial FROM member; + +ALTER TABLE member + MODIFY serial_number INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE; From a445724eb98d356f4564b1d11451b2262d98a0a7 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 21:47:29 +0900 Subject: [PATCH 28/29] feat: implement member related apis --- .../java/kr/mafoo/user/api/MemberApi.java | 43 +++++++++++++++++++ .../user/controller/MemberController.java | 33 ++++++++++++++ .../user/repository/MemberRepository.java | 2 + .../kr/mafoo/user/service/MemberService.java | 7 +++ 4 files changed, 85 insertions(+) create mode 100644 user-service/src/main/java/kr/mafoo/user/api/MemberApi.java create mode 100644 user-service/src/main/java/kr/mafoo/user/controller/MemberController.java diff --git a/user-service/src/main/java/kr/mafoo/user/api/MemberApi.java b/user-service/src/main/java/kr/mafoo/user/api/MemberApi.java new file mode 100644 index 00000000..2c0538ab --- /dev/null +++ b/user-service/src/main/java/kr/mafoo/user/api/MemberApi.java @@ -0,0 +1,43 @@ +package kr.mafoo.user.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.user.annotation.RequestMemberId; +import kr.mafoo.user.controller.dto.response.MemberResponse; +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 org.springframework.web.bind.annotation.RequestParam; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Tag(name = "사용자 관련 API", description = "사용자 정보 조회 API") +@Validated +@RequestMapping("/v1/members") +public interface MemberApi { + @Operation(summary = "사용자 검색", description = "키워드로 사용자를 검색합니다. (이름으로 검색)") + @GetMapping + Flux getMemberListByName( + @RequestMemberId + @Parameter(hidden = true) + String requesterId, + + @Parameter(description = "검색어", example = "사람") + @RequestParam + String keyword + ); + + @Operation(summary = "사용자 단건 조회", description = "사용자 단건 정보를 조회합니다.") + @GetMapping("{memberId}") + Mono getMember( + @RequestMemberId + @Parameter(hidden = true) + String requesterId, + + @Parameter(description = "사용자 ID", example = "test_member_id") + @PathVariable + String memberId + ); +} diff --git a/user-service/src/main/java/kr/mafoo/user/controller/MemberController.java b/user-service/src/main/java/kr/mafoo/user/controller/MemberController.java new file mode 100644 index 00000000..975c8fdb --- /dev/null +++ b/user-service/src/main/java/kr/mafoo/user/controller/MemberController.java @@ -0,0 +1,33 @@ +package kr.mafoo.user.controller; + +import kr.mafoo.user.api.MemberApi; +import kr.mafoo.user.controller.dto.response.MemberResponse; +import kr.mafoo.user.service.MemberService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@RestController +public class MemberController implements MemberApi { + private final MemberService memberService; + + @Override + public Flux getMemberListByName( + String requesterId, + String keyword + ) { + return memberService.getMemberByKeyword(keyword) + .map(MemberResponse::fromEntity); + } + + @Override + public Mono getMember( + String requesterId, + String memberId + ) { + return memberService.getMemberByMemberId(memberId) + .map(MemberResponse::fromEntity); + } +} diff --git a/user-service/src/main/java/kr/mafoo/user/repository/MemberRepository.java b/user-service/src/main/java/kr/mafoo/user/repository/MemberRepository.java index e8da0184..01962764 100644 --- a/user-service/src/main/java/kr/mafoo/user/repository/MemberRepository.java +++ b/user-service/src/main/java/kr/mafoo/user/repository/MemberRepository.java @@ -2,8 +2,10 @@ import kr.mafoo.user.domain.MemberEntity; import org.springframework.data.r2dbc.repository.R2dbcRepository; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public interface MemberRepository extends R2dbcRepository { + Flux findAllByNameContaining(String memberId); Mono deleteMemberById(String memberId); } diff --git a/user-service/src/main/java/kr/mafoo/user/service/MemberService.java b/user-service/src/main/java/kr/mafoo/user/service/MemberService.java index bbf1ea3b..1b30a5e1 100644 --- a/user-service/src/main/java/kr/mafoo/user/service/MemberService.java +++ b/user-service/src/main/java/kr/mafoo/user/service/MemberService.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Slf4j @@ -26,6 +27,12 @@ public Mono quitMemberByMemberId(String memberId) { .then(memberRepository.deleteMemberById(memberId)); } + public Flux getMemberByKeyword(String keyword) { + return memberRepository + .findAllByNameContaining(keyword) + .switchIfEmpty(Mono.error(new MemberNotFoundException())); + } + public Mono getMemberByMemberId(String memberId) { return memberRepository .findById(memberId) From 316c8cfa54acf1ff0cf7865b884022a786abea84 Mon Sep 17 00:00:00 2001 From: Gyoungmin Kim Date: Thu, 21 Nov 2024 21:53:14 +0900 Subject: [PATCH 29/29] feat: implement photo-service's MemberService --- .../kr/mafoo/photo/service/MemberService.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java b/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java index 91969388..19a7096c 100644 --- a/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java +++ b/photo-service/src/main/java/kr/mafoo/photo/service/MemberService.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.web.reactive.function.client.WebClient; @@ -28,8 +29,24 @@ public Mono getMemberInfoByToken(String authorizationToken) { } public Mono getMemberInfoById(String memberId, String authorizationToken) { - // TODO : API 구현 후 연결 필요 - return Mono.empty(); + return client + .get() + .uri(endpoint + "/user/v1/members/" + memberId) + .header("Authorization", "Bearer " + authorizationToken) + .retrieve() + .onStatus(status -> !status.is2xxSuccessful(), (res) -> Mono.error(new MafooUserApiFailed())) + .bodyToMono(MemberDto.class); + } + + public Flux getMemberListByKeyword(String keyword, String authorizationToken) { + return client + .get() + .uri(endpoint + "/user/v1/members?keyword=" + keyword) + .header("Authorization", "Bearer " + authorizationToken) + .retrieve() + .onStatus(status -> !status.is2xxSuccessful(), (res) -> Mono.error(new MafooUserApiFailed())) + .bodyToFlux(MemberDto.class); } + }