73 lines
3.3 KiB
Kotlin
73 lines
3.3 KiB
Kotlin
package me.wypark.blogbackend.api.controller
|
|
|
|
import me.wypark.blogbackend.api.common.ApiResponse
|
|
import me.wypark.blogbackend.api.dto.CommentDeleteRequest
|
|
import me.wypark.blogbackend.api.dto.CommentResponse
|
|
import me.wypark.blogbackend.api.dto.CommentSaveRequest
|
|
import me.wypark.blogbackend.domain.comment.CommentService
|
|
import org.springframework.http.ResponseEntity
|
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
|
import org.springframework.security.core.userdetails.User
|
|
import org.springframework.web.bind.annotation.*
|
|
|
|
/**
|
|
* [일반 사용자용 댓글 API]
|
|
*
|
|
* 게시글에 대한 사용자 참여(Social Interaction)를 담당하는 컨트롤러입니다.
|
|
* 사용자 경험(UX)을 고려하여, 회원가입 없이도 자유롭게 소통할 수 있도록
|
|
* 회원(Member)과 비회원(Guest)의 접근을 동시에 허용하는 하이브리드 로직을 수행합니다.
|
|
*/
|
|
@RestController
|
|
@RequestMapping("/api/comments")
|
|
class CommentController(
|
|
private val commentService: CommentService
|
|
) {
|
|
|
|
/**
|
|
* 특정 게시글의 전체 댓글 목록을 조회합니다.
|
|
*
|
|
* 단순 리스트가 아닌, 대댓글(Nested Comments) 구조를 유지한 상태로 반환하여
|
|
* 클라이언트가 별도의 재귀 로직 구현 없이 트리 형태로 즉시 렌더링할 수 있도록 지원합니다.
|
|
*/
|
|
@GetMapping
|
|
fun getComments(@RequestParam postSlug: String): ResponseEntity<ApiResponse<List<CommentResponse>>> {
|
|
return ResponseEntity.ok(ApiResponse.success(commentService.getComments(postSlug)))
|
|
}
|
|
|
|
/**
|
|
* 댓글을 작성합니다 (회원/비회원 공용).
|
|
*
|
|
* 참여 장벽을 낮추기 위해 로그인 여부를 강제하지 않습니다.
|
|
* Security Context의 User 객체가 null일 경우 비회원으로 간주하며,
|
|
* 이 경우 RequestBody에 포함된 닉네임과 비밀번호를 사용하여 임시 신원을 생성합니다.
|
|
*/
|
|
@PostMapping
|
|
fun createComment(
|
|
@RequestBody request: CommentSaveRequest,
|
|
@AuthenticationPrincipal user: User? // 비회원 접근 시 null (Optional Principal)
|
|
): ResponseEntity<ApiResponse<Long>> {
|
|
val email = user?.username // 인증된 사용자라면 email 추출
|
|
val commentId = commentService.createComment(request, email)
|
|
return ResponseEntity.ok(ApiResponse.success(commentId, "댓글이 등록되었습니다."))
|
|
}
|
|
|
|
/**
|
|
* 댓글을 삭제합니다.
|
|
*
|
|
* 작성자 유형(회원/비회원)에 따라 검증 전략(Strategy)이 달라집니다.
|
|
* - 회원: 현재 로그인한 사용자의 ID와 댓글 작성자 ID의 일치 여부를 검증
|
|
* - 비회원: 댓글 작성 시 설정한 비밀번호(Guest Password)의 일치 여부를 검증
|
|
*/
|
|
@DeleteMapping("/{id}")
|
|
fun deleteComment(
|
|
@PathVariable id: Long,
|
|
@RequestBody(required = false) request: CommentDeleteRequest?, // 비회원일 경우에만 바디가 필요함
|
|
@AuthenticationPrincipal user: User?
|
|
): ResponseEntity<ApiResponse<Nothing>> {
|
|
val email = user?.username
|
|
val password = request?.guestPassword
|
|
|
|
commentService.deleteComment(id, email, password)
|
|
return ResponseEntity.ok(ApiResponse.success(message = "댓글이 삭제되었습니다."))
|
|
}
|
|
} |