diff --git a/module-api/src/main/java/com/mile/controller/comment/CommentController.java b/module-api/src/main/java/com/mile/controller/comment/CommentController.java index d01fcb25..827ac679 100644 --- a/module-api/src/main/java/com/mile/controller/comment/CommentController.java +++ b/module-api/src/main/java/com/mile/controller/comment/CommentController.java @@ -3,21 +3,27 @@ import com.mile.authentication.PrincipalHandler; import com.mile.comment.service.CommentService; +import com.mile.commentreply.service.dto.ReplyCreateRequest; import com.mile.dto.SuccessResponse; import com.mile.exception.message.SuccessMessage; import com.mile.resolver.comment.CommentIdPathVariable; +import com.mile.resolver.reply.ReplyIdPathVariable; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@Slf4j @RequestMapping("/api/comment") @RequiredArgsConstructor -public class CommentController implements CommentControllerSwagger{ +public class CommentController implements CommentControllerSwagger { private final CommentService commentService; private final PrincipalHandler principalHandler; @@ -30,4 +36,26 @@ public ResponseEntity deleteComment( commentService.deleteComment(commentId, principalHandler.getUserIdFromPrincipal()); return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.of(SuccessMessage.COMMENT_DELETE_SUCCESS)); } + + @PostMapping("/{commentId}") + public ResponseEntity createCommentReply( + @CommentIdPathVariable final Long commentId, + @RequestBody final ReplyCreateRequest createRequest, + @PathVariable("commentId") final String commentUrl + ) { + return ResponseEntity.status(HttpStatus.CREATED).header("Location", + commentService.createCommentReply( + principalHandler.getUserIdFromPrincipal(), + commentId, createRequest + )).body(SuccessResponse.of(SuccessMessage.REPLY_CREATE_SUCCESS)); + } + + @DeleteMapping("/reply/{replyId}") + public ResponseEntity deleteCommentReply( + @ReplyIdPathVariable final Long replyId, + @PathVariable("replyId") final String replyUrl + ) { + commentService.deleteReply(principalHandler.getUserIdFromPrincipal(), replyId); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.REPLY_DELETE_SUCCESS)); + } } diff --git a/module-api/src/main/java/com/mile/controller/comment/CommentControllerSwagger.java b/module-api/src/main/java/com/mile/controller/comment/CommentControllerSwagger.java index bc51889f..9ca34a68 100644 --- a/module-api/src/main/java/com/mile/controller/comment/CommentControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/comment/CommentControllerSwagger.java @@ -1,5 +1,6 @@ package com.mile.controller.comment; +import com.mile.commentreply.service.dto.ReplyCreateRequest; import com.mile.dto.ErrorResponse; import com.mile.dto.SuccessResponse; import io.swagger.v3.oas.annotations.Operation; @@ -13,9 +14,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; -import java.security.Principal; - -@Tag(name = "Comment", description = "댓글 관련 API - 현재는 댓글 삭제만 API 해당") +@Tag(name = "Comment", description = "댓글 관련 API") public interface CommentControllerSwagger { @Operation(description = "댓글 삭제 API") @@ -34,4 +33,40 @@ ResponseEntity deleteComment( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long commentId, @PathVariable("commentId") final String commentUrl ); + + + @Operation(description = "대댓글 등록 API") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "댓글 등록이 완료되었습니다."), + @ApiResponse(responseCode = "403", description = "해당 사용자는 댓글에 접근 권한이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "404", description = "해당 댓글이 존재하지 않습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity createCommentReply( + @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long commentId, + final ReplyCreateRequest createRequest, + @PathVariable("commentId") final String commentUrl + ); + + @Operation(description = "대댓글 삭제 API") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "대댓글 삭제가 완료되었습니다."), + @ApiResponse(responseCode = "403", description = "해당 사용자는 댓글에 접근 권한이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "404", description = "해당 댓글이 존재하지 않습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity deleteCommentReply( + @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long replyId, + @PathVariable("replyId") final String replyUrl + ); } diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimController.java b/module-api/src/main/java/com/mile/controller/moim/MoimController.java index b492d592..e332af5d 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimController.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimController.java @@ -11,20 +11,21 @@ import com.mile.moim.service.dto.MoimCreateRequest; import com.mile.moim.service.dto.MoimCreateResponse; import com.mile.moim.service.dto.MoimCuriousPostListResponse; +import com.mile.moim.service.dto.MoimInfoModifyRequest; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; -import com.mile.moim.service.dto.MoimTopicInfoListResponse; -import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; -import com.mile.moim.service.dto.MoimInfoModifyRequest; +import com.mile.moim.service.dto.MoimListOfUserResponse; +import com.mile.moim.service.dto.MoimNameConflictCheckResponse; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; import com.mile.moim.service.dto.MoimTopicResponse; import com.mile.moim.service.dto.MoimWriterNameListGetResponse; import com.mile.moim.service.dto.PopularWriterListResponse; import com.mile.moim.service.dto.TemporaryPostExistResponse; import com.mile.moim.service.dto.TopicCreateRequest; import com.mile.moim.service.dto.TopicListResponse; -import com.mile.moim.service.dto.WriterNameConflictCheckResponse; import com.mile.moim.service.dto.WriterMemberJoinRequest; +import com.mile.moim.service.dto.WriterNameConflictCheckResponse; import com.mile.resolver.moim.MoimIdPathVariable; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -60,7 +61,7 @@ public SuccessResponse getTopicsFromMoim( @Override - @GetMapping("/{moimId}/") + @GetMapping("/{moimId}/name/validation") public ResponseEntity> checkConflictOfWriterName( @MoimIdPathVariable final Long moimId, @RequestParam final String writerName, @@ -89,7 +90,7 @@ public ResponseEntity> getInvitation @PathVariable("moimId") final String moimUrl ) { return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_INVITE_INFO_GET_SUCCESS, - moimService.getMoimInvitationInfo(moimId))); + moimService.getMoimInvitationInfo(principalHandler.getUserIdFromPrincipal(), moimId))); } @Override @@ -161,6 +162,7 @@ public ResponseEntity> getMoimInfoForOwne ) { return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_INFO_FOR_OWNER_GET_SUCCESS, moimService.getMoimInfoForOwner(moimId, principalHandler.getUserIdFromPrincipal()))); } + @Override @PostMapping("/{moimId}/topic") public ResponseEntity createTopicOfMoim( @@ -168,7 +170,7 @@ public ResponseEntity createTopicOfMoim( @RequestBody final TopicCreateRequest createRequest, @PathVariable("moimId") final String moimUrl ) { - return ResponseEntity.created(URI.create(moimService.createTopic(moimId,principalHandler.getUserIdFromPrincipal(), createRequest))).body(SuccessResponse.of(SuccessMessage.TOPIC_CREATE_SUCCESS)); + return ResponseEntity.created(URI.create(moimService.createTopic(moimId, principalHandler.getUserIdFromPrincipal(), createRequest))).body(SuccessResponse.of(SuccessMessage.TOPIC_CREATE_SUCCESS)); } @GetMapping("/best") @@ -243,5 +245,14 @@ public ResponseEntity> getWriterN @PathVariable("moimId") final String moimUrl ) { return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_WRITERNAME_LIST_GET_SUCCESS, moimService.getWriterNameListOfMoim(moimId, principalHandler.getUserIdFromPrincipal(), page))); - }; + } + + ; + + @Override + @GetMapping("/moimList") + public ResponseEntity> getMoimListOfUser() { + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.MOIM_LIST_OF_USER_GET_SUCCESS, moimService.getMoimOfUserList(principalHandler.getUserIdFromPrincipal()))); + } + } diff --git a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java index 2fbc7788..f380faaa 100644 --- a/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/moim/MoimControllerSwagger.java @@ -8,21 +8,21 @@ import com.mile.moim.service.dto.MoimCreateRequest; import com.mile.moim.service.dto.MoimCreateResponse; import com.mile.moim.service.dto.MoimCuriousPostListResponse; +import com.mile.moim.service.dto.MoimInfoModifyRequest; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; -import com.mile.moim.service.dto.MoimTopicInfoListResponse; -import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; +import com.mile.moim.service.dto.MoimListOfUserResponse; import com.mile.moim.service.dto.MoimNameConflictCheckResponse; -import com.mile.moim.service.dto.MoimInfoModifyRequest; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; import com.mile.moim.service.dto.MoimTopicResponse; import com.mile.moim.service.dto.MoimWriterNameListGetResponse; +import com.mile.moim.service.dto.PopularWriterListResponse; import com.mile.moim.service.dto.TemporaryPostExistResponse; import com.mile.moim.service.dto.TopicCreateRequest; import com.mile.moim.service.dto.TopicListResponse; -import com.mile.moim.service.dto.PopularWriterListResponse; -import com.mile.moim.service.dto.WriterNameConflictCheckResponse; import com.mile.moim.service.dto.WriterMemberJoinRequest; +import com.mile.moim.service.dto.WriterNameConflictCheckResponse; import com.mile.resolver.moim.MoimIdPathVariable; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -176,10 +176,10 @@ SuccessResponse getTemporaryPost( @Operation(summary = "초대 링크에서 모임 정보 조회") @ApiResponses( value = { - @ApiResponse(responseCode = "200", description = "댓글 조회가 완료되었습니다."), - @ApiResponse(responseCode = "404", description = "해당 글모임이 존재하지 않습니다.\n", + @ApiResponse(responseCode = "200", description = "댓글 조회가 완료되었습니다."), + @ApiResponse(responseCode = "404", description = "해당 글모임이 존재하지 않습니다.\n", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), - @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } ) @@ -187,11 +187,15 @@ ResponseEntity> getInvitationInfo( @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long moimId, @PathVariable("moimId") final String moimUrl ); + @Operation(summary = "필명 중복 확인") @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "댓글 중복 여부가 조회되었습니다."), - @ApiResponse(responseCode = "404" , description = "1. 해당 모임은 존재하지 않습니다.\n"), + @ApiResponse(responseCode = "400", description = "사용 불가능한 필명입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "404", description = "1. 해당 모임은 존재하지 않습니다.\n", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } @@ -201,14 +205,14 @@ ResponseEntity> checkConflictOf final String writerName, @PathVariable("moimId") final String moimUrl ); - + @Operation(summary = "글모임 링크 접속 후 모임원 가입") @ApiResponses( value = { - @ApiResponse(responseCode = "201", description = "모임 가입에 완료되었습니다"), - @ApiResponse(responseCode = "400" ,description = "1. 소개 글은 최대 110자 이내로 작성해주세요.\n" + - "2. 필명이 입력되지 않았습니다.\n" + - "3. 필명은 최대 8자 이내로 작성해주세요.\n"), + @ApiResponse(responseCode = "201", description = "모임 가입에 완료되었습니다"), + @ApiResponse(responseCode = "400", description = "1. 소개 글은 최대 110자 이내로 작성해주세요.\n" + + "2. 필명이 입력되지 않았습니다.\n" + + "3. 필명은 최대 8자 이내로 작성해주세요.\n"), @ApiResponse(responseCode = "404", description = "해당 모임은 존재하지 않습니다."), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) @@ -240,8 +244,8 @@ ResponseEntity> getMoimTopicList( @Operation(summary = "관리자 페이지 모임 정보 수정") @ApiResponses( value = { - @ApiResponse(responseCode = "204", description = "모임 정보 수정이 완료되었습니다."), - @ApiResponse(responseCode = "400" ,description = "1. 소개 글은 최대 100자 이내로 작성해주세요.\n" + + @ApiResponse(responseCode = "204", description = "모임 정보 수정이 완료되었습니다."), + @ApiResponse(responseCode = "400", description = "1. 소개 글은 최대 100자 이내로 작성해주세요.\n" + "2. 글모임 이름은 최대 10 글자 이내로 작성해주세요.\n"), @ApiResponse(responseCode = "401", description = "로그인 후 진행해주세요."), @ApiResponse(responseCode = "403", description = "사용자는 해당 모임의 모임장이 아닙니다."), @@ -253,13 +257,14 @@ ResponseEntity modifyMoimInformation( @RequestBody final MoimInfoModifyRequest request, @PathVariable("moimId") final String moimUrl ); - + @Operation(summary = "글모임 이름 중복확인") @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "글모임 이름 중복 확인이 완료되었습니다."), - + @ApiResponse(responseCode = "400", description = "사용 불가능한 모임명입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) } @@ -287,7 +292,7 @@ ResponseEntity> getInvitationCode( @ApiResponses( value = { @ApiResponse(responseCode = "201", description = "글감 리스트 조회가 완료되었습니다."), - @ApiResponse(responseCode = "400" ,description = "1. 글모임명은 최대 10글자 이내로 작성해주세요.\n" + + @ApiResponse(responseCode = "400", description = "1. 글모임명은 최대 10글자 이내로 작성해주세요.\n" + "2. 필명은 최대 8글자 이내로 작성해주세요.\n" + "3. 글모임장 소개글은 최대 100자 이내로 작성해주세요." + "4. 글감 소개글은 최대 90자 이내로 작성해주세요."), @@ -304,9 +309,9 @@ ResponseEntity> createMoim( @ApiResponses( value = { @ApiResponse(responseCode = "201", description = "글감 생성이 완료되었습니다."), - @ApiResponse(responseCode = "400",description = "1. 글감은 최대 15자 이내로 작성해주세요.\n" + @ApiResponse(responseCode = "400", description = "1. 글감은 최대 15자 이내로 작성해주세요.\n" + "2. 글감 제목이 비어있습니다.\n" + "3. 글감 태그는 최대 5자 이내로 작성해주세요.\n" - + "4. 글감 태그가 비어있습니다.\n" + "5. 글감 설명은 최대 90자 이내로 작성해주세요." + + "4. 글감 태그가 비어있습니다.\n" + "5. 글감 설명은 최대 90자 이내로 작성해주세요." ), @ApiResponse(responseCode = "401", description = "로그인 후 이용해주세요.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))), @@ -364,4 +369,18 @@ ResponseEntity> getWriterNameList @RequestParam final int page, @PathVariable("moimId") final String moimUrl ); + + @Operation(summary = "유저 글모임 리스트 조회") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "글모임 리스트 조회가 조회되었습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "401", description = "로그인 후 이용해주세요.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity> getMoimListOfUser(); + } diff --git a/module-api/src/main/java/com/mile/controller/post/PostController.java b/module-api/src/main/java/com/mile/controller/post/PostController.java index bd70fb4b..f900802d 100644 --- a/module-api/src/main/java/com/mile/controller/post/PostController.java +++ b/module-api/src/main/java/com/mile/controller/post/PostController.java @@ -16,7 +16,6 @@ import com.mile.post.service.dto.TemporaryPostGetResponse; import com.mile.resolver.post.PostIdPathVariable; import com.mile.writername.service.dto.WriterNameResponse; -import feign.Response; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -152,6 +151,7 @@ public SuccessResponse createPost( )); } + @Override @PostMapping("/temporary") public SuccessResponse createTemporaryPost( @RequestBody final TemporaryPostCreateRequest temporaryPostCreateRequest @@ -163,6 +163,20 @@ public SuccessResponse createTemporaryPost( return SuccessResponse.of(SuccessMessage.TEMPORARY_POST_CREATE_SUCCESS); } + @Override + @DeleteMapping("/temporary/{postId}") + public ResponseEntity deleteTemporaryPost( + @PostIdPathVariable final Long postId, + @PathVariable("postId") final String postUrl + ) { + postService.deleteTemporaryPost( + principalHandler.getUserIdFromPrincipal(), + postId + ); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.TEMPORARY_POST_DELETE_SUCCESS)); + } + + @Override @PutMapping("/temporary/{postId}") public ResponseEntity> putTemporaryToFixedPost( @PostIdPathVariable final Long postId, diff --git a/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java index 211a2e93..2317007e 100644 --- a/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java +++ b/module-api/src/main/java/com/mile/controller/post/PostControllerSwagger.java @@ -162,6 +162,23 @@ ResponseEntity putPost( @PathVariable("postId") final String postUrl ); + @Operation(summary = "임시저장된 글 삭제") + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "임시 저장 글 삭제가 완료되었습니다."), + @ApiResponse(responseCode = "404", description = "해당 글은 존재하지 않습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "403", description = "해당 사용자는 글 수정/삭제 권한이 없습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))) + } + ) + ResponseEntity deleteTemporaryPost( + @Parameter(schema = @Schema(implementation = String.class), in = ParameterIn.PATH) final Long postId, + @PathVariable("postId") final String postUrl + ); + @Operation(summary = "글 삭제") @ApiResponses( value = { diff --git a/module-common/src/main/java/com/mile/config/web/WebConfig.java b/module-common/src/main/java/com/mile/config/web/WebConfig.java index 46a06f66..fea20b74 100644 --- a/module-common/src/main/java/com/mile/config/web/WebConfig.java +++ b/module-common/src/main/java/com/mile/config/web/WebConfig.java @@ -3,6 +3,7 @@ import com.mile.resolver.comment.CommentVariableResolver; import com.mile.resolver.moim.MoimVariableResolver; import com.mile.resolver.post.PostVariableResolver; +import com.mile.resolver.reply.ReplyVariableResolver; import com.mile.resolver.topic.TopicVariableResolver; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -11,6 +12,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; + @RequiredArgsConstructor @Configuration public class WebConfig implements WebMvcConfigurer { @@ -18,6 +20,8 @@ public class WebConfig implements WebMvcConfigurer { private final TopicVariableResolver topicVariableResolver; private final PostVariableResolver postVariableResolver; private final CommentVariableResolver commentVariableResolver; + private final ReplyVariableResolver replyVariableResolver; + @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") @@ -32,5 +36,6 @@ public void addArgumentResolvers(List resolvers) resolvers.add(topicVariableResolver); resolvers.add(commentVariableResolver); resolvers.add(postVariableResolver); + resolvers.add(replyVariableResolver); } } \ No newline at end of file diff --git a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java index e57d6678..d27beffc 100644 --- a/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/ErrorMessage.java @@ -29,6 +29,7 @@ public enum ErrorMessage { TOPIC_POST_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 글감의 글이 존재하지 않습니다."), MOIM_POST_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 모임의 글이 존재하지 않습니다."), RANDOM_VALUE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "랜덤 글 이름을 생성하는데 실패했습니다."), + REPLY_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "Id에 해당하는 대댓글이 없습니다."), /* Bad Request */ @@ -46,6 +47,9 @@ public enum ErrorMessage { IMAGE_SIZE_INVALID_ERROR(HttpStatus.BAD_REQUEST.value(), "이미지 사이즈는 5MB를 넘을 수 없습니다."), INVALID_URL_EXCEPTION(HttpStatus.BAD_REQUEST.value(), "요청된 URL을 다시 확인해주세요"), LEAST_TOPIC_SIZE_OF_MOIM_ERROR(HttpStatus.BAD_REQUEST.value(), "모임에는 최소 하나의 글감이 있어야 합니다."), + USER_MOIM_ALREADY_JOIN(HttpStatus.BAD_REQUEST.value(), "사용자는 이미 모임에 가입했습니다."), + WRITER_NAME_LENGTH_WRONG(HttpStatus.BAD_REQUEST.value(), "사용 불가능한 필명입니다."), + MOIM_NAME_LENGTH_WRONG(HttpStatus.BAD_REQUEST.value(), "사용 불가능한 모임명입니다."), /* Conflict */ @@ -62,6 +66,7 @@ public enum ErrorMessage { Forbidden */ USER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 모임에 접근 권한이 없습니다."), + REPLY_USER_FORBIDDEN(HttpStatus.UNAUTHORIZED.value(), "사용자에게 해당 대댓글에 대한 권한이 없습니다."), WRITER_AUTHENTICATE_ERROR(HttpStatus.FORBIDDEN.value(), "해당 사용자는 글 생성/수정/삭제 권한이 없습니다."), MOIM_OWNER_AUTHENTICATION_ERROR(HttpStatus.FORBIDDEN.value(), "사용자는 해당 모임의 모임장이 아닙니다."), /* diff --git a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java index ce767a5f..152bc924 100644 --- a/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java +++ b/module-common/src/main/java/com/mile/exception/message/SuccessMessage.java @@ -34,7 +34,7 @@ public enum SuccessMessage { BEST_MOIM_POSTS_GET_SUCCESS(HttpStatus.OK.value(), "베스트 활동 모임과 글 조회가 완료되었습니다."), IS_TEMPORARY_POST_EXIST_GET_SUCCESS(HttpStatus.OK.value(), "임시저장 글 존재 여부 조회가 완료되었습니다."), MOIM_INVITE_INFO_GET_SUCCESS(HttpStatus.OK.value(), "모임의 초대 정보 조회가 완료되었습니다."), - IS_CONFLICT_WRITER_NAME_GET_SUCCESS(HttpStatus.OK.value(), "댓글 중복 여부가 조회되었습니다."), + IS_CONFLICT_WRITER_NAME_GET_SUCCESS(HttpStatus.OK.value(), "필명 중복 여부가 조회되었습니다."), MOIM_TOPIC_LIST_GET_SUCCESS(HttpStatus.OK.value(), "글감 리스트 조회가 완료되었습니다."), TOPIC_PUT_SUCCESS(HttpStatus.OK.value(), "글감 수정이 완료되었습니다."), TOPIC_DETAIL_GET_SUCCESS(HttpStatus.OK.value(), "글감 상세 정보 조회가 완료되었습니다."), @@ -46,9 +46,13 @@ public enum SuccessMessage { MOIM_INFO_FOR_OWNER_GET_SUCCESS(HttpStatus.OK.value(), "관리자 페이지의 모임 정보가 조회되었습니다."), TOPIC_DELETE_SUCCESS(HttpStatus.OK.value(), "글감 삭제가 완료되었습니다."), MOIM_WRITERNAME_LIST_GET_SUCCESS(HttpStatus.OK.value(), "멤버 리스트 조회가 완료되었습니다."), + TEMPORARY_POST_DELETE_SUCCESS(HttpStatus.OK.value(), "임시 저장 글 삭제가 완료되었습니다."), + REPLY_DELETE_SUCCESS(HttpStatus.OK.value(), "대댓글 삭제가 완료되었습니다."), + MOIM_LIST_OF_USER_GET_SUCCESS(HttpStatus.OK.value(), "모임 리스트 조회가 완료되었습니다."), /* 201 CREATED */ + REPLY_CREATE_SUCCESS(HttpStatus.CREATED.value(), "대댓글 등록이 완료되었습니다."), WRITER_JOIN_SUCCESS(HttpStatus.CREATED.value(), "모임 가입에 완료되었습니다"), COMMENT_CREATE_SUCCESS(HttpStatus.CREATED.value(), "댓글 등록이 완료되었습니다."), CURIOUS_CREATE_SUCCESS(HttpStatus.CREATED.value(), "궁금해요 생성이 완료되었습니다."), diff --git a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java index fbe874b8..6c40b449 100644 --- a/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/mile/handler/GlobalExceptionHandler.java @@ -18,18 +18,28 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.HandlerMethodValidationException; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.NoHandlerFoundException; +import java.util.Objects; + @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { + private static final int INDEX_ZERO = 0; + @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity handleHttpMessageNotReadableException(final HttpMessageNotReadableException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorMessage.ENUM_VALUE_BAD_REQUEST)); } + @ExceptionHandler(HandlerMethodValidationException.class) + public ResponseEntity handleHandlerMethodValidationException(final HandlerMethodValidationException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(HttpStatus.BAD_REQUEST.value(), Objects.requireNonNull(e.getAllValidationResults().get(INDEX_ZERO).getResolvableErrors().get(INDEX_ZERO).getDefaultMessage()))); + } + @ExceptionHandler(MethodArgumentTypeMismatchException.class) public ResponseEntity handleMethodArgumentTypeMismatchException(final MethodArgumentTypeMismatchException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorMessage.REQUEST_URL_WRONG_ERROR)); @@ -58,8 +68,10 @@ public ResponseEntity handleHttpRequestMethodNotSupportedExceptio @ExceptionHandler(MethodArgumentNotValidException.class) protected ResponseEntity handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { FieldError fieldError = e.getBindingResult().getFieldError(); - if (fieldError == null) return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorMessage.VALIDATION_REQUEST_MISSING_EXCEPTION)); - else return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(HttpStatus.BAD_REQUEST.value(), fieldError.getDefaultMessage())); + if (fieldError == null) + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorMessage.VALIDATION_REQUEST_MISSING_EXCEPTION)); + else + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(HttpStatus.BAD_REQUEST.value(), fieldError.getDefaultMessage())); } @ExceptionHandler(ForbiddenException.class) diff --git a/module-common/src/main/java/com/mile/resolver/reply/ReplyIdPathVariable.java b/module-common/src/main/java/com/mile/resolver/reply/ReplyIdPathVariable.java new file mode 100644 index 00000000..ba13b58d --- /dev/null +++ b/module-common/src/main/java/com/mile/resolver/reply/ReplyIdPathVariable.java @@ -0,0 +1,11 @@ +package com.mile.resolver.reply; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface ReplyIdPathVariable { +} diff --git a/module-common/src/main/java/com/mile/resolver/reply/ReplyVariableResolver.java b/module-common/src/main/java/com/mile/resolver/reply/ReplyVariableResolver.java new file mode 100644 index 00000000..7451abbb --- /dev/null +++ b/module-common/src/main/java/com/mile/resolver/reply/ReplyVariableResolver.java @@ -0,0 +1,42 @@ +package com.mile.resolver.reply; + +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.BadRequestException; +import com.mile.utils.SecureUrlUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import org.springframework.web.servlet.HandlerMapping; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class ReplyVariableResolver implements HandlerMethodArgumentResolver { + private static final String REPLY_PATH_VARIABLE = "replyId"; + private final SecureUrlUtil secureUrlUtil; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(ReplyIdPathVariable.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + final HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + final Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + + final String replyId = pathVariables.get(REPLY_PATH_VARIABLE); + System.out.println(replyId); + try { + return secureUrlUtil.decodeUrl(replyId); + } catch (NumberFormatException e) { + throw new BadRequestException(ErrorMessage.INVALID_URL_EXCEPTION); + } + } +} \ No newline at end of file diff --git a/module-common/src/main/java/com/mile/utils/DateUtil.java b/module-common/src/main/java/com/mile/utils/DateUtil.java index 7e647766..19c4120d 100644 --- a/module-common/src/main/java/com/mile/utils/DateUtil.java +++ b/module-common/src/main/java/com/mile/utils/DateUtil.java @@ -13,7 +13,8 @@ public class DateUtil { private static final String DAY = "일"; private static final String STRING_DATE_WITH_TIME = "yy.MM.dd HH:mm"; private static final String STRING_DATE = "yy-MM-dd"; - private static final String YEAR_DATE_STRING = "yyyy-MM-dd"; + private static final String DOT_STRING_DATE = "yy.MM.dd"; + private static final String YEAR_DATE_STRING = "yyyy-MM-dd"; /* yyyy년 MM월 dd일 이 필요할 때 사용 @@ -39,6 +40,15 @@ public static String getStringWithTimeOfLocalDate( */ public static String getStringDateOfLocalDate( final LocalDateTime localDateTime + ) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DOT_STRING_DATE); + return localDateTime.format(formatter); + } + /* + yy.MM.dd 이 필요할 때 사용 + */ + public static String getStringDateOfDotFormat( + final LocalDateTime localDateTime ) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(STRING_DATE); return localDateTime.format(formatter); @@ -53,6 +63,7 @@ public static String getStringDateWithYear( DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YEAR_DATE_STRING); return localDateTime.format(formatter); } + private static String getKoreanString( final LocalDateTime localDateTime ) { diff --git a/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java b/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java index ed17e484..ec26bbd3 100644 --- a/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java +++ b/module-domain/src/main/java/com/mile/comment/repository/CommentRepository.java @@ -19,4 +19,7 @@ public interface CommentRepository extends JpaRepository { @Modifying @Query("delete from Comment c where c.post = :post") void deleteAllByPost(@Param("post")final Post post); + + int countByPost(final Post post); + int countByWriterNameId(final Long writerNameId); } \ No newline at end of file diff --git a/module-domain/src/main/java/com/mile/comment/service/CommentGetService.java b/module-domain/src/main/java/com/mile/comment/service/CommentGetService.java new file mode 100644 index 00000000..bab518cd --- /dev/null +++ b/module-domain/src/main/java/com/mile/comment/service/CommentGetService.java @@ -0,0 +1,18 @@ +package com.mile.comment.service; + +import com.mile.comment.repository.CommentRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CommentGetService { + + private final CommentRepository commentRepository; + + public int findCommentCountByWriterNameId( + final Long writerNameId + ) { + return commentRepository.countByWriterNameId(writerNameId); + } +} diff --git a/module-domain/src/main/java/com/mile/comment/service/CommentService.java b/module-domain/src/main/java/com/mile/comment/service/CommentService.java index 4f8750dd..15e140bb 100644 --- a/module-domain/src/main/java/com/mile/comment/service/CommentService.java +++ b/module-domain/src/main/java/com/mile/comment/service/CommentService.java @@ -3,6 +3,8 @@ import com.mile.comment.domain.Comment; import com.mile.comment.repository.CommentRepository; import com.mile.comment.service.dto.CommentResponse; +import com.mile.commentreply.service.CommentReplyService; +import com.mile.commentreply.service.dto.ReplyCreateRequest; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.NotFoundException; @@ -29,6 +31,7 @@ public class CommentService { private final PostGetService postGetService; private final SecureUrlUtil secureUrlUtil; private final WriterNameService writerNameService; + private final CommentReplyService commentReplyService; @Transactional public void deleteComment( @@ -37,6 +40,7 @@ public void deleteComment( ) { Comment comment = findById(commentId); authenticateUser(comment, userId); + commentReplyService.deleteRepliesByComment(comment); delete(comment); } @@ -74,6 +78,14 @@ public void createComment( comment.setIdUrl(secureUrlUtil.encodeUrl(comment.getId())); } + + public void deleteReply( + final Long userId, + final Long replyId + ) { + commentReplyService.deleteCommentReply(userId, replyId); + } + private Comment create( final Post post, final WriterName writerName, @@ -90,8 +102,30 @@ public List getCommentResponse( ) { postAuthenticateService.authenticateUserWithPostId(postId, userId); List commentList = findByPostId(postId); + Long writerNameId = writerNameService.getWriterNameIdByMoimIdAndUserId(moimId, userId); return commentList.stream() - .map(comment -> CommentResponse.of(comment, writerNameService.getWriterNameIdByMoimIdAndUserId(moimId, userId), isCommentWriterEqualWriterOfPost(comment, postId))).collect(Collectors.toList()); + .map(comment -> CommentResponse.of( + comment, + writerNameId, + isCommentWriterEqualWriterOfPost(comment, postId), + commentReplyService.findRepliesByComment(comment, writerNameId))).collect(Collectors.toList()); + } + + + public String createCommentReply( + final Long userId, + final Long commentId, + final ReplyCreateRequest replyCreateRequest + ) { + Comment comment = findById(commentId); + return commentReplyService.createCommentReply( + writerNameService.findWriterNameByMoimIdAndUserId(getMoimIdFromComment(comment), userId), + comment, + replyCreateRequest); + } + + private Long getMoimIdFromComment(final Comment comment) { + return comment.getPost().getTopic().getMoim().getId(); } private boolean isCommentWriterEqualWriterOfPost( @@ -115,15 +149,16 @@ public int findCommentCountByPost( } - private boolean isCommentListNull( - final List commentList + public void deleteAllByPost( + final Post post ) { - return commentList.isEmpty(); + commentRepository.findByPostId(post.getId()).forEach(commentReplyService::deleteRepliesByComment); + commentRepository.deleteAllByPost(post); } - public void deleteAllByPost( + public int countByPost( final Post post ) { - commentRepository.deleteAllByPost(post); + return commentRepository.countByPost(post); } } diff --git a/module-domain/src/main/java/com/mile/comment/service/dto/CommentResponse.java b/module-domain/src/main/java/com/mile/comment/service/dto/CommentResponse.java index e037d4f6..1b3efc7d 100644 --- a/module-domain/src/main/java/com/mile/comment/service/dto/CommentResponse.java +++ b/module-domain/src/main/java/com/mile/comment/service/dto/CommentResponse.java @@ -1,14 +1,19 @@ package com.mile.comment.service.dto; import com.mile.comment.domain.Comment; +import com.mile.commentreply.service.dto.ReplyResponse; import com.mile.writername.domain.WriterName; +import java.util.List; + public record CommentResponse( String commentId, String name, String moimName, String content, - boolean isMyComment + boolean isMyComment, + boolean isAnonymous, + List replies ) { private final static String ANONYMOUS = "작자미상"; private final static String AUTHOR = "글쓴이"; @@ -16,15 +21,18 @@ public record CommentResponse( public static CommentResponse of( final Comment comment, final Long writerNameId, - final boolean isWriterOfPost + final boolean isWriterOfPost, + final List replies ) { WriterName writerName = comment.getWriterName(); return new CommentResponse( comment.getIdUrl(), - getNameString(comment,writerName,isWriterOfPost), + getNameString(comment, writerName, isWriterOfPost), writerName.getMoim().getName(), comment.getContent(), - writerName.getId().equals(writerNameId) + writerName.getId().equals(writerNameId), + comment.isAnonymous(), + replies ); } diff --git a/module-domain/src/main/java/com/mile/commentreply/domain/CommentReply.java b/module-domain/src/main/java/com/mile/commentreply/domain/CommentReply.java new file mode 100644 index 00000000..eea13f61 --- /dev/null +++ b/module-domain/src/main/java/com/mile/commentreply/domain/CommentReply.java @@ -0,0 +1,54 @@ +package com.mile.commentreply.domain; + +import com.mile.comment.domain.Comment; +import com.mile.writername.domain.WriterName; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@NoArgsConstructor +@Getter +public class CommentReply { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne + private WriterName writerName; + @ManyToOne + private Comment comment; + @Setter + private String idUrl; + private boolean isAnonymous; + private String content; + + @Builder + private CommentReply(final WriterName writerName, + final Comment comment, + final boolean isAnonymous, + final String content) { + this.writerName = writerName; + this.comment = comment; + this.isAnonymous = isAnonymous; + this.content = content; + } + + public static CommentReply create(final WriterName writerName, + final Comment comment, + final String content, + final boolean isAnonymous) { + return CommentReply.builder() + .writerName(writerName) + .comment(comment) + .isAnonymous(isAnonymous) + .content(content) + .build(); + } +} diff --git a/module-domain/src/main/java/com/mile/commentreply/repository/CommentReplyRepository.java b/module-domain/src/main/java/com/mile/commentreply/repository/CommentReplyRepository.java new file mode 100644 index 00000000..1c1be32b --- /dev/null +++ b/module-domain/src/main/java/com/mile/commentreply/repository/CommentReplyRepository.java @@ -0,0 +1,12 @@ +package com.mile.commentreply.repository; + +import com.mile.comment.domain.Comment; +import com.mile.commentreply.domain.CommentReply; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface CommentReplyRepository extends JpaRepository { + + List findByComment(final Comment comment); +} diff --git a/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyService.java b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyService.java new file mode 100644 index 00000000..74afe1d9 --- /dev/null +++ b/module-domain/src/main/java/com/mile/commentreply/service/CommentReplyService.java @@ -0,0 +1,79 @@ +package com.mile.commentreply.service; + +import com.mile.comment.domain.Comment; +import com.mile.commentreply.domain.CommentReply; +import com.mile.commentreply.repository.CommentReplyRepository; +import com.mile.commentreply.service.dto.ReplyCreateRequest; +import com.mile.commentreply.service.dto.ReplyResponse; +import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.NotFoundException; +import com.mile.exception.model.UnauthorizedException; +import com.mile.utils.SecureUrlUtil; +import com.mile.writername.domain.WriterName; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class CommentReplyService { + + private final CommentReplyRepository commentReplyRepository; + private final SecureUrlUtil secureUrlUtil; + + @Transactional + public String createCommentReply( + final WriterName writerName, + final Comment comment, + final ReplyCreateRequest replyCreateRequest + ) { + CommentReply commentReply = commentReplyRepository.save(CommentReply.create(writerName, comment, replyCreateRequest.content(), replyCreateRequest.isAnonymous())); + commentReply.setIdUrl(secureUrlUtil.encodeUrl(commentReply.getId())); + return commentReply.getId().toString(); + } + + public void deleteCommentReply( + final Long userId, + final Long replyId + ) { + CommentReply commentReply = findById(replyId); + authenticateReplyWithUserId(userId, commentReply); + commentReplyRepository.delete(commentReply); + } + + private void authenticateReplyWithUserId( + final Long userId, + final CommentReply commentReply + ) { + if(!commentReply.getWriterName().getWriter().getId().equals(userId)) { + throw new UnauthorizedException(ErrorMessage.REPLY_USER_FORBIDDEN); + } + } + + public void deleteRepliesByComment( + final Comment comment + ) { + commentReplyRepository.deleteAll(commentReplyRepository.findByComment(comment)); + } + public List findRepliesByComment( + final Comment comment, + final Long writerNameId + ) { + return commentReplyRepository.findByComment(comment).stream().map(c -> ReplyResponse.of(c, writerNameId, isWriterOfPost(c))).collect(Collectors.toList()); + } + + private boolean isWriterOfPost(final CommentReply commentReply) { + return commentReply.getComment().getPost().getWriterName().getId().equals(commentReply.getWriterName().getId()); + } + + private CommentReply findById( + final Long replyId + ) { + return commentReplyRepository.findById(replyId).orElseThrow( + () -> new NotFoundException(ErrorMessage.REPLY_NOT_FOUND) + ); + } +} diff --git a/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyCreateRequest.java b/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyCreateRequest.java new file mode 100644 index 00000000..7595193a --- /dev/null +++ b/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyCreateRequest.java @@ -0,0 +1,7 @@ +package com.mile.commentreply.service.dto; + +public record ReplyCreateRequest( + String content, + boolean isAnonymous +) { +} diff --git a/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyResponse.java b/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyResponse.java new file mode 100644 index 00000000..9ad0e6df --- /dev/null +++ b/module-domain/src/main/java/com/mile/commentreply/service/dto/ReplyResponse.java @@ -0,0 +1,50 @@ +package com.mile.commentreply.service.dto; + +import com.mile.comment.domain.Comment; +import com.mile.comment.service.dto.CommentResponse; +import com.mile.commentreply.domain.CommentReply; +import com.mile.writername.domain.WriterName; + +import java.util.List; + +public record ReplyResponse( + String replyId, + String name, + String moimName, + String content, + boolean isMyReply, + boolean isAnonymous +) { + private final static String ANONYMOUS = "작자미상"; + private final static String AUTHOR = "글쓴이"; + + public static ReplyResponse of( + final CommentReply commentReply, + final Long writerNameId, + final boolean isWriterOfPost + ) { + WriterName writerName = commentReply.getWriterName(); + return new ReplyResponse( + commentReply.getIdUrl(), + getNameString(commentReply, writerName, isWriterOfPost), + writerName.getMoim().getName(), + commentReply.getContent(), + writerName.getId().equals(writerNameId), + commentReply.isAnonymous() + ); + } + + private static String getNameString( + final CommentReply commentReply, + final WriterName writerName, + final boolean isWriterOfPost + ) { + if (isWriterOfPost) { + return AUTHOR; + } else if (commentReply.isAnonymous()) { + return ANONYMOUS + writerName.getId().toString(); + } else { + return writerName.getName(); + } + } +} diff --git a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java index 1d4cc793..f80bb216 100644 --- a/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java +++ b/module-domain/src/main/java/com/mile/config/BaseTimeEntity.java @@ -14,4 +14,10 @@ public abstract class BaseTimeEntity { @CreatedDate private LocalDateTime createdAt; + + public void updateCratedAt( + final LocalDateTime now + ) { + this.createdAt = now; + } } diff --git a/module-domain/src/main/java/com/mile/moim/service/MoimService.java b/module-domain/src/main/java/com/mile/moim/service/MoimService.java index 935b8ba1..c03be1f7 100644 --- a/module-domain/src/main/java/com/mile/moim/service/MoimService.java +++ b/module-domain/src/main/java/com/mile/moim/service/MoimService.java @@ -1,6 +1,7 @@ package com.mile.moim.service; import com.mile.exception.message.ErrorMessage; +import com.mile.exception.model.BadRequestException; import com.mile.exception.model.ForbiddenException; import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; @@ -15,9 +16,11 @@ import com.mile.moim.service.dto.MoimInfoModifyRequest; import com.mile.moim.service.dto.MoimInfoOwnerResponse; import com.mile.moim.service.dto.MoimInfoResponse; -import com.mile.moim.service.dto.MoimTopicInfoListResponse; -import com.mile.moim.service.dto.MoimNameConflictCheckResponse; import com.mile.moim.service.dto.MoimInvitationInfoResponse; +import com.mile.moim.service.dto.MoimListOfUserResponse; +import com.mile.moim.service.dto.MoimNameConflictCheckResponse; +import com.mile.moim.service.dto.MoimOfUserResponse; +import com.mile.moim.service.dto.MoimTopicInfoListResponse; import com.mile.moim.service.dto.MoimTopicResponse; import com.mile.moim.service.dto.MoimWriterNameListGetResponse; import com.mile.moim.service.dto.PopularWriterListResponse; @@ -28,7 +31,6 @@ import com.mile.moim.service.dto.WriterNameConflictCheckResponse; import com.mile.post.domain.Post; import com.mile.post.service.PostAuthenticateService; -import com.mile.post.service.PostCreateService; import com.mile.post.service.PostDeleteService; import com.mile.post.service.PostGetService; import com.mile.topic.service.TopicService; @@ -42,13 +44,17 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Service +@Slf4j @RequiredArgsConstructor public class MoimService { @@ -58,9 +64,10 @@ public class MoimService { private final MoimRepository moimRepository; private final PostDeleteService postCuriousService; private final PostAuthenticateService postAuthenticateService; - private final PostCreateService postCreateService; private final PostGetService postGetService; private final SecureUrlUtil secureUrlUtil; + private static final int WRITER_NAME_MAX_VALUE = 8; + private static final int MOIM_NAME_MAX_VALUE = 10; public ContentListResponse getContentsFromMoim( final Long moimId, @@ -71,6 +78,9 @@ public ContentListResponse getContentsFromMoim( } public WriterNameConflictCheckResponse checkConflictOfWriterName(Long moimId, String writerName) { + if (writerName.length() > WRITER_NAME_MAX_VALUE) { + throw new BadRequestException(ErrorMessage.WRITER_NAME_LENGTH_WRONG); + } return WriterNameConflictCheckResponse.of(writerNameService.existWriterNamesByMoimAndName(findById(moimId), writerName)); } @@ -83,11 +93,22 @@ public Long joinMoim( } public MoimInvitationInfoResponse getMoimInvitationInfo( + final Long userId, final Long moimId ) { + isUserAlreadyInMoim(moimId, userId); return MoimInvitationInfoResponse.of(findById(moimId), writerNameService.findNumbersOfWritersByMoimId(moimId)); } + private void isUserAlreadyInMoim( + final Long moimId, + final Long userId + ) { + if (writerNameService.findMemberByMoimIdANdWriterId(moimId, userId).isPresent()) { + throw new BadRequestException(ErrorMessage.USER_MOIM_ALREADY_JOIN); + } + } + public void authenticateOwnerOfMoim( final Moim moim, final Long userId @@ -108,7 +129,7 @@ public MoimAuthenticateResponse getAuthenticateUserOfMoim( final Long moimId, final Long userId ) { - return MoimAuthenticateResponse.of(writerNameService.isUserInMoim(moimId, userId)); + return MoimAuthenticateResponse.of(writerNameService.isUserInMoim(moimId, userId), isMoimOwnerEqualsUser(findById(moimId), userService.findById(userId))); } public Moim findById( @@ -183,14 +204,14 @@ public TemporaryPostExistResponse getTemporaryPost( final Long moimId, final Long userId ) { - String postId = postCreateService.getTemporaryPostExist(findById(moimId), writerNameService.findByWriterId(userId)); + String postId = postGetService.getTemporaryPostExist(findById(moimId), writerNameService.findByWriterId(userId)); return TemporaryPostExistResponse.of(!secureUrlUtil.decodeUrl(postId).equals(0L), postId); } public MoimTopicInfoListResponse getMoimTopicList( - final Long moimId, - final Long userId, - final int page + final Long moimId, + final Long userId, + final int page ) { getAuthenticateOwnerOfMoim(moimId, userId); return topicService.getTopicListFromMoim(moimId, page); @@ -217,9 +238,13 @@ public void modifyMoimInforation( moim.modifyMoimInfo(modifyRequest); authenticateOwnerOfMoim(moim, userId); } + public MoimNameConflictCheckResponse validateMoimName( final String moimName ) { + if (moimName.length() > MOIM_NAME_MAX_VALUE) { + throw new BadRequestException(ErrorMessage.MOIM_NAME_LENGTH_WRONG); + } return MoimNameConflictCheckResponse.of(!moimRepository.existsByName(moimName)); } @@ -277,6 +302,7 @@ private void setFirstTopic( createRequest.topicDescription()); createTopic(moim.getId(), userId, topicRequest); } + public MoimInfoOwnerResponse getMoimInfoForOwner( final Long moimId, final Long userId @@ -295,4 +321,13 @@ public MoimWriterNameListGetResponse getWriterNameListOfMoim( authenticateOwnerOfMoim(moim, userId); return writerNameService.getWriterNameInfoList(moimId, page); } + + public MoimListOfUserResponse getMoimOfUserList( + final Long userId + ) { + return MoimListOfUserResponse.of(writerNameService.getMoimListOfUser(userId) + .stream() + .map(moim -> MoimOfUserResponse.of(moim)) + .collect(Collectors.toList())); + } } diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimAuthenticateResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimAuthenticateResponse.java index d6c3f595..1b6fd3a3 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/MoimAuthenticateResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimAuthenticateResponse.java @@ -1,11 +1,13 @@ package com.mile.moim.service.dto; public record MoimAuthenticateResponse( - boolean isMember + boolean isMember, + boolean isOwner ) { public static MoimAuthenticateResponse of( - final boolean isMember + final boolean isMember, + final boolean isOwner ) { - return new MoimAuthenticateResponse(isMember); + return new MoimAuthenticateResponse(isMember, isOwner); } } diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimInvitationInfoResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimInvitationInfoResponse.java index a99e7b25..2431ac3f 100644 --- a/module-domain/src/main/java/com/mile/moim/service/dto/MoimInvitationInfoResponse.java +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimInvitationInfoResponse.java @@ -1,11 +1,13 @@ package com.mile.moim.service.dto; import com.mile.moim.domain.Moim; +import com.mile.utils.DateUtil; public record MoimInvitationInfoResponse( String moimTitle, String imageUrl, String leader, + String foundedDate, int memberCount, String description ) { @@ -13,6 +15,7 @@ public static MoimInvitationInfoResponse of( final Moim moim, final int memberCount ) { - return new MoimInvitationInfoResponse(moim.getName(), moim.getImageUrl(), moim.getOwner().getName(), memberCount, moim.getInformation()); + return new MoimInvitationInfoResponse(moim.getName(), moim.getImageUrl(), moim.getOwner().getName(), + DateUtil.getStringDateOfDotFormat(moim.getCreatedAt()), memberCount, moim.getInformation()); } } diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimListOfUserResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimListOfUserResponse.java new file mode 100644 index 00000000..2c7f5b5b --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimListOfUserResponse.java @@ -0,0 +1,15 @@ +package com.mile.moim.service.dto; + +import java.util.List; + +public record MoimListOfUserResponse( + List moims +) { + public static MoimListOfUserResponse of ( + final List moims + ) { + return new MoimListOfUserResponse( + moims + ); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/service/dto/MoimOfUserResponse.java b/module-domain/src/main/java/com/mile/moim/service/dto/MoimOfUserResponse.java new file mode 100644 index 00000000..b70dd6bb --- /dev/null +++ b/module-domain/src/main/java/com/mile/moim/service/dto/MoimOfUserResponse.java @@ -0,0 +1,17 @@ +package com.mile.moim.service.dto; + +import com.mile.moim.domain.Moim; + +public record MoimOfUserResponse( + String moimName, + String moimId +) { + public static MoimOfUserResponse of( + final Moim moim + ) { + return new MoimOfUserResponse( + moim.getName(), + moim.getIdUrl() + ); + } +} diff --git a/module-domain/src/main/java/com/mile/post/repository/PostRepository.java b/module-domain/src/main/java/com/mile/post/repository/PostRepository.java index 509a93c2..4bcedf10 100644 --- a/module-domain/src/main/java/com/mile/post/repository/PostRepository.java +++ b/module-domain/src/main/java/com/mile/post/repository/PostRepository.java @@ -8,5 +8,5 @@ public interface PostRepository extends JpaRepository, PostRepositoryCustom { boolean existsPostByIdAndWriterNameId(final Long postId, final Long userId); List findByTopic(final Topic topic); - + int countByWriterNameId(final Long writerNameId); } diff --git a/module-domain/src/main/java/com/mile/post/service/PostCreateService.java b/module-domain/src/main/java/com/mile/post/service/PostCreateService.java index 7440d0a9..9b5abcd5 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostCreateService.java +++ b/module-domain/src/main/java/com/mile/post/service/PostCreateService.java @@ -1,35 +1,44 @@ package com.mile.post.service; -import com.mile.moim.domain.Moim; import com.mile.post.domain.Post; import com.mile.post.repository.PostRepository; +import com.mile.post.service.dto.TemporaryPostCreateRequest; +import com.mile.topic.service.TopicService; +import com.mile.utils.SecureUrlUtil; import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.Base64; -import java.util.Comparator; -import java.util.List; @Service @RequiredArgsConstructor public class PostCreateService { private final PostRepository postRepository; + private final TopicService topicService; + private final SecureUrlUtil secureUrlUtil; + private static final boolean TEMPORARY_TRUE = true; + private static final String DEFAULT_IMG_URL = "https://mile-s3.s3.ap-northeast-2.amazonaws.com/post/KakaoTalk_Photo_2024-01-14-15-52-49.png"; - public String getTemporaryPostExist( - final Moim moim, - final WriterName writerName - ) { - List postList = postRepository.findByMoimAndWriterNameWhereIsTemporary(moim, writerName); - if(isPostListEmpty(postList)) { - return Base64.getUrlEncoder().encodeToString(String.valueOf(0L).getBytes()); - } - return postList.stream().sorted(Comparator.comparing(Post::getCreatedAt).reversed()).toList().get(0).getIdUrl(); + + private boolean checkContainPhoto(final String imageUrl) { + return !imageUrl.equals(DEFAULT_IMG_URL); } - private boolean isPostListEmpty( - final List postList + public void createTemporaryPost( + final WriterName writerName, + final TemporaryPostCreateRequest temporaryPostCreateRequest ) { - return postList.isEmpty(); + Post post = postRepository.save(Post.create( + topicService.findById(secureUrlUtil.decodeUrl(temporaryPostCreateRequest.topicId())), // Topic + writerName, // WriterName + temporaryPostCreateRequest.title(), + temporaryPostCreateRequest.content(), + temporaryPostCreateRequest.imageUrl(), + checkContainPhoto(temporaryPostCreateRequest.imageUrl()), + temporaryPostCreateRequest.anonymous(), + TEMPORARY_TRUE + )); + post.setIdUrl(Base64.getUrlEncoder().encodeToString(post.getId().toString().getBytes())); } } diff --git a/module-domain/src/main/java/com/mile/post/service/PostDeleteService.java b/module-domain/src/main/java/com/mile/post/service/PostDeleteService.java index 77d470f1..20c05311 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostDeleteService.java +++ b/module-domain/src/main/java/com/mile/post/service/PostDeleteService.java @@ -11,6 +11,7 @@ import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; @@ -23,6 +24,7 @@ public class PostDeleteService { private final CuriousService curiousService; private final CommentService commentService; private final S3Service s3Service; + private List getPostHaveCuriousCount( final List postList ) { @@ -30,6 +32,20 @@ private List getPostHaveCuriousCount( return postList; } + public void deleteTemporaryPosts( + final Moim moim, + final WriterName writerName + ) { + postRepository.findByMoimAndWriterNameWhereIsTemporary(moim, writerName).forEach(this::delete); + } + @Transactional + public void deleteTemporaryPost( + final Post post + ) { + postRepository.delete(post); + + } + public void delete( final Post post ) { @@ -56,6 +72,7 @@ private void deleteS3File( ) { s3Service.deleteImage(key); } + public MoimCuriousPostListResponse getMostCuriousPostByMoim(final Moim moim) { List postList = getPostHaveCuriousCount(postRepository.findTop2ByMoimOrderByCuriousCountDesc(moim)); return MoimCuriousPostListResponse.of(postList diff --git a/module-domain/src/main/java/com/mile/post/service/PostGetService.java b/module-domain/src/main/java/com/mile/post/service/PostGetService.java index 9bfffea4..037f544b 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostGetService.java +++ b/module-domain/src/main/java/com/mile/post/service/PostGetService.java @@ -7,6 +7,8 @@ import com.mile.post.domain.Post; import com.mile.post.repository.PostRepository; import com.mile.topic.domain.Topic; +import com.mile.utils.SecureUrlUtil; +import com.mile.writername.domain.WriterName; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -19,7 +21,7 @@ public class PostGetService { private final PostRepository postRepository; - + private final SecureUrlUtil secureUrlUtil; public Post findById( final Long postId @@ -27,6 +29,26 @@ public Post findById( return postRepository.findById(postId).orElseThrow( () -> new NotFoundException(ErrorMessage.POST_NOT_FOUND) ); + + } + + + public String getTemporaryPostExist( + final Moim moim, + final WriterName writerName + ) { + List postList = postRepository.findByMoimAndWriterNameWhereIsTemporary(moim, writerName); + if (isPostListEmpty(postList)) { + return secureUrlUtil.encodeUrl(0L); + } + postList.sort(Comparator.comparing(Post::getCreatedAt).reversed()); + return postList.get(0).getIdUrl(); + } + + private boolean isPostListEmpty( + final List postList + ) { + return postList.isEmpty(); } public List findByTopic( @@ -48,4 +70,11 @@ public List findAllByTopic( ) { return postRepository.findByTopic(topic); } + + public int findPostCountByWriterNameId( + final Long writerNameId + ) { + return postRepository.countByWriterNameId(writerNameId); + } + } diff --git a/module-domain/src/main/java/com/mile/post/service/PostService.java b/module-domain/src/main/java/com/mile/post/service/PostService.java index cf5a9cfd..5310fd76 100644 --- a/module-domain/src/main/java/com/mile/post/service/PostService.java +++ b/module-domain/src/main/java/com/mile/post/service/PostService.java @@ -30,6 +30,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.Base64; import java.util.List; @@ -49,9 +50,9 @@ public class PostService { private final TopicService topicService; private final PostDeleteService postDeleteService; private final SecureUrlUtil secureUrlUtil; + private final PostCreateService postCreateService; private static final boolean TEMPORARY_FALSE = false; - private static final boolean TEMPORARY_TRUE = true; private static final boolean CURIOUS_FALSE = false; private static final boolean CURIOUS_TRUE = true; private static final String DEFAULT_IMG_URL = "https://mile-s3.s3.ap-northeast-2.amazonaws.com/post/KakaoTalk_Photo_2024-01-14-15-52-49.png"; @@ -179,7 +180,7 @@ public PostGetResponse getPost( Post post = postGetService.findById(postId); post.increaseHits(); Moim moim = post.getTopic().getMoim(); - return PostGetResponse.of(post, moim); + return PostGetResponse.of(post, moim, commentService.countByPost(post)); } @@ -189,6 +190,13 @@ private Long decodeUrlToLong( return Long.parseLong(new String(Base64.getUrlDecoder().decode(url))); } + public void deleteTemporaryPost(final Long userId, final Long postId) { + postAuthenticateService.authenticateWriter(postId, userId); + Post post = postGetService.findById(postId); + postDeleteService.deleteTemporaryPost(post); + } + + @Transactional public WriterNameResponse createPost( final Long userId, @@ -221,17 +229,9 @@ public void createTemporaryPost( final TemporaryPostCreateRequest temporaryPostCreateRequest ) { postAuthenticateService.authenticateWriterOfMoim(userId, decodeUrlToLong(temporaryPostCreateRequest.moimId())); - Post post = postRepository.saveAndFlush(Post.create( - topicService.findById(decodeUrlToLong(temporaryPostCreateRequest.topicId())), // Topic - writerNameService.findByMoimAndUser(decodeUrlToLong(temporaryPostCreateRequest.moimId()), userId), // WriterName - temporaryPostCreateRequest.title(), - temporaryPostCreateRequest.content(), - temporaryPostCreateRequest.imageUrl(), - checkContainPhoto(temporaryPostCreateRequest.imageUrl()), - temporaryPostCreateRequest.anonymous(), - TEMPORARY_TRUE - )); - post.setIdUrl(Base64.getUrlEncoder().encodeToString(post.getId().toString().getBytes())); + WriterName writerName = writerNameService.findByMoimAndUser(secureUrlUtil.decodeUrl(temporaryPostCreateRequest.moimId()), userId); + postDeleteService.deleteTemporaryPosts(topicService.findById(secureUrlUtil.decodeUrl(temporaryPostCreateRequest.topicId())).getMoim(), writerName); + postCreateService.createTemporaryPost(writerName, temporaryPostCreateRequest); } private boolean checkContainPhoto(final String imageUrl) { @@ -245,6 +245,7 @@ public WriterNameResponse putTemporaryToFixedPost(final Long userId, final PostP isPostTemporary(post); updateTemporaryPost(postId, request); post.setTemporary(TEMPORARY_FALSE); + post.updateCratedAt(LocalDateTime.now()); return WriterNameResponse.of(post.getIdUrl(), writerName.getName()); } diff --git a/module-domain/src/main/java/com/mile/post/service/dto/PostGetResponse.java b/module-domain/src/main/java/com/mile/post/service/dto/PostGetResponse.java index 57a61d33..cc632ac2 100644 --- a/module-domain/src/main/java/com/mile/post/service/dto/PostGetResponse.java +++ b/module-domain/src/main/java/com/mile/post/service/dto/PostGetResponse.java @@ -12,12 +12,15 @@ public record PostGetResponse( String imageUrl, String writerName, String moimName, - String writerInfo + String writerInfo, + int hitsCount, + int curiousCount, + int commentCount ) { private final static String ANONYMOUS = "작자미상"; private final static String ANONYMOUS_INFO = "익명으로 작성한 사용자입니다."; - public static PostGetResponse of(Post post, Moim moim) { + public static PostGetResponse of(Post post, Moim moim, int commentCount) { String writerName = post.getWriterName().getName(); String information = post.getWriterName().getInformation(); @@ -33,7 +36,10 @@ public static PostGetResponse of(Post post, Moim moim) { post.getImageUrl(), writerName, moim.getName(), - information + information, + post.getHitsCount(), + post.getCuriousCount(), + commentCount ); } } diff --git a/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java b/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java index 9385ae18..2fd62adc 100644 --- a/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java +++ b/module-domain/src/main/java/com/mile/writername/repository/WriterNameRepository.java @@ -25,4 +25,6 @@ public interface WriterNameRepository extends JpaRepository { Page findByMoimIdOrderByIdDesc(Long moimId, Pageable pageable); Optional findById(final Long id); + + List findAllByWriterId(final Long writerId); } \ No newline at end of file diff --git a/module-domain/src/main/java/com/mile/writername/service/WriterNameService.java b/module-domain/src/main/java/com/mile/writername/service/WriterNameService.java index 1a0ee056..8cbb33af 100644 --- a/module-domain/src/main/java/com/mile/writername/service/WriterNameService.java +++ b/module-domain/src/main/java/com/mile/writername/service/WriterNameService.java @@ -1,16 +1,18 @@ package com.mile.writername.service; +import com.mile.comment.service.CommentGetService; +import com.mile.comment.service.CommentService; import com.mile.exception.message.ErrorMessage; import com.mile.exception.model.NotFoundException; import com.mile.moim.domain.Moim; import com.mile.moim.service.dto.MoimWriterNameListGetResponse; import com.mile.moim.service.dto.WriterMemberJoinRequest; import com.mile.post.domain.Post; +import com.mile.post.service.PostGetService; import com.mile.user.domain.User; import com.mile.writername.domain.WriterName; import com.mile.writername.repository.WriterNameRepository; import com.mile.writername.service.dto.WriterNameInfoResponse; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -19,12 +21,16 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class WriterNameService { private final WriterNameRepository writerNameRepository; + private final PostGetService postGetService; + private final CommentGetService commentGetService; private static final int MIN_TOTAL_CURIOUS_COUNT = 0; private static final int WRITERNAME_PER_PAGE_SIZE = 5; @@ -58,6 +64,14 @@ public WriterName findByMoimAndUser( ); } + public Optional findMemberByMoimIdANdWriterId( + final Long moimId, + final Long writerId + ) { + return writerNameRepository.findByMoimIdAndWriterId(moimId, writerId); + } + + public WriterName getWriterNameByPostAndUserId( final Post post, final Long userId @@ -105,6 +119,13 @@ public void increaseTotalCuriousCountByWriterId( writerName.increaseTotalCuriousCount(); } + + public WriterName findWriterNameByMoimIdAndUserId( + final Long moimId, + final Long userId + ) { + return getById(getWriterNameIdByMoimIdAndUserId(moimId, userId)); + } public List findTop2ByCuriousCount(final Long moimid) { return writerNameRepository.findTop2ByMoimIdAndTotalCuriousCountGreaterThanOrderByTotalCuriousCountDesc(moimid, MIN_TOTAL_CURIOUS_COUNT); } @@ -133,11 +154,13 @@ public MoimWriterNameListGetResponse getWriterNameInfoList( final Long moimId, final int page ) { - PageRequest pageRequest = PageRequest.of(page-1, WRITERNAME_PER_PAGE_SIZE, Sort.by(Sort.Direction.DESC, "id")); + PageRequest pageRequest = PageRequest.of(page - 1, WRITERNAME_PER_PAGE_SIZE, Sort.by(Sort.Direction.DESC, "id")); Page writerNamePage = writerNameRepository.findByMoimIdOrderByIdDesc(moimId, pageRequest); List infoResponses = writerNamePage.getContent() .stream() - .map(writerName -> WriterNameInfoResponse.of(writerName.getId(), writerName.getName(), writerName.getInformation())) + .map(writerName -> WriterNameInfoResponse.of(writerName.getId(), writerName.getName(), + postGetService.findPostCountByWriterNameId(writerName.getId()), + commentGetService.findCommentCountByWriterNameId(writerName.getId()))) .collect(Collectors.toList()); return MoimWriterNameListGetResponse.of( @@ -146,4 +169,13 @@ public MoimWriterNameListGetResponse getWriterNameInfoList( infoResponses ); } + + public List getMoimListOfUser( + final Long userId + ) { + return writerNameRepository.findAllByWriterId(userId) + .stream() + .map(writerName -> writerName.getMoim()) + .collect(Collectors.toList()); + } } diff --git a/module-domain/src/main/java/com/mile/writername/service/dto/WriterNameInfoResponse.java b/module-domain/src/main/java/com/mile/writername/service/dto/WriterNameInfoResponse.java index 18836395..f28189e5 100644 --- a/module-domain/src/main/java/com/mile/writername/service/dto/WriterNameInfoResponse.java +++ b/module-domain/src/main/java/com/mile/writername/service/dto/WriterNameInfoResponse.java @@ -3,13 +3,15 @@ public record WriterNameInfoResponse( Long writerNameId, String writerName, - String information + int postCount, + int commentCount ) { public static WriterNameInfoResponse of( final Long writerNameId, final String writerName, - final String information + final int postCount, + final int commentCount ) { - return new WriterNameInfoResponse(writerNameId, writerName, information); + return new WriterNameInfoResponse(writerNameId, writerName, postCount, commentCount); } }