-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #150 from sharemindteam/feature/145-counselorSide-…
…post feat: 일대다 상담 미답변 질문 조회 및 답변 기능 구현
- Loading branch information
Showing
17 changed files
with
414 additions
and
11 deletions.
There are no files selected for viewing
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/sharemind/comment/application/CommentService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.sharemind.comment.application; | ||
|
||
import com.example.sharemind.comment.dto.request.CommentCreateRequest; | ||
import com.example.sharemind.comment.dto.response.CommentGetResponse; | ||
|
||
import java.util.List; | ||
|
||
public interface CommentService { | ||
List<CommentGetResponse> getCommentsByPost(Long postId, Long customerId); | ||
|
||
void createComment(CommentCreateRequest commentCreateRequest, Long customerId); | ||
} |
56 changes: 56 additions & 0 deletions
56
src/main/java/com/example/sharemind/comment/application/CommentServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.example.sharemind.comment.application; | ||
|
||
import com.example.sharemind.comment.domain.Comment; | ||
import com.example.sharemind.comment.dto.request.CommentCreateRequest; | ||
import com.example.sharemind.comment.dto.response.CommentGetResponse; | ||
import com.example.sharemind.comment.exception.CommentErrorCode; | ||
import com.example.sharemind.comment.exception.CommentException; | ||
import com.example.sharemind.comment.repository.CommentRepository; | ||
import com.example.sharemind.counselor.application.CounselorService; | ||
import com.example.sharemind.counselor.domain.Counselor; | ||
import com.example.sharemind.post.application.PostService; | ||
import com.example.sharemind.post.content.PostStatus; | ||
import com.example.sharemind.post.domain.Post; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class CommentServiceImpl implements CommentService { | ||
|
||
private final PostService postService; | ||
private final CounselorService counselorService; | ||
private final CommentRepository commentRepository; | ||
|
||
private static final Integer MAX_COMMENTS = 5; | ||
|
||
@Override | ||
public List<CommentGetResponse> getCommentsByPost(Long postId, Long customerId) { | ||
Post post = postService.checkAndGetCounselorPost(postId, customerId); | ||
|
||
List<Comment> comments = commentRepository.findByPostAndIsActivatedIsTrue(post); | ||
return comments.stream() | ||
.map(CommentGetResponse::of) | ||
.toList(); | ||
} | ||
|
||
@Transactional | ||
@Override | ||
public void createComment(CommentCreateRequest commentCreateRequest, Long customerId) { | ||
Post post = postService.checkAndGetCounselorPost(commentCreateRequest.getPostId(), customerId); | ||
Counselor counselor = counselorService.getCounselorByCustomerId(customerId); | ||
|
||
if (commentRepository.findByPostAndCounselorAndIsActivatedIsTrue(post, counselor) != null) | ||
throw new CommentException(CommentErrorCode.COMMENT_ALREADY_REGISTERED, counselor.getNickname()); | ||
|
||
commentRepository.save(commentCreateRequest.toEntity(post, counselor)); | ||
|
||
List<Comment> comments = commentRepository.findByPostAndIsActivatedIsTrue(post); | ||
if (comments.size() == MAX_COMMENTS) | ||
post.updatePostStatus(PostStatus.COMPLETED); | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/java/com/example/sharemind/comment/domain/Comment.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.example.sharemind.comment.domain; | ||
|
||
import com.example.sharemind.counselor.domain.Counselor; | ||
import com.example.sharemind.global.common.BaseEntity; | ||
import com.example.sharemind.post.domain.Post; | ||
import jakarta.persistence.*; | ||
import jakarta.validation.constraints.Size; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
@Entity | ||
public class Comment extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "comment_id") | ||
private Long commentId; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | ||
@JoinColumn(name = "post_id") | ||
private Post post; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY, optional = false) | ||
@JoinColumn(name = "counselor_id") | ||
private Counselor counselor; | ||
|
||
@Size(max = 500, message = "상담 답변은 최대 500자입니다.") | ||
private String content; | ||
|
||
@Column(name = "is_chosen", nullable = false) | ||
private Boolean isChosen; | ||
|
||
@Column(name = "total_like", nullable = false) | ||
private Long totalLike; | ||
|
||
@Builder | ||
public Comment(Post post, Counselor counselor, String content) { | ||
this.post = post; | ||
this.counselor = counselor; | ||
this.content = content; | ||
isChosen = false; | ||
totalLike = 0L; | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/example/sharemind/comment/dto/request/CommentCreateRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.example.sharemind.comment.dto.request; | ||
|
||
import com.example.sharemind.comment.domain.Comment; | ||
import com.example.sharemind.counselor.domain.Counselor; | ||
import com.example.sharemind.post.domain.Post; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class CommentCreateRequest { | ||
|
||
@Schema(description = "상담 id") | ||
@NotNull | ||
private Long postId; | ||
|
||
@Schema(description = "content") | ||
private String content; | ||
|
||
public Comment toEntity(Post post, Counselor counselor) { | ||
return Comment.builder() | ||
.post(post) | ||
.counselor(counselor) | ||
.content(content) | ||
.build(); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/main/java/com/example/sharemind/comment/dto/response/CommentGetResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.example.sharemind.comment.dto.response; | ||
|
||
import com.example.sharemind.comment.domain.Comment; | ||
import com.example.sharemind.global.utils.TimeUtil; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class CommentGetResponse { | ||
|
||
@Schema(description = "상담사 닉네임") | ||
private final String nickName; | ||
|
||
@Schema(description = "답변 내용") | ||
private final String content; | ||
|
||
@Schema(description = "좋아요 수") | ||
private final Long totalLike; | ||
|
||
@Schema(description = "마지막 업데이트 일시", example = "오전 11:10") | ||
private final String updatedAt; | ||
|
||
@Schema(description = "채택 여부", example="true") | ||
private final Boolean isChosen; | ||
|
||
@Builder | ||
public CommentGetResponse(String nickName, String content, Long totalLike, String updatedAt, Boolean isChosen) { | ||
this.nickName = nickName; | ||
this.content = content; | ||
this.totalLike = totalLike; | ||
this.updatedAt = updatedAt; | ||
this.isChosen = isChosen; | ||
} | ||
|
||
public static CommentGetResponse of(Comment comment) { | ||
return CommentGetResponse.builder() | ||
.nickName(comment.getCounselor().getNickname()) | ||
.content(comment.getContent()) | ||
.totalLike(comment.getTotalLike()) | ||
.updatedAt(TimeUtil.getUpdatedAt(comment.getUpdatedAt())) | ||
.isChosen(comment.getIsChosen()) | ||
.build(); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/main/java/com/example/sharemind/comment/exception/CommentErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.example.sharemind.comment.exception; | ||
|
||
import lombok.Getter; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
public enum CommentErrorCode { | ||
|
||
COMMENT_ALREADY_REGISTERED(HttpStatus.BAD_REQUEST, "상담사 당 댓글은 한 번만 작성할 수 있습니다."); | ||
|
||
private final HttpStatus httpStatus; | ||
private final String message; | ||
|
||
CommentErrorCode(HttpStatus httpStatus, String message) { | ||
this.httpStatus = httpStatus; | ||
this.message = message; | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/com/example/sharemind/comment/exception/CommentException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.example.sharemind.comment.exception; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class CommentException extends RuntimeException { | ||
|
||
private final CommentErrorCode errorCode; | ||
|
||
public CommentException(CommentErrorCode errorCode, String message) { | ||
super(errorCode.getMessage() + " : " + message); | ||
this.errorCode = errorCode; | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/main/java/com/example/sharemind/comment/presentation/CommentController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.example.sharemind.comment.presentation; | ||
|
||
import com.example.sharemind.comment.application.CommentService; | ||
import com.example.sharemind.comment.dto.request.CommentCreateRequest; | ||
import com.example.sharemind.comment.dto.response.CommentGetResponse; | ||
import com.example.sharemind.global.exception.CustomExceptionResponse; | ||
import com.example.sharemind.global.jwt.CustomUserDetails; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.Parameters; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
@Tag(name = "Comment Controller", description = "일대다 상담 답변 관리 컨트롤러") | ||
@RestController | ||
@RequestMapping("/api/v1/comments") | ||
@RequiredArgsConstructor | ||
public class CommentController { | ||
|
||
private final CommentService commentService; | ||
|
||
@Operation(summary = "상담사 사이드 일대다 상담 질문 단건의 댓글 조회", description = """ | ||
- 상담사가 일대다 상담 질문에 대답하기 위한 상담 질문 단건의 댓글 조회 | ||
- 주소 형식: /api/v1/comments/counselors/1""") | ||
@ApiResponses({ | ||
@ApiResponse(responseCode = "200", description = "조회 성공"), | ||
@ApiResponse(responseCode = "400", description = "1. 진행중이지 않은 상담 2. 마감된 상담 중 상담사 본인이 답변을 작성하지 않은 상담", | ||
content = @Content(mediaType = "application/json", | ||
schema = @Schema(implementation = CustomExceptionResponse.class)) | ||
) | ||
}) | ||
@Parameters({ | ||
@Parameter(name = "postId", description = """ | ||
- 일대다 상담 ID""") | ||
}) | ||
@GetMapping("/counselors/{postId}") | ||
public ResponseEntity<List<CommentGetResponse>> getCounselorComments(@PathVariable Long postId, | ||
@AuthenticationPrincipal CustomUserDetails customUserDetails) { | ||
return ResponseEntity.ok(commentService.getCommentsByPost(postId, customUserDetails.getCustomer().getCustomerId())); | ||
} | ||
|
||
@Operation(summary = "상담사 사이드 일대다 상담 댓글 작성", description = """ | ||
- 상담사 사이드 일대다 상담 댓글 작성 API | ||
- 주소 형식: /api/v1/comments/counselors""") | ||
@ApiResponses({ | ||
@ApiResponse(responseCode = "201", description = "댓글 생성 성공"), | ||
@ApiResponse(responseCode = "400", description = "1. 진행중이지 않은 상담 2. 마감된 상담 중 상담사 본인이 답변을 작성하지 않은 상담 3. 이미 답변을 작성한 상담", | ||
content = @Content(mediaType = "application/json", | ||
schema = @Schema(implementation = CustomExceptionResponse.class)) | ||
) | ||
}) | ||
@PostMapping("/counselors") | ||
public ResponseEntity<Void> createComments(@RequestBody CommentCreateRequest commentCreateRequest, | ||
@AuthenticationPrincipal CustomUserDetails customUserDetails) { | ||
commentService.createComment(commentCreateRequest, customUserDetails.getCustomer().getCustomerId()); | ||
return ResponseEntity.status(HttpStatus.CREATED).build(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/example/sharemind/comment/repository/CommentRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.example.sharemind.comment.repository; | ||
|
||
import com.example.sharemind.comment.domain.Comment; | ||
import com.example.sharemind.counselor.domain.Counselor; | ||
import com.example.sharemind.post.domain.Post; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
@Repository | ||
public interface CommentRepository extends JpaRepository<Comment, Long> { | ||
List<Comment> findByPostAndIsActivatedIsTrue(Post post); | ||
|
||
Comment findByPostAndCounselorAndIsActivatedIsTrue(Post post, Counselor counselor); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.