From 43070d7ed8d9ef787a84f98bd8f51899397b60ba Mon Sep 17 00:00:00 2001 From: kimtaesoo7 Date: Tue, 10 Sep 2024 14:48:53 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B6=8C=ED=95=9C=20=EB=B0=8F=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=20=EB=B3=80=ED=99=94=20=EC=B6=94=EA=B0=80=20-=20S11P21S002-44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment/service/CommentService.java | 39 ++++++++++++-- .../folder/controller/FolderController.java | 12 +++++ .../folder/entity/dto/FolderResponse.java | 19 +++++++ .../domain/folder/service/FolderService.java | 24 +++++++-- .../image/controller/ImageController.java | 20 +++++++ .../worlabel/domain/image/entity/Image.java | 10 ++-- .../domain/image/entity/LabelStatus.java | 19 ++++++- .../image/entity/dto/ImageResponse.java | 9 +++- .../image/entity/dto/ImageStatusRequest.java | 19 +++++++ .../domain/image/service/ImageService.java | 54 ++++++++++++++++--- .../participant/entity/PrivilegeType.java | 25 +++++++-- .../repository/ParticipantRepository.java | 4 +- .../project/service/ProjectService.java | 8 +-- .../worlabel/global/exception/ErrorCode.java | 6 +-- 14 files changed, 236 insertions(+), 32 deletions(-) create mode 100644 backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageStatusRequest.java diff --git a/backend/src/main/java/com/worlabel/domain/comment/service/CommentService.java b/backend/src/main/java/com/worlabel/domain/comment/service/CommentService.java index ec4862b..8364fb2 100644 --- a/backend/src/main/java/com/worlabel/domain/comment/service/CommentService.java +++ b/backend/src/main/java/com/worlabel/domain/comment/service/CommentService.java @@ -4,6 +4,8 @@ import com.worlabel.domain.comment.entity.Comment; import com.worlabel.domain.comment.entity.dto.CommentRequest; import com.worlabel.domain.comment.entity.dto.CommentResponse; import com.worlabel.domain.comment.repository.CommentRepository; +import com.worlabel.domain.folder.entity.Folder; +import com.worlabel.domain.folder.repository.FolderRepository; import com.worlabel.domain.image.entity.Image; import com.worlabel.domain.image.repository.ImageRepository; import com.worlabel.domain.member.entity.Member; @@ -26,10 +28,11 @@ public class CommentService { private final ParticipantRepository participantRepository; private final MemberRepository memberRepository; private final ImageRepository imageRepository; + private final FolderRepository folderRepository; @Transactional(readOnly = true) public List getAllComments(final Integer memberId, final Integer projectId, final Long imageId) { - checkAuthorized(memberId, projectId); + checkAuthorizedAndImageProjectRelation(memberId, projectId, imageId); return commentRepository.findByImageId(imageId).stream() .map(CommentResponse::from) @@ -38,14 +41,14 @@ public class CommentService { @Transactional(readOnly = true) public CommentResponse getCommentById(final Integer memberId, final Integer projectId, final Integer commentId) { - checkAuthorized(memberId, projectId); + checkAuthorizedAndCommentProjectRelation(memberId, projectId, commentId); Comment comment = getComment(commentId); return CommentResponse.from(comment); } public CommentResponse createComment(final CommentRequest commentRequest, Integer memberId, final Integer projectId, final Long imageId) { - checkAuthorized(memberId, projectId); + checkAuthorizedAndImageProjectRelation(memberId, projectId, imageId); Member member = getMember(memberId); Image image = getImage(imageId); @@ -67,6 +70,36 @@ public class CommentService { commentRepository.delete(comment); } + /** + * 프로젝트에 속한 멤버인지 검증하고, 이미지가 해당 프로젝트에 속하는지 검증 + */ + private void checkAuthorizedAndImageProjectRelation(final Integer memberId, final Integer projectId, final Long imageId) { + checkAuthorized(memberId, projectId); + Image image = getImage(imageId); + Folder folder = image.getFolder(); // 이미지가 속한 폴더를 가져옴 + + if (!folderRepository.existsByIdAndProjectId(folder.getId(), projectId)) { + throw new CustomException(ErrorCode.IMAGE_NOT_FOUND); + } + } + + /** + * 프로젝트에 속한 멤버인지 검증하고, 코멘트가 속한 이미지가 해당 프로젝트에 속하는지 검증 + */ + private void checkAuthorizedAndCommentProjectRelation(final Integer memberId, final Integer projectId, final Integer commentId) { + checkAuthorized(memberId, projectId); + Comment comment = getComment(commentId); + Image image = comment.getImage(); + Folder folder = image.getFolder(); // 코멘트가 속한 이미지의 폴더를 가져옴 + + if (!folderRepository.existsByIdAndProjectId(folder.getId(), projectId)) { + throw new CustomException(ErrorCode.COMMENT_NOT_FOUND); + } + } + + /** + * 멤버가 해당 프로젝트에 참여하고 있는지, 권한이 있는지 검증 + */ private void checkAuthorized(final Integer memberId, final Integer projectId) { if (!participantRepository.existsByMemberIdAndProjectId(memberId, projectId)) { throw new CustomException(ErrorCode.UNAUTHORIZED); diff --git a/backend/src/main/java/com/worlabel/domain/folder/controller/FolderController.java b/backend/src/main/java/com/worlabel/domain/folder/controller/FolderController.java index cc64d30..53e93e3 100644 --- a/backend/src/main/java/com/worlabel/domain/folder/controller/FolderController.java +++ b/backend/src/main/java/com/worlabel/domain/folder/controller/FolderController.java @@ -47,6 +47,18 @@ public class FolderController { return SuccessResponse.of(folderResponse); } + @Operation(summary = "폴더 하위 리뷰해야할 목록만 조회", description = "폴더하위 리뷰해야할 목록을 조회합니다.") + @SwaggerApiSuccess(description = "폴더 하위 리뷰해야할 목록을 성공적으로 조회합니다.") + @SwaggerApiError({ErrorCode.EMPTY_REQUEST_PARAMETER, ErrorCode.SERVER_ERROR}) + @GetMapping("/{folder_id}/review") + public BaseResponse getFolderByIdWithNeedReview( + @CurrentUser final Integer memberId, + @PathVariable("project_id") final Integer projectId, + @PathVariable("folder_id") final Integer folderId) { + FolderResponse folderResponse = folderService.getFolderByIdWithNeedReview(memberId, projectId, folderId); + return SuccessResponse.of(folderResponse); + } + @Operation(summary = "폴더 수정", description = "폴더 정보를 수정합니다.") @SwaggerApiSuccess(description = "폴더를 성공적으로 수정합니다.") @SwaggerApiError({ErrorCode.EMPTY_REQUEST_PARAMETER, ErrorCode.SERVER_ERROR}) diff --git a/backend/src/main/java/com/worlabel/domain/folder/entity/dto/FolderResponse.java b/backend/src/main/java/com/worlabel/domain/folder/entity/dto/FolderResponse.java index ec11135..88e4d9d 100644 --- a/backend/src/main/java/com/worlabel/domain/folder/entity/dto/FolderResponse.java +++ b/backend/src/main/java/com/worlabel/domain/folder/entity/dto/FolderResponse.java @@ -1,6 +1,7 @@ package com.worlabel.domain.folder.entity.dto; import com.worlabel.domain.folder.entity.Folder; +import com.worlabel.domain.image.entity.LabelStatus; import com.worlabel.domain.image.entity.dto.ImageResponse; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; @@ -42,6 +43,24 @@ public class FolderResponse { ); } + public static FolderResponse fromWithNeedReview(final Folder folder) { + List images = folder.getImageList().stream() + .filter(image -> image.getStatus() == LabelStatus.NEED_REVIEW) + .map(ImageResponse::from) + .toList(); + + List children = folder.getChildren().stream() + .map(FolderIdResponse::from) + .toList(); + + return new FolderResponse( + folder.getId(), + folder.getTitle(), + images, + children + ); + } + public static FolderResponse from(final List topFolders) { List list = topFolders.stream() .map(FolderIdResponse::from) diff --git a/backend/src/main/java/com/worlabel/domain/folder/service/FolderService.java b/backend/src/main/java/com/worlabel/domain/folder/service/FolderService.java index 87c669d..bf32044 100644 --- a/backend/src/main/java/com/worlabel/domain/folder/service/FolderService.java +++ b/backend/src/main/java/com/worlabel/domain/folder/service/FolderService.java @@ -33,7 +33,7 @@ public class FolderService { Folder parent = null; if (folderRequest.getParentId() != 0) { - parent = getFolder(folderRequest.getParentId(),projectId); + parent = getFolder(folderRequest.getParentId(), projectId); } Folder folder = Folder.of(folderRequest.getTitle(), parent, project); @@ -53,7 +53,7 @@ public class FolderService { if (folderId == 0) { return FolderResponse.from(folderRepository.findAllByProjectIdAndParentIsNull(projectId)); } else { - return FolderResponse.from(getFolder(folderId,projectId)); + return FolderResponse.from(getFolder(folderId, projectId)); } } @@ -62,7 +62,7 @@ public class FolderService { */ public FolderResponse updateFolder(final Integer memberId, final Integer projectId, final Integer folderId, final FolderRequest updatedFolderRequest) { checkUnauthorized(memberId, projectId); - Folder folder = getFolder(folderId,projectId); + Folder folder = getFolder(folderId, projectId); Folder parentFolder = folderRepository.findById(updatedFolderRequest.getParentId()) .orElse(null); @@ -77,17 +77,31 @@ public class FolderService { */ public void deleteFolder(final Integer memberId, final Integer projectId, final Integer folderId) { checkUnauthorized(memberId, projectId); - Folder folder = getFolder(folderId,projectId); + Folder folder = getFolder(folderId, projectId); folderRepository.delete(folder); } + /** + * 리뷰 목록만 조회 + */ + public FolderResponse getFolderByIdWithNeedReview(final Integer memberId, final Integer projectId, final Integer folderId) { + checkExistParticipant(memberId, projectId); + + // 최상위 폴더 + if (folderId == 0) { + return FolderResponse.from(folderRepository.findAllByProjectIdAndParentIsNull(projectId)); + } else { + return FolderResponse.fromWithNeedReview(getFolder(folderId, projectId)); + } + } + private Project getProject(final Integer projectId) { return projectRepository.findById(projectId) .orElseThrow(() -> new CustomException(ErrorCode.PROJECT_NOT_FOUND)); } private Folder getFolder(final Integer folderId, final Integer projectId) { - return folderRepository.findAllByProjectIdAndId(projectId,folderId) + return folderRepository.findAllByProjectIdAndId(projectId, folderId) .orElseThrow(() -> new CustomException(ErrorCode.FOLDER_NOT_FOUND)); } diff --git a/backend/src/main/java/com/worlabel/domain/image/controller/ImageController.java b/backend/src/main/java/com/worlabel/domain/image/controller/ImageController.java index 90e66aa..a668802 100644 --- a/backend/src/main/java/com/worlabel/domain/image/controller/ImageController.java +++ b/backend/src/main/java/com/worlabel/domain/image/controller/ImageController.java @@ -2,6 +2,7 @@ package com.worlabel.domain.image.controller; import com.worlabel.domain.image.entity.dto.ImageMoveRequest; import com.worlabel.domain.image.entity.dto.ImageResponse; +import com.worlabel.domain.image.entity.dto.ImageStatusRequest; import com.worlabel.domain.image.service.ImageService; import com.worlabel.global.annotation.CurrentUser; import com.worlabel.global.config.swagger.SwaggerApiError; @@ -88,4 +89,23 @@ public class ImageController { imageService.deleteImage(projectId, folderId, imageId, memberId); return SuccessResponse.empty(); } + + @PutMapping("/{image_id}/status") + @SwaggerApiSuccess(description = "이미지 상태 변경.") + @Operation(summary = "이미지 상태 변경", description = "특정 이미지의 상태를 변경합니다.") + @SwaggerApiError({ErrorCode.BAD_REQUEST, ErrorCode.NOT_AUTHOR, ErrorCode.SERVER_ERROR, ErrorCode.PARTICIPANT_UNAUTHORIZED, ErrorCode.FOLDER_NOT_FOUND, ErrorCode.IMAGE_NOT_FOUND}) + public BaseResponse changeImageStatus( + @CurrentUser final Integer memberId, + @PathVariable("folder_id") final Integer folderId, + @PathVariable("project_id") final Integer projectId, + @PathVariable("image_id") final Long imageId, + @RequestBody final ImageStatusRequest imageStatusRequest + ) { + log.debug("project: {} , folder: {}, 수정하려는 이미지: {}, 현재 로그인 중인 사용자 : {}", projectId, folderId, imageId, memberId); + ImageResponse imageResponse = imageService.changeImageStatus(projectId, folderId, imageId, memberId, imageStatusRequest); + return SuccessResponse.of(imageResponse); + } + + + } diff --git a/backend/src/main/java/com/worlabel/domain/image/entity/Image.java b/backend/src/main/java/com/worlabel/domain/image/entity/Image.java index 8e03657..12cceb1 100644 --- a/backend/src/main/java/com/worlabel/domain/image/entity/Image.java +++ b/backend/src/main/java/com/worlabel/domain/image/entity/Image.java @@ -47,9 +47,9 @@ public class Image extends BaseEntity { /** * 이미지 레이블링 상태 */ - @Enumerated(EnumType.STRING) @Column(name = "status", nullable = false) - private LabelStatus status = LabelStatus.Pending; + @Enumerated(EnumType.STRING) + private LabelStatus status = LabelStatus.PENDING; /** * 속한 폴더 @@ -73,10 +73,14 @@ public class Image extends BaseEntity { } public static Image of(final String imageTitle, final String imageUrl, final Integer order, final Folder folder) { - return new Image(imageTitle,imageUrl, order, folder); + return new Image(imageTitle, imageUrl, order, folder); } public void moveFolder(final Folder moveFolder) { this.folder = moveFolder; } + + public void updateStatus(final LabelStatus labelStatus) { + this.status = labelStatus; + } } diff --git a/backend/src/main/java/com/worlabel/domain/image/entity/LabelStatus.java b/backend/src/main/java/com/worlabel/domain/image/entity/LabelStatus.java index a0e8969..93f66a7 100644 --- a/backend/src/main/java/com/worlabel/domain/image/entity/LabelStatus.java +++ b/backend/src/main/java/com/worlabel/domain/image/entity/LabelStatus.java @@ -1,5 +1,22 @@ package com.worlabel.domain.image.entity; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + public enum LabelStatus { - Pending, IN_PROGRESS, NEED_REVIEW, COMPLETED + PENDING, + IN_PROGRESS, + NEED_REVIEW, + COMPLETED; + + // 입력 값을 enum 값과 일치시키기 위해 대소문자 구분 없이 변환 + @JsonCreator + public static LabelStatus from(String value) { + return LabelStatus.valueOf(value.toUpperCase()); // 입력된 값을 대문자로 변환 + } + + @JsonValue + public String toValue() { + return name(); + } } diff --git a/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageResponse.java b/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageResponse.java index 6b7a325..ff519f7 100644 --- a/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageResponse.java +++ b/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageResponse.java @@ -1,6 +1,7 @@ package com.worlabel.domain.image.entity.dto; import com.worlabel.domain.image.entity.Image; +import com.worlabel.domain.image.entity.LabelStatus; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -15,15 +16,19 @@ public class ImageResponse { @Schema(description = "이미지 파일 제목", example = "image.jpg") private String imageTitle; - + @Schema(description = "이미지 URL", example = "https://example.com/image.jpg") private String imageUrl; + @Schema(description = "이미지 상태", example = "PENDING") + private LabelStatus status; + public static ImageResponse from(final Image image) { return new ImageResponse( image.getId(), image.getTitle(), - image.getImageUrl() + image.getImageUrl(), + image.getStatus() ); } } \ No newline at end of file diff --git a/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageStatusRequest.java b/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageStatusRequest.java new file mode 100644 index 0000000..134858b --- /dev/null +++ b/backend/src/main/java/com/worlabel/domain/image/entity/dto/ImageStatusRequest.java @@ -0,0 +1,19 @@ +package com.worlabel.domain.image.entity.dto; + +import com.worlabel.domain.image.entity.LabelStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Schema(name = "이미지 상태변경 요청 DTO", description = "이미지의 상태를 변경할때 사용되는 요청 DTO") +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class ImageStatusRequest { + + @Schema(description = "상태", example = "NEED_REVIEW") + @NotNull(message = "상태를 입력하세요.") + private LabelStatus labelStatus; +} \ No newline at end of file diff --git a/backend/src/main/java/com/worlabel/domain/image/service/ImageService.java b/backend/src/main/java/com/worlabel/domain/image/service/ImageService.java index 0f93361..4d30233 100644 --- a/backend/src/main/java/com/worlabel/domain/image/service/ImageService.java +++ b/backend/src/main/java/com/worlabel/domain/image/service/ImageService.java @@ -4,7 +4,9 @@ import com.worlabel.domain.folder.entity.Folder; import com.worlabel.domain.folder.repository.FolderRepository; import com.worlabel.domain.image.entity.Image; import com.worlabel.domain.image.entity.dto.ImageResponse; +import com.worlabel.domain.image.entity.dto.ImageStatusRequest; import com.worlabel.domain.image.repository.ImageRepository; +import com.worlabel.domain.participant.entity.Participant; import com.worlabel.domain.participant.entity.PrivilegeType; import com.worlabel.domain.participant.repository.ParticipantRepository; import com.worlabel.global.exception.CustomException; @@ -33,6 +35,7 @@ public class ImageService { * 이미지 리스트 업로드 */ public void uploadImageList(final List imageList, final Integer folderId, final Integer projectId, final Integer memberId) { + // 권한이 편집자 이상인지 확인 checkEditorParticipant(memberId, projectId); Folder folder = getFolder(folderId); for (int order = 0; order < imageList.size(); order++) { @@ -48,8 +51,11 @@ public class ImageService { */ @Transactional(readOnly = true) public ImageResponse getImageById(final Integer projectId, final Integer folderId, final Long imageId, final Integer memberId) { + // 참가에 존재하는지 확인 checkExistParticipant(memberId, projectId); - Image image = getImage(folderId, imageId); + + // 이미지가 해당 프로젝트에 속하는지 확인 + Image image = getImageAndValidateProject(folderId, imageId, projectId); return ImageResponse.from(image); } @@ -63,13 +69,15 @@ public class ImageService { final Long imageId, final Integer memberId ) { + // 권한이 편집자 이상인지 확인 checkEditorParticipant(memberId, projectId); Folder folder = null; if (moveFolderId != null) { folder = getFolder(moveFolderId); } - Image image = getImage(folderId, imageId); + // 이미지가 해당 프로젝트에 속하는지 확인 + Image image = getImageAndValidateProject(folderId, imageId, projectId); image.moveFolder(folder); } @@ -77,31 +85,65 @@ public class ImageService { * 이미지 삭제 */ public void deleteImage(final Integer projectId, final Integer folderId, final Long imageId, final Integer memberId) { + // 권한이 편집자 이상인지 확인 checkEditorParticipant(memberId, projectId); - Image image = getImage(folderId, imageId); + + // 이미지가 해당 프로젝트에 속하는지 확인 + Image image = getImageAndValidateProject(folderId, imageId, projectId); + imageRepository.delete(image); s3UploadService.deleteImageFromS3(image.getImageUrl()); } + /** + * 이미지 상태 변경 + */ + public ImageResponse changeImageStatus(final Integer projectId, final Integer folderId, final Long imageId, final Integer memberId, final ImageStatusRequest imageStatusRequest) { + // 참가에 존재하는지 확인 + checkExistParticipant(memberId, projectId); + + // 이미지가 해당 프로젝트에 속하는지 확인 + Image image = getImageAndValidateProject(folderId, imageId, projectId); + + // 이미지 상태 변경 로직 추가 (생략) + image.updateStatus(imageStatusRequest.getLabelStatus()); + + return ImageResponse.from(image); + } + + // 참가에 존재하는지 확인 private void checkExistParticipant(final Integer memberId, final Integer projectId) { if (!participantRepository.existsByMemberIdAndProjectId(memberId, projectId)) { throw new CustomException(ErrorCode.BAD_REQUEST); } } + // 편집자 이상의 권한을 확인하는 메서드 private void checkEditorParticipant(final Integer memberId, final Integer projectId) { - if (participantRepository.doesParticipantUnauthorizedExistByMemberIdAndProjectId(memberId,projectId)) { + Participant participant = participantRepository.findByMemberIdAndProjectId(memberId, projectId) + .orElseThrow(() -> new CustomException(ErrorCode.PARTICIPANT_UNAUTHORIZED)); + + if (!participant.getPrivilege().isEditeAuth()) { throw new CustomException(ErrorCode.PARTICIPANT_UNAUTHORIZED); } } + // 폴더 가져오기 private Folder getFolder(final Integer folderId) { return folderRepository.findById(folderId) .orElseThrow(() -> new CustomException(ErrorCode.FOLDER_NOT_FOUND)); } - private Image getImage(Integer folderId, Long imageId) { - return imageRepository.findByIdAndFolderId(imageId, folderId) + // 이미지 가져오면서 프로젝트 소속 여부를 확인 + private Image getImageAndValidateProject(final Integer folderId, final Long imageId, final Integer projectId) { + Image image = imageRepository.findByIdAndFolderId(imageId, folderId) .orElseThrow(() -> new CustomException(ErrorCode.IMAGE_NOT_FOUND)); + + // 이미지가 해당 프로젝트에 속하는지 확인 + if (!image.getFolder().getProject().getId().equals(projectId)) { + throw new CustomException(ErrorCode.PROJECT_IMAGE_MISMATCH); + } + + return image; } } diff --git a/backend/src/main/java/com/worlabel/domain/participant/entity/PrivilegeType.java b/backend/src/main/java/com/worlabel/domain/participant/entity/PrivilegeType.java index c6ad16e..6aa8b38 100644 --- a/backend/src/main/java/com/worlabel/domain/participant/entity/PrivilegeType.java +++ b/backend/src/main/java/com/worlabel/domain/participant/entity/PrivilegeType.java @@ -1,8 +1,23 @@ package com.worlabel.domain.participant.entity; -/** - * 프로젝트 참여 권한 - */ +import lombok.Getter; + +@Getter public enum PrivilegeType { - ADMIN, MANAGER, EDITOR, VIEWER -} + ADMIN(4), + MANAGER(3), + EDITOR(2), + VIEWER(1); + + private final int score; + + // 점수를 부여하는 생성자 + PrivilegeType(final int score) { + this.score = score; + } + + // 편집자 이상의 권한이 있는지 확인하는 메서드 + public boolean isEditeAuth() { + return this.score >= EDITOR.getScore(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/worlabel/domain/participant/repository/ParticipantRepository.java b/backend/src/main/java/com/worlabel/domain/participant/repository/ParticipantRepository.java index 5fb5ce3..ddfc9a9 100644 --- a/backend/src/main/java/com/worlabel/domain/participant/repository/ParticipantRepository.java +++ b/backend/src/main/java/com/worlabel/domain/participant/repository/ParticipantRepository.java @@ -7,6 +7,8 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface ParticipantRepository extends JpaRepository { @@ -23,7 +25,7 @@ public interface ParticipantRepository extends JpaRepository findByMemberIdAndProjectId(Integer memberId, Integer projectId); } diff --git a/backend/src/main/java/com/worlabel/domain/project/service/ProjectService.java b/backend/src/main/java/com/worlabel/domain/project/service/ProjectService.java index 55b9e1d..3efbaa2 100644 --- a/backend/src/main/java/com/worlabel/domain/project/service/ProjectService.java +++ b/backend/src/main/java/com/worlabel/domain/project/service/ProjectService.java @@ -98,7 +98,8 @@ public class ProjectService { checkAdminParticipant(memberId, projectId); checkNotAdminParticipant(participantRequest.getMemberId(), projectId); - Participant participant = participantRepository.findByMemberIdAndProjectId(participantRequest.getMemberId(), projectId); + Participant participant = participantRepository.findByMemberIdAndProjectId(participantRequest.getMemberId(), projectId) + .orElseThrow(() -> new CustomException(ErrorCode.PARTICIPANT_UNAUTHORIZED)); participant.updatePrivilege(participantRequest.getPrivilegeType()); } @@ -107,11 +108,12 @@ public class ProjectService { checkAdminParticipant(memberId, projectId); checkNotAdminParticipant(removeMemberId, projectId); - Participant participant = participantRepository.findByMemberIdAndProjectId(removeMemberId, projectId); + Participant participant = participantRepository.findByMemberIdAndProjectId(removeMemberId, projectId) + .orElseThrow(() -> new CustomException(ErrorCode.PARTICIPANT_UNAUTHORIZED)); + participantRepository.delete(participant); } - private Workspace getWorkspace(final Integer memberId, final Integer workspaceId) { return workspaceRepository.findByMemberIdAndId(memberId, workspaceId) .orElseThrow(() -> new CustomException(ErrorCode.WORKSPACE_NOT_FOUND)); diff --git a/backend/src/main/java/com/worlabel/global/exception/ErrorCode.java b/backend/src/main/java/com/worlabel/global/exception/ErrorCode.java index efe5dfc..5e473cf 100644 --- a/backend/src/main/java/com/worlabel/global/exception/ErrorCode.java +++ b/backend/src/main/java/com/worlabel/global/exception/ErrorCode.java @@ -36,6 +36,7 @@ public enum ErrorCode { // Project - 4000 PROJECT_NOT_FOUND(HttpStatus.NOT_FOUND, 4000, "프로젝트를 찾을 수 없습니다"), + PROJECT_IMAGE_MISMATCH(HttpStatus.BAD_REQUEST, 4001, "해당 프로젝트에는 존재하지 않는 이미지입니다."), // Participant - 5000, PARTICIPANT_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, 5000, "해당 프로젝트에 접근 권한이 없습니다."), @@ -51,10 +52,9 @@ public enum ErrorCode { // AI - 8000 AI_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 8000, "AI 서버 오류 입니다."), - // Comment - 9000 - COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, 9000, "해당 댓글을 찾을 수 없습니다."), + // Comment - 9000, + COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, 9000, "해당 댓글을 찾을 수 없습니다."); - ; private final HttpStatus status; private final int code; private final String message;