From ccfd0401c36ba5d2ca8406fae1af4d8049f3038f Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 30 Jan 2025 18:15:15 +0900 Subject: [PATCH 01/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84(?= =?UTF-8?q?=EC=B2=A8=EB=B6=80=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=20=EC=95=84?= =?UTF-8?q?=EB=8B=8C=20=EC=9D=BC=EB=B0=98=20=EB=8C=93=EA=B8=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/comment/PostCommentController.java | 32 +++++++++++ .../dto/task/PostAndEditCommentRequest.java | 7 +++ .../CommentPersistenceAdapter.java | 20 ++++++- .../inbound/comment/PostCommentUsecase.java | 8 +++ .../taskhistory/CommandCommentPort.java | 2 +- .../service/comment/PostCommentService.java | 53 +++++++++++++++++++ .../server/domain/model/task/Comment.java | 10 ++++ 7 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java create mode 100644 src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java create mode 100644 src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java create mode 100644 src/main/java/clap/server/application/service/comment/PostCommentService.java diff --git a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java new file mode 100644 index 00000000..5c93887a --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java @@ -0,0 +1,32 @@ +package clap.server.adapter.inbound.web.comment; + +import clap.server.adapter.inbound.security.SecurityUserDetails; +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.application.port.inbound.comment.PostCommentUsecase; +import clap.server.common.annotation.architecture.WebAdapter; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "02. Task", description = "작업 생성/수정 API") +@WebAdapter +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/comment") +public class PostCommentController { + + private final PostCommentUsecase postCommentUsecase; + + @Operation(summary = "댓글 작성") + @PostMapping("/{taskId}") + @Secured({"ROLE_MANAGER", "ROLE_USER"}) + public void createTask( + @AuthenticationPrincipal SecurityUserDetails userInfo, + @PathVariable Long taskId, + @RequestBody(required = true) PostAndEditCommentRequest request){ + postCommentUsecase.save(userInfo.getUserId(), taskId, request); + } +} diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java new file mode 100644 index 00000000..41baf2c7 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java @@ -0,0 +1,7 @@ +package clap.server.adapter.inbound.web.dto.task; + + +public record PostAndEditCommentRequest( + String content +) { +} diff --git a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java index 48b65cf7..046a875b 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java @@ -1,13 +1,29 @@ package clap.server.adapter.outbound.persistense; -import clap.server.application.port.outbound.taskhistory.LoadCommentPort; +import clap.server.adapter.outbound.persistense.mapper.CommentPersistenceMapper; +import clap.server.adapter.outbound.persistense.repository.task.CommentRepository; +import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.application.port.outbound.task.LoadCommentPort; +import clap.server.common.annotation.architecture.PersistenceAdapter; import clap.server.domain.model.task.Comment; +import lombok.RequiredArgsConstructor; import java.util.Optional; -public class CommentPersistenceAdapter implements LoadCommentPort { +@PersistenceAdapter +@RequiredArgsConstructor +public class CommentPersistenceAdapter implements LoadCommentPort, CommandCommentPort { + + private final CommentRepository commentRepository; + private final CommentPersistenceMapper commentPersistenceMapper; + @Override public Optional findById(Long id) { return Optional.empty(); } + + @Override + public void save(Comment comment) { + commentRepository.save(commentPersistenceMapper.toEntity(comment)); + } } diff --git a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java new file mode 100644 index 00000000..7812e8db --- /dev/null +++ b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java @@ -0,0 +1,8 @@ +package clap.server.application.port.inbound.comment; + +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; + +public interface PostCommentUsecase { + + void save(Long userId, Long taskId, PostAndEditCommentRequest request); +} diff --git a/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java b/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java index ed378deb..1adf7116 100644 --- a/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java +++ b/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java @@ -5,5 +5,5 @@ import java.util.Optional; public interface CommandCommentPort { - Optional save(Comment comment); + void save(Comment comment); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java new file mode 100644 index 00000000..17fd2def --- /dev/null +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -0,0 +1,53 @@ +package clap.server.application.service.comment; + +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; +import clap.server.application.mapper.AttachmentMapper; +import clap.server.application.port.inbound.comment.PostCommentUsecase; +import clap.server.application.port.inbound.domain.MemberService; +import clap.server.application.port.inbound.domain.TaskService; +import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.common.annotation.architecture.ApplicationService; +import clap.server.common.constants.FilePathConstants; +import clap.server.domain.model.member.Member; +import clap.server.domain.model.task.Attachment; +import clap.server.domain.model.task.Comment; +import clap.server.domain.model.task.Task; +import clap.server.exception.ApplicationException; +import clap.server.exception.code.MemberErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@ApplicationService +@RequiredArgsConstructor +public class PostCommentService implements PostCommentUsecase { + + private final MemberService memberService; + private final TaskService taskService; + private final CommandCommentPort commandCommentPort; + + @Transactional + @Override + public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { + Task task = taskService.findById(taskId); + Member member = memberService.findActiveMember(userId); + + // 일반 회원일 경우 => 요청자인지 확인 + // 담당자일 경우 => 처리자인지 확인 + if ((member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) + && !(member.getMemberId() == task.getProcessor().getMemberId())) { + throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); + } + + if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) + && !(member.getMemberId() == task.getRequester().getMemberId())) { + throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); + } + + Comment comment = Comment.createComment(member, task, request); + commandCommentPort.save(comment); + } +} diff --git a/src/main/java/clap/server/domain/model/task/Comment.java b/src/main/java/clap/server/domain/model/task/Comment.java index 52822050..b186ac0f 100644 --- a/src/main/java/clap/server/domain/model/task/Comment.java +++ b/src/main/java/clap/server/domain/model/task/Comment.java @@ -1,5 +1,6 @@ package clap.server.domain.model.task; +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; import clap.server.domain.model.common.BaseTime; import clap.server.domain.model.member.Member; import lombok.AccessLevel; @@ -17,4 +18,13 @@ public class Comment extends BaseTime { private String content; private boolean isModified; + public static Comment createComment(Member member, Task task, PostAndEditCommentRequest request) { + return Comment.builder() + .member(member) + .task(task) + .content(request.content()) + .isModified(false) + .build(); + } + } From 54842f2a801a42cd8ddac962e7734aa1ca79328f Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 30 Jan 2025 23:56:42 +0900 Subject: [PATCH 02/58] =?UTF-8?q?CLAP-177=20fix:=20rebase=ED=95=98?= =?UTF-8?q?=EB=A9=B0=20=EB=B0=9C=EC=83=9D=ED=95=9C=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../outbound/persistense/CommentPersistenceAdapter.java | 6 ++++-- .../port/outbound/task/CommandCommentPort.java | 8 ++++++++ .../application/port/outbound/task/LoadCommentPort.java | 9 +++++++++ .../java/clap/server/exception/code/MemberErrorCode.java | 3 ++- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java create mode 100644 src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java diff --git a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java index 046a875b..927e5d12 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java @@ -1,5 +1,6 @@ package clap.server.adapter.outbound.persistense; +import clap.server.adapter.outbound.persistense.entity.task.CommentEntity; import clap.server.adapter.outbound.persistense.mapper.CommentPersistenceMapper; import clap.server.adapter.outbound.persistense.repository.task.CommentRepository; import clap.server.application.port.outbound.task.CommandCommentPort; @@ -23,7 +24,8 @@ public Optional findById(Long id) { } @Override - public void save(Comment comment) { - commentRepository.save(commentPersistenceMapper.toEntity(comment)); + public Comment saveComment(Comment comment) { + CommentEntity commentEntity = commentRepository.save(commentPersistenceMapper.toEntity(comment)); + return commentPersistenceMapper.toDomain(commentEntity); } } diff --git a/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java b/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java new file mode 100644 index 00000000..834732f3 --- /dev/null +++ b/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java @@ -0,0 +1,8 @@ +package clap.server.application.port.outbound.task; + +import clap.server.domain.model.task.Comment; + +public interface CommandCommentPort { + + Comment saveComment(Comment comment); +} diff --git a/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java b/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java new file mode 100644 index 00000000..d3a42ea2 --- /dev/null +++ b/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java @@ -0,0 +1,9 @@ +package clap.server.application.port.outbound.task; + +import clap.server.domain.model.task.Comment; + +import java.util.Optional; + +public interface LoadCommentPort { + Optional findById(Long commentId); +} diff --git a/src/main/java/clap/server/exception/code/MemberErrorCode.java b/src/main/java/clap/server/exception/code/MemberErrorCode.java index dae6b6ef..5dc871ab 100644 --- a/src/main/java/clap/server/exception/code/MemberErrorCode.java +++ b/src/main/java/clap/server/exception/code/MemberErrorCode.java @@ -10,7 +10,8 @@ public enum MemberErrorCode implements BaseErrorCode { MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBER_001", "회원을 찾을 수 없습니다."), ACTIVE_MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBER_002", "활성화 회원을 찾을 수 없습니다."), NOT_A_REVIEWER(HttpStatus.FORBIDDEN, "MEMBER_003", "리뷰어 권한이 없습니다."), - MEMBER_REGISTER_FAILED(HttpStatus.BAD_REQUEST, "MEMBER_004", "회원 등록에 실패하였습니다"); + MEMBER_REGISTER_FAILED(HttpStatus.BAD_REQUEST, "MEMBER_004", "회원 등록에 실패하였습니다"), + NOT_A_COMMENTER(HttpStatus.FORBIDDEN, "MEMBER_005", "댓글 작성 권한이 없습니다.") ; private final HttpStatus httpStatus; From 64772a256bddd5ce9e9139a1104b333e5f7ba979 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:00:13 +0900 Subject: [PATCH 03/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84(?= =?UTF-8?q?=EC=B2=A8=EB=B6=80=20=ED=8C=8C=EC=9D=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/comment/PostCommentController.java | 19 +++++++++ .../dto/task/PostAndEditCommentRequest.java | 3 ++ .../application/mapper/AttachmentMapper.java | 15 +++++++ .../inbound/comment/PostCommentUsecase.java | 5 +++ .../service/comment/PostCommentService.java | 39 +++++++++++++++++-- .../server/domain/model/task/Attachment.java | 11 ++++++ .../server/domain/model/task/Comment.java | 5 +-- 7 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java index 5c93887a..65656da1 100644 --- a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java +++ b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java @@ -5,11 +5,17 @@ import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.security.access.annotation.Secured; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; @Tag(name = "02. Task", description = "작업 생성/수정 API") @WebAdapter @@ -21,6 +27,7 @@ public class PostCommentController { private final PostCommentUsecase postCommentUsecase; @Operation(summary = "댓글 작성") + @Parameter(name = "labelId", description = "댓글 작성할 작업 고유 ID", required = true, in = ParameterIn.PATH) @PostMapping("/{taskId}") @Secured({"ROLE_MANAGER", "ROLE_USER"}) public void createTask( @@ -29,4 +36,16 @@ public void createTask( @RequestBody(required = true) PostAndEditCommentRequest request){ postCommentUsecase.save(userInfo.getUserId(), taskId, request); } + + @Operation(summary = "댓글 작성(첨부 파일)") + @Parameter(name = "labelId", description = "댓글 작성할 작업 고유 ID", required = true, in = ParameterIn.PATH) + @PostMapping("/attachment/{taskId}") + @Secured({"ROLE_MANAGER", "ROLE_USER"}) + public void createAttachmentTask( + @AuthenticationPrincipal SecurityUserDetails userInfo, + @PathVariable Long taskId, + @RequestPart(name = "attachment") @NotNull List attachments) { + postCommentUsecase.saveCommentAttachment(userInfo.getUserId(), taskId, attachments); + } + } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java index 41baf2c7..b66a6506 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java @@ -1,7 +1,10 @@ package clap.server.adapter.inbound.web.dto.task; +import io.swagger.v3.oas.annotations.media.Schema; + public record PostAndEditCommentRequest( + @Schema(description = "댓글 내용") String content ) { } diff --git a/src/main/java/clap/server/application/mapper/AttachmentMapper.java b/src/main/java/clap/server/application/mapper/AttachmentMapper.java index 119221b6..217780eb 100644 --- a/src/main/java/clap/server/application/mapper/AttachmentMapper.java +++ b/src/main/java/clap/server/application/mapper/AttachmentMapper.java @@ -2,6 +2,7 @@ import clap.server.adapter.inbound.web.dto.task.AttachmentResponse; import clap.server.domain.model.task.Attachment; +import clap.server.domain.model.task.Comment; import clap.server.domain.model.task.Task; import org.springframework.web.multipart.MultipartFile; @@ -9,6 +10,7 @@ import java.util.stream.IntStream; import static clap.server.domain.model.task.Attachment.createAttachment; +import static clap.server.domain.model.task.Attachment.createCommentAttachment; public class AttachmentMapper { private AttachmentMapper() { @@ -26,6 +28,19 @@ public static List toTaskAttachments(Task task, List .toList(); } + public static List toCommentAttachments(Task task, Comment comment, List files, List fileUrls) { + return IntStream.range(0, files.size()) + .mapToObj(i -> createCommentAttachment( + task, + comment, + files.get(i).getOriginalFilename(), + fileUrls.get(i), + files.get(i).getSize() + )) + .toList(); + } + + public static List toAttachmentResponseList(List attachments) { return attachments.stream() .map(attachment -> new AttachmentResponse( diff --git a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java index 7812e8db..e964316e 100644 --- a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java @@ -1,8 +1,13 @@ package clap.server.application.port.inbound.comment; import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; public interface PostCommentUsecase { void save(Long userId, Long taskId, PostAndEditCommentRequest request); + + void saveCommentAttachment(Long userId, Long taskId, List files); } diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index 17fd2def..f515bfae 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -1,11 +1,13 @@ package clap.server.application.service.comment; import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.adapter.outbound.infrastructure.s3.S3UploadAdapter; import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; import clap.server.application.mapper.AttachmentMapper; import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.domain.TaskService; +import clap.server.application.port.outbound.task.CommandAttachmentPort; import clap.server.application.port.outbound.task.CommandCommentPort; import clap.server.common.annotation.architecture.ApplicationService; import clap.server.common.constants.FilePathConstants; @@ -28,6 +30,8 @@ public class PostCommentService implements PostCommentUsecase { private final MemberService memberService; private final TaskService taskService; private final CommandCommentPort commandCommentPort; + private final S3UploadAdapter s3UploadAdapter; + private final CommandAttachmentPort commandAttachmentPort; @Transactional @Override @@ -35,6 +39,34 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { Task task = taskService.findById(taskId); Member member = memberService.findActiveMember(userId); + // 일반 회원일 경우 => 요청자인지 확인 + // 담당자일 경우 => 처리자인지 확인 + if (checkCommenter(task, member)) { + Comment comment = Comment.createComment(member, task, request.content()); + commandCommentPort.saveComment(comment); + } + } + + @Transactional + @Override + public void saveCommentAttachment(Long userId, Long taskId, List files) { + Task task = taskService.findById(taskId); + Member member = memberService.findActiveMember(userId); + + if (checkCommenter(task, member)) { + Comment comment = Comment.createComment(member, task, "Attachment"); + Comment savedComment = commandCommentPort.saveComment(comment); + saveAttachment(files, task, savedComment); + } + } + + private void saveAttachment(List files, Task task, Comment comment) { + List fileUrls = s3UploadAdapter.uploadFiles(FilePathConstants.TASK_IMAGE, files); + List attachments = AttachmentMapper.toCommentAttachments(task, comment, files, fileUrls); + commandAttachmentPort.saveAll(attachments); + } + + public Boolean checkCommenter(Task task, Member member) { // 일반 회원일 경우 => 요청자인지 확인 // 담당자일 경우 => 처리자인지 확인 if ((member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) @@ -42,12 +74,13 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); } - if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) + else if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) && !(member.getMemberId() == task.getRequester().getMemberId())) { throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); } + else { + return true; + } - Comment comment = Comment.createComment(member, task, request); - commandCommentPort.save(comment); } } diff --git a/src/main/java/clap/server/domain/model/task/Attachment.java b/src/main/java/clap/server/domain/model/task/Attachment.java index 3fafddee..11a2bfee 100644 --- a/src/main/java/clap/server/domain/model/task/Attachment.java +++ b/src/main/java/clap/server/domain/model/task/Attachment.java @@ -40,6 +40,17 @@ public static Attachment createAttachment(Task task, String originalName, String .build(); } + public static Attachment createCommentAttachment(Task task, Comment comment, String originalName, String fileUrl, long fileSize) { + return Attachment.builder() + .task(task) + .comment(comment) + .originalName(originalName) + .fileUrl(fileUrl) + .fileSize(formatFileSize(fileSize)) + .isDeleted(false) + .build(); + } + public void softDelete() { this.isDeleted = true; } diff --git a/src/main/java/clap/server/domain/model/task/Comment.java b/src/main/java/clap/server/domain/model/task/Comment.java index b186ac0f..ef4a3a43 100644 --- a/src/main/java/clap/server/domain/model/task/Comment.java +++ b/src/main/java/clap/server/domain/model/task/Comment.java @@ -18,13 +18,12 @@ public class Comment extends BaseTime { private String content; private boolean isModified; - public static Comment createComment(Member member, Task task, PostAndEditCommentRequest request) { + public static Comment createComment(Member member, Task task, String content) { return Comment.builder() .member(member) .task(task) - .content(request.content()) + .content(content) .isModified(false) .build(); } - } From a6cb457e690d60ddcdd3ba9d2d3aea1d0528d319 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:21:48 +0900 Subject: [PATCH 04/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EC=8B=9C=20taskHistory=EC=97=90=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/comment/PostCommentService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index f515bfae..1d411db1 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -3,18 +3,21 @@ import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; import clap.server.adapter.outbound.infrastructure.s3.S3UploadAdapter; import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskHistoryType; import clap.server.application.mapper.AttachmentMapper; import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.domain.TaskService; import clap.server.application.port.outbound.task.CommandAttachmentPort; import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.application.port.outbound.taskhistory.CommandTaskHistoryPort; import clap.server.common.annotation.architecture.ApplicationService; import clap.server.common.constants.FilePathConstants; import clap.server.domain.model.member.Member; import clap.server.domain.model.task.Attachment; import clap.server.domain.model.task.Comment; import clap.server.domain.model.task.Task; +import clap.server.domain.model.task.TaskHistory; import clap.server.exception.ApplicationException; import clap.server.exception.code.MemberErrorCode; import lombok.RequiredArgsConstructor; @@ -32,6 +35,7 @@ public class PostCommentService implements PostCommentUsecase { private final CommandCommentPort commandCommentPort; private final S3UploadAdapter s3UploadAdapter; private final CommandAttachmentPort commandAttachmentPort; + private final CommandTaskHistoryPort commandTaskHistoryPort; @Transactional @Override @@ -44,6 +48,9 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { if (checkCommenter(task, member)) { Comment comment = Comment.createComment(member, task, request.content()); commandCommentPort.saveComment(comment); + + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,comment); + commandTaskHistoryPort.save(taskHistory); } } @@ -57,6 +64,9 @@ public void saveCommentAttachment(Long userId, Long taskId, List Comment comment = Comment.createComment(member, task, "Attachment"); Comment savedComment = commandCommentPort.saveComment(comment); saveAttachment(files, task, savedComment); + + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member,comment); + commandTaskHistoryPort.save(taskHistory); } } From 914728476b499b1dd4253e7d4fbc59d3efb3fb90 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:25:27 +0900 Subject: [PATCH 05/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EC=8B=9C=20taskHistory=EC=97=90=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=802?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/comment/PostCommentService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index 1d411db1..0d9ca297 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -47,9 +47,9 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { // 담당자일 경우 => 처리자인지 확인 if (checkCommenter(task, member)) { Comment comment = Comment.createComment(member, task, request.content()); - commandCommentPort.saveComment(comment); + Comment savedComment = commandCommentPort.saveComment(comment); - TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,comment); + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,savedComment); commandTaskHistoryPort.save(taskHistory); } } @@ -65,7 +65,7 @@ public void saveCommentAttachment(Long userId, Long taskId, List Comment savedComment = commandCommentPort.saveComment(comment); saveAttachment(files, task, savedComment); - TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member,comment); + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member, savedComment); commandTaskHistoryPort.save(taskHistory); } } From ef44e6ef5af8083eca7bf20298a77071ef8e4e8d Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 30 Jan 2025 18:15:15 +0900 Subject: [PATCH 06/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84(?= =?UTF-8?q?=EC=B2=A8=EB=B6=80=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=20=EC=95=84?= =?UTF-8?q?=EB=8B=8C=20=EC=9D=BC=EB=B0=98=20=EB=8C=93=EA=B8=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/comment/PostCommentController.java | 32 +++++++++++ .../dto/task/PostAndEditCommentRequest.java | 7 +++ .../CommentPersistenceAdapter.java | 20 ++++++- .../inbound/comment/PostCommentUsecase.java | 8 +++ .../taskhistory/CommandCommentPort.java | 2 +- .../service/comment/PostCommentService.java | 53 +++++++++++++++++++ .../server/domain/model/task/Comment.java | 10 ++++ 7 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java create mode 100644 src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java create mode 100644 src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java create mode 100644 src/main/java/clap/server/application/service/comment/PostCommentService.java diff --git a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java new file mode 100644 index 00000000..5c93887a --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java @@ -0,0 +1,32 @@ +package clap.server.adapter.inbound.web.comment; + +import clap.server.adapter.inbound.security.SecurityUserDetails; +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.application.port.inbound.comment.PostCommentUsecase; +import clap.server.common.annotation.architecture.WebAdapter; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "02. Task", description = "작업 생성/수정 API") +@WebAdapter +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/comment") +public class PostCommentController { + + private final PostCommentUsecase postCommentUsecase; + + @Operation(summary = "댓글 작성") + @PostMapping("/{taskId}") + @Secured({"ROLE_MANAGER", "ROLE_USER"}) + public void createTask( + @AuthenticationPrincipal SecurityUserDetails userInfo, + @PathVariable Long taskId, + @RequestBody(required = true) PostAndEditCommentRequest request){ + postCommentUsecase.save(userInfo.getUserId(), taskId, request); + } +} diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java new file mode 100644 index 00000000..41baf2c7 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java @@ -0,0 +1,7 @@ +package clap.server.adapter.inbound.web.dto.task; + + +public record PostAndEditCommentRequest( + String content +) { +} diff --git a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java index 48b65cf7..046a875b 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java @@ -1,13 +1,29 @@ package clap.server.adapter.outbound.persistense; -import clap.server.application.port.outbound.taskhistory.LoadCommentPort; +import clap.server.adapter.outbound.persistense.mapper.CommentPersistenceMapper; +import clap.server.adapter.outbound.persistense.repository.task.CommentRepository; +import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.application.port.outbound.task.LoadCommentPort; +import clap.server.common.annotation.architecture.PersistenceAdapter; import clap.server.domain.model.task.Comment; +import lombok.RequiredArgsConstructor; import java.util.Optional; -public class CommentPersistenceAdapter implements LoadCommentPort { +@PersistenceAdapter +@RequiredArgsConstructor +public class CommentPersistenceAdapter implements LoadCommentPort, CommandCommentPort { + + private final CommentRepository commentRepository; + private final CommentPersistenceMapper commentPersistenceMapper; + @Override public Optional findById(Long id) { return Optional.empty(); } + + @Override + public void save(Comment comment) { + commentRepository.save(commentPersistenceMapper.toEntity(comment)); + } } diff --git a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java new file mode 100644 index 00000000..7812e8db --- /dev/null +++ b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java @@ -0,0 +1,8 @@ +package clap.server.application.port.inbound.comment; + +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; + +public interface PostCommentUsecase { + + void save(Long userId, Long taskId, PostAndEditCommentRequest request); +} diff --git a/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java b/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java index ed378deb..1adf7116 100644 --- a/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java +++ b/src/main/java/clap/server/application/port/outbound/taskhistory/CommandCommentPort.java @@ -5,5 +5,5 @@ import java.util.Optional; public interface CommandCommentPort { - Optional save(Comment comment); + void save(Comment comment); } \ No newline at end of file diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java new file mode 100644 index 00000000..17fd2def --- /dev/null +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -0,0 +1,53 @@ +package clap.server.application.service.comment; + +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; +import clap.server.application.mapper.AttachmentMapper; +import clap.server.application.port.inbound.comment.PostCommentUsecase; +import clap.server.application.port.inbound.domain.MemberService; +import clap.server.application.port.inbound.domain.TaskService; +import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.common.annotation.architecture.ApplicationService; +import clap.server.common.constants.FilePathConstants; +import clap.server.domain.model.member.Member; +import clap.server.domain.model.task.Attachment; +import clap.server.domain.model.task.Comment; +import clap.server.domain.model.task.Task; +import clap.server.exception.ApplicationException; +import clap.server.exception.code.MemberErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@ApplicationService +@RequiredArgsConstructor +public class PostCommentService implements PostCommentUsecase { + + private final MemberService memberService; + private final TaskService taskService; + private final CommandCommentPort commandCommentPort; + + @Transactional + @Override + public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { + Task task = taskService.findById(taskId); + Member member = memberService.findActiveMember(userId); + + // 일반 회원일 경우 => 요청자인지 확인 + // 담당자일 경우 => 처리자인지 확인 + if ((member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) + && !(member.getMemberId() == task.getProcessor().getMemberId())) { + throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); + } + + if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) + && !(member.getMemberId() == task.getRequester().getMemberId())) { + throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); + } + + Comment comment = Comment.createComment(member, task, request); + commandCommentPort.save(comment); + } +} diff --git a/src/main/java/clap/server/domain/model/task/Comment.java b/src/main/java/clap/server/domain/model/task/Comment.java index 52822050..b186ac0f 100644 --- a/src/main/java/clap/server/domain/model/task/Comment.java +++ b/src/main/java/clap/server/domain/model/task/Comment.java @@ -1,5 +1,6 @@ package clap.server.domain.model.task; +import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; import clap.server.domain.model.common.BaseTime; import clap.server.domain.model.member.Member; import lombok.AccessLevel; @@ -17,4 +18,13 @@ public class Comment extends BaseTime { private String content; private boolean isModified; + public static Comment createComment(Member member, Task task, PostAndEditCommentRequest request) { + return Comment.builder() + .member(member) + .task(task) + .content(request.content()) + .isModified(false) + .build(); + } + } From 39c3893611481827421747b1f1ef984a82321741 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 30 Jan 2025 23:56:42 +0900 Subject: [PATCH 07/58] =?UTF-8?q?CLAP-177=20fix:=20rebase=ED=95=98?= =?UTF-8?q?=EB=A9=B0=20=EB=B0=9C=EC=83=9D=ED=95=9C=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../outbound/persistense/CommentPersistenceAdapter.java | 6 ++++-- .../port/outbound/task/CommandCommentPort.java | 8 ++++++++ .../application/port/outbound/task/LoadCommentPort.java | 9 +++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java create mode 100644 src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java diff --git a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java index 046a875b..927e5d12 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/CommentPersistenceAdapter.java @@ -1,5 +1,6 @@ package clap.server.adapter.outbound.persistense; +import clap.server.adapter.outbound.persistense.entity.task.CommentEntity; import clap.server.adapter.outbound.persistense.mapper.CommentPersistenceMapper; import clap.server.adapter.outbound.persistense.repository.task.CommentRepository; import clap.server.application.port.outbound.task.CommandCommentPort; @@ -23,7 +24,8 @@ public Optional findById(Long id) { } @Override - public void save(Comment comment) { - commentRepository.save(commentPersistenceMapper.toEntity(comment)); + public Comment saveComment(Comment comment) { + CommentEntity commentEntity = commentRepository.save(commentPersistenceMapper.toEntity(comment)); + return commentPersistenceMapper.toDomain(commentEntity); } } diff --git a/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java b/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java new file mode 100644 index 00000000..834732f3 --- /dev/null +++ b/src/main/java/clap/server/application/port/outbound/task/CommandCommentPort.java @@ -0,0 +1,8 @@ +package clap.server.application.port.outbound.task; + +import clap.server.domain.model.task.Comment; + +public interface CommandCommentPort { + + Comment saveComment(Comment comment); +} diff --git a/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java b/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java new file mode 100644 index 00000000..d3a42ea2 --- /dev/null +++ b/src/main/java/clap/server/application/port/outbound/task/LoadCommentPort.java @@ -0,0 +1,9 @@ +package clap.server.application.port.outbound.task; + +import clap.server.domain.model.task.Comment; + +import java.util.Optional; + +public interface LoadCommentPort { + Optional findById(Long commentId); +} From fa353710d758982f71dff7d987bfe3917e84ea90 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:00:13 +0900 Subject: [PATCH 08/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84(?= =?UTF-8?q?=EC=B2=A8=EB=B6=80=20=ED=8C=8C=EC=9D=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/comment/PostCommentController.java | 19 +++++++++ .../dto/task/PostAndEditCommentRequest.java | 3 ++ .../application/mapper/AttachmentMapper.java | 15 +++++++ .../inbound/comment/PostCommentUsecase.java | 5 +++ .../service/comment/PostCommentService.java | 39 +++++++++++++++++-- .../server/domain/model/task/Attachment.java | 11 ++++++ .../server/domain/model/task/Comment.java | 5 +-- 7 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java index 5c93887a..65656da1 100644 --- a/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java +++ b/src/main/java/clap/server/adapter/inbound/web/comment/PostCommentController.java @@ -5,11 +5,17 @@ import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.security.access.annotation.Secured; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; @Tag(name = "02. Task", description = "작업 생성/수정 API") @WebAdapter @@ -21,6 +27,7 @@ public class PostCommentController { private final PostCommentUsecase postCommentUsecase; @Operation(summary = "댓글 작성") + @Parameter(name = "labelId", description = "댓글 작성할 작업 고유 ID", required = true, in = ParameterIn.PATH) @PostMapping("/{taskId}") @Secured({"ROLE_MANAGER", "ROLE_USER"}) public void createTask( @@ -29,4 +36,16 @@ public void createTask( @RequestBody(required = true) PostAndEditCommentRequest request){ postCommentUsecase.save(userInfo.getUserId(), taskId, request); } + + @Operation(summary = "댓글 작성(첨부 파일)") + @Parameter(name = "labelId", description = "댓글 작성할 작업 고유 ID", required = true, in = ParameterIn.PATH) + @PostMapping("/attachment/{taskId}") + @Secured({"ROLE_MANAGER", "ROLE_USER"}) + public void createAttachmentTask( + @AuthenticationPrincipal SecurityUserDetails userInfo, + @PathVariable Long taskId, + @RequestPart(name = "attachment") @NotNull List attachments) { + postCommentUsecase.saveCommentAttachment(userInfo.getUserId(), taskId, attachments); + } + } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java index 41baf2c7..b66a6506 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/PostAndEditCommentRequest.java @@ -1,7 +1,10 @@ package clap.server.adapter.inbound.web.dto.task; +import io.swagger.v3.oas.annotations.media.Schema; + public record PostAndEditCommentRequest( + @Schema(description = "댓글 내용") String content ) { } diff --git a/src/main/java/clap/server/application/mapper/AttachmentMapper.java b/src/main/java/clap/server/application/mapper/AttachmentMapper.java index 119221b6..217780eb 100644 --- a/src/main/java/clap/server/application/mapper/AttachmentMapper.java +++ b/src/main/java/clap/server/application/mapper/AttachmentMapper.java @@ -2,6 +2,7 @@ import clap.server.adapter.inbound.web.dto.task.AttachmentResponse; import clap.server.domain.model.task.Attachment; +import clap.server.domain.model.task.Comment; import clap.server.domain.model.task.Task; import org.springframework.web.multipart.MultipartFile; @@ -9,6 +10,7 @@ import java.util.stream.IntStream; import static clap.server.domain.model.task.Attachment.createAttachment; +import static clap.server.domain.model.task.Attachment.createCommentAttachment; public class AttachmentMapper { private AttachmentMapper() { @@ -26,6 +28,19 @@ public static List toTaskAttachments(Task task, List .toList(); } + public static List toCommentAttachments(Task task, Comment comment, List files, List fileUrls) { + return IntStream.range(0, files.size()) + .mapToObj(i -> createCommentAttachment( + task, + comment, + files.get(i).getOriginalFilename(), + fileUrls.get(i), + files.get(i).getSize() + )) + .toList(); + } + + public static List toAttachmentResponseList(List attachments) { return attachments.stream() .map(attachment -> new AttachmentResponse( diff --git a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java index 7812e8db..e964316e 100644 --- a/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/comment/PostCommentUsecase.java @@ -1,8 +1,13 @@ package clap.server.application.port.inbound.comment; import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; public interface PostCommentUsecase { void save(Long userId, Long taskId, PostAndEditCommentRequest request); + + void saveCommentAttachment(Long userId, Long taskId, List files); } diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index 17fd2def..f515bfae 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -1,11 +1,13 @@ package clap.server.application.service.comment; import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; +import clap.server.adapter.outbound.infrastructure.s3.S3UploadAdapter; import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; import clap.server.application.mapper.AttachmentMapper; import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.domain.TaskService; +import clap.server.application.port.outbound.task.CommandAttachmentPort; import clap.server.application.port.outbound.task.CommandCommentPort; import clap.server.common.annotation.architecture.ApplicationService; import clap.server.common.constants.FilePathConstants; @@ -28,6 +30,8 @@ public class PostCommentService implements PostCommentUsecase { private final MemberService memberService; private final TaskService taskService; private final CommandCommentPort commandCommentPort; + private final S3UploadAdapter s3UploadAdapter; + private final CommandAttachmentPort commandAttachmentPort; @Transactional @Override @@ -35,6 +39,34 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { Task task = taskService.findById(taskId); Member member = memberService.findActiveMember(userId); + // 일반 회원일 경우 => 요청자인지 확인 + // 담당자일 경우 => 처리자인지 확인 + if (checkCommenter(task, member)) { + Comment comment = Comment.createComment(member, task, request.content()); + commandCommentPort.saveComment(comment); + } + } + + @Transactional + @Override + public void saveCommentAttachment(Long userId, Long taskId, List files) { + Task task = taskService.findById(taskId); + Member member = memberService.findActiveMember(userId); + + if (checkCommenter(task, member)) { + Comment comment = Comment.createComment(member, task, "Attachment"); + Comment savedComment = commandCommentPort.saveComment(comment); + saveAttachment(files, task, savedComment); + } + } + + private void saveAttachment(List files, Task task, Comment comment) { + List fileUrls = s3UploadAdapter.uploadFiles(FilePathConstants.TASK_IMAGE, files); + List attachments = AttachmentMapper.toCommentAttachments(task, comment, files, fileUrls); + commandAttachmentPort.saveAll(attachments); + } + + public Boolean checkCommenter(Task task, Member member) { // 일반 회원일 경우 => 요청자인지 확인 // 담당자일 경우 => 처리자인지 확인 if ((member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) @@ -42,12 +74,13 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); } - if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) + else if ((member.getMemberInfo().getRole() == MemberRole.ROLE_USER) && !(member.getMemberId() == task.getRequester().getMemberId())) { throw new ApplicationException(MemberErrorCode.NOT_A_COMMENTER); } + else { + return true; + } - Comment comment = Comment.createComment(member, task, request); - commandCommentPort.save(comment); } } diff --git a/src/main/java/clap/server/domain/model/task/Attachment.java b/src/main/java/clap/server/domain/model/task/Attachment.java index 3fafddee..11a2bfee 100644 --- a/src/main/java/clap/server/domain/model/task/Attachment.java +++ b/src/main/java/clap/server/domain/model/task/Attachment.java @@ -40,6 +40,17 @@ public static Attachment createAttachment(Task task, String originalName, String .build(); } + public static Attachment createCommentAttachment(Task task, Comment comment, String originalName, String fileUrl, long fileSize) { + return Attachment.builder() + .task(task) + .comment(comment) + .originalName(originalName) + .fileUrl(fileUrl) + .fileSize(formatFileSize(fileSize)) + .isDeleted(false) + .build(); + } + public void softDelete() { this.isDeleted = true; } diff --git a/src/main/java/clap/server/domain/model/task/Comment.java b/src/main/java/clap/server/domain/model/task/Comment.java index b186ac0f..ef4a3a43 100644 --- a/src/main/java/clap/server/domain/model/task/Comment.java +++ b/src/main/java/clap/server/domain/model/task/Comment.java @@ -18,13 +18,12 @@ public class Comment extends BaseTime { private String content; private boolean isModified; - public static Comment createComment(Member member, Task task, PostAndEditCommentRequest request) { + public static Comment createComment(Member member, Task task, String content) { return Comment.builder() .member(member) .task(task) - .content(request.content()) + .content(content) .isModified(false) .build(); } - } From bdae98d0d37d435a05834a1a1a3705af544e056f Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:21:48 +0900 Subject: [PATCH 09/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EC=8B=9C=20taskHistory=EC=97=90=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/comment/PostCommentService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index f515bfae..1d411db1 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -3,18 +3,21 @@ import clap.server.adapter.inbound.web.dto.task.PostAndEditCommentRequest; import clap.server.adapter.outbound.infrastructure.s3.S3UploadAdapter; import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole; +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskHistoryType; import clap.server.application.mapper.AttachmentMapper; import clap.server.application.port.inbound.comment.PostCommentUsecase; import clap.server.application.port.inbound.domain.MemberService; import clap.server.application.port.inbound.domain.TaskService; import clap.server.application.port.outbound.task.CommandAttachmentPort; import clap.server.application.port.outbound.task.CommandCommentPort; +import clap.server.application.port.outbound.taskhistory.CommandTaskHistoryPort; import clap.server.common.annotation.architecture.ApplicationService; import clap.server.common.constants.FilePathConstants; import clap.server.domain.model.member.Member; import clap.server.domain.model.task.Attachment; import clap.server.domain.model.task.Comment; import clap.server.domain.model.task.Task; +import clap.server.domain.model.task.TaskHistory; import clap.server.exception.ApplicationException; import clap.server.exception.code.MemberErrorCode; import lombok.RequiredArgsConstructor; @@ -32,6 +35,7 @@ public class PostCommentService implements PostCommentUsecase { private final CommandCommentPort commandCommentPort; private final S3UploadAdapter s3UploadAdapter; private final CommandAttachmentPort commandAttachmentPort; + private final CommandTaskHistoryPort commandTaskHistoryPort; @Transactional @Override @@ -44,6 +48,9 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { if (checkCommenter(task, member)) { Comment comment = Comment.createComment(member, task, request.content()); commandCommentPort.saveComment(comment); + + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,comment); + commandTaskHistoryPort.save(taskHistory); } } @@ -57,6 +64,9 @@ public void saveCommentAttachment(Long userId, Long taskId, List Comment comment = Comment.createComment(member, task, "Attachment"); Comment savedComment = commandCommentPort.saveComment(comment); saveAttachment(files, task, savedComment); + + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member,comment); + commandTaskHistoryPort.save(taskHistory); } } From 69c86d2b6b6bb42c271b6edddcc6aa33ca3588c4 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 31 Jan 2025 00:25:27 +0900 Subject: [PATCH 10/58] =?UTF-8?q?CLAP-177=20feat:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EC=8B=9C=20taskHistory=EC=97=90=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=802?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/comment/PostCommentService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/clap/server/application/service/comment/PostCommentService.java b/src/main/java/clap/server/application/service/comment/PostCommentService.java index 1d411db1..0d9ca297 100644 --- a/src/main/java/clap/server/application/service/comment/PostCommentService.java +++ b/src/main/java/clap/server/application/service/comment/PostCommentService.java @@ -47,9 +47,9 @@ public void save(Long userId, Long taskId, PostAndEditCommentRequest request) { // 담당자일 경우 => 처리자인지 확인 if (checkCommenter(task, member)) { Comment comment = Comment.createComment(member, task, request.content()); - commandCommentPort.saveComment(comment); + Comment savedComment = commandCommentPort.saveComment(comment); - TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,comment); + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT, task, null, member,savedComment); commandTaskHistoryPort.save(taskHistory); } } @@ -65,7 +65,7 @@ public void saveCommentAttachment(Long userId, Long taskId, List Comment savedComment = commandCommentPort.saveComment(comment); saveAttachment(files, task, savedComment); - TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member,comment); + TaskHistory taskHistory = TaskHistory.createTaskHistory(TaskHistoryType.COMMENT_FILE, task, null, member, savedComment); commandTaskHistoryPort.save(taskHistory); } } From fa2bcc3556b01d275c0c18e6e420c47043393ccf Mon Sep 17 00:00:00 2001 From: joowojr Date: Wed, 29 Jan 2025 22:12:29 +0700 Subject: [PATCH 11/58] =?UTF-8?q?CLAP-172=20Feat:=20=EC=9B=B9=ED=9B=85=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit