Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import com.example.blog.domain.comment.dto.CommentResponse;
import com.example.blog.domain.comment.dto.CommentUpdateRequest;
import com.example.blog.domain.comment.service.CommentService;
import com.example.blog.domain.report.dto.ReportCommentRequest;
import com.example.blog.domain.report.dto.ReportResponse;
import com.example.blog.domain.report.service.ReportService;
import com.example.blog.global.response.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -17,6 +20,7 @@
public class CommentController {

private final CommentService commentService;
private final ReportService reportService;

@PostMapping("/api/v1/posts/{postId}/comments")
@ResponseStatus(HttpStatus.CREATED)
Expand Down Expand Up @@ -50,4 +54,23 @@ public void delete(
) {
commentService.delete(userId, commentId);
}

@PostMapping("/api/v1/posts/{postId}/comments/{commentId}/accept")
public ApiResponse<CommentResponse> accept(
@RequestHeader("X-User-Id") Long userId,
@PathVariable Long postId,
@PathVariable Long commentId
) {
return ApiResponse.success(commentService.acceptComment(userId, postId, commentId));
}

@PostMapping("/api/v1/comments/{commentId}/reports")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<ReportResponse> reportComment(
@RequestHeader("X-User-Id") Long reporterId,
@PathVariable Long commentId,
@RequestBody @Valid ReportCommentRequest request
) {
return ApiResponse.success(reportService.reportComment(reporterId, commentId, request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public record CommentResponse(
Long userId,
String username,
String content,
boolean accepted,
Long parentCommentId,
List<CommentResponse> replies,
LocalDateTime createdAt
Expand All @@ -26,6 +27,7 @@ public static CommentResponse from(Comment comment) {
comment.getUser().getId(),
comment.getUser().getUsername(),
comment.getContent(),
comment.isAccepted(),
comment.getParentComment() != null ? comment.getParentComment().getId() : null,
replies,
comment.getCreatedAt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,28 @@ public class Comment extends BaseEntity {
@OneToMany(mappedBy = "parentComment")
private List<Comment> replies = new ArrayList<>();

@Column(nullable = false)
private boolean accepted;

public static Comment of(User user, Post post, String content, Comment parentComment) {
Comment comment = new Comment();
comment.user = user;
comment.post = post;
comment.content = content;
comment.parentComment = parentComment;
comment.accepted = false;
return comment;
}

public void update(String content) {
this.content = content;
}

public void accept() {
this.accepted = true;
}

public void unaccept() {
this.accepted = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface CommentRepository extends JpaRepository<Comment, Long> {

List<Comment> findByPost_IdAndParentCommentIsNull(Long postId);

Optional<Comment> findByPost_IdAndAcceptedTrue(Long postId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public CommentResponse create(Long userId, Long postId, CommentCreateRequest req
parentComment = commentRepository.findById(request.parentCommentId())
.orElseThrow(() -> new NotFoundException(ErrorCode.COMMENT_NOT_FOUND));
if (!parentComment.getPost().getId().equals(postId)) {
throw new BusinessException(ErrorCode.INVALID_REPORT_TARGET);
throw new BusinessException(ErrorCode.INVALID_PARENT_COMMENT);
}
if (parentComment.getParentComment() != null) {
throw new BusinessException(ErrorCode.INVALID_REPORT_TARGET);
throw new BusinessException(ErrorCode.INVALID_PARENT_COMMENT);
}
}

Expand Down Expand Up @@ -76,4 +76,28 @@ public void delete(Long userId, Long commentId) {
}
commentRepository.delete(comment);
}

public CommentResponse acceptComment(Long userId, Long postId, Long commentId) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new NotFoundException(ErrorCode.POST_NOT_FOUND));
if (!post.getUser().getId().equals(userId)) {
throw new BusinessException(ErrorCode.FORBIDDEN_ACCESS);
}

Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new NotFoundException(ErrorCode.COMMENT_NOT_FOUND));
if (!comment.getPost().getId().equals(postId)) {
throw new BusinessException(ErrorCode.INVALID_PARENT_COMMENT);
}

if (comment.isAccepted()) {
return CommentResponse.from(comment);
}

commentRepository.findByPost_IdAndAcceptedTrue(postId)
.ifPresent(Comment::unaccept);

comment.accept();
return CommentResponse.from(comment);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import com.example.blog.domain.post.dto.PostResponse;
import com.example.blog.domain.post.dto.PostUpdateRequest;
import com.example.blog.domain.post.service.PostService;
import com.example.blog.domain.report.dto.ReportPostRequest;
import com.example.blog.domain.report.dto.ReportResponse;
import com.example.blog.domain.report.service.ReportService;
import com.example.blog.global.response.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -17,6 +20,7 @@
public class PostController {

private final PostService postService;
private final ReportService reportService;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
Expand Down Expand Up @@ -58,4 +62,22 @@ public void delete(
) {
postService.delete(userId, postId);
}

@PostMapping("/{postId}/hide")
public ApiResponse<PostResponse> hide(
@RequestHeader("X-User-Id") Long userId,
@PathVariable Long postId
) {
return ApiResponse.success(postService.hidePost(userId, postId));
}

@PostMapping("/{postId}/reports")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<ReportResponse> reportPost(
@RequestHeader("X-User-Id") Long reporterId,
@PathVariable Long postId,
@RequestBody @Valid ReportPostRequest request
) {
return ApiResponse.success(reportService.reportPost(reporterId, postId, request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static PostResponse from(Post post) {
post.getUser().getUsername(),
post.getTitle(),
post.getContent(),
post.getStatus(),
post.getStatus().name(),
post.getCreatedAt(),
post.getUpdatedAt()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.example.blog.domain.comment.entity.Comment;
import com.example.blog.domain.user.entity.User;
import com.example.blog.global.entity.BaseEntity;
import com.example.blog.global.exception.BusinessException;
import com.example.blog.global.exception.ErrorCode;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down Expand Up @@ -32,22 +34,23 @@ public class Post extends BaseEntity {
@Column(columnDefinition = "TEXT")
private String content;

@Enumerated(EnumType.STRING)
@Column(length = 20)
private String status;
private PostStatus status;

@OneToMany(mappedBy = "post")
private List<Comment> comments = new ArrayList<>();

public static Post of(User user, String title, String content, String status) {
public static Post of(User user, String title, String content, PostStatus status) {
Post post = new Post();
post.user = user;
post.title = title;
post.content = content;
post.status = status != null ? status : "PUBLISHED";
post.status = status != null ? status : PostStatus.PUBLISHED;
return post;
}

public void update(String title, String content, String status) {
public void update(String title, String content, PostStatus status) {
if (title != null) {
this.title = title;
}
Expand All @@ -58,4 +61,11 @@ public void update(String title, String content, String status) {
this.status = status;
}
}

public void hide() {
if (this.status == PostStatus.HIDDEN) {
throw new BusinessException(ErrorCode.POST_ALREADY_HIDDEN);
}
this.status = PostStatus.HIDDEN;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.blog.domain.post.entity;

public enum PostStatus {
PUBLISHED, HIDDEN
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.example.blog.domain.post.repository;

import com.example.blog.domain.post.entity.Post;
import com.example.blog.domain.post.entity.PostStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<Post, Long> {

Page<Post> findByStatus(String status, Pageable pageable);
Page<Post> findByStatus(PostStatus status, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.blog.domain.post.dto.PostResponse;
import com.example.blog.domain.post.dto.PostUpdateRequest;
import com.example.blog.domain.post.entity.Post;
import com.example.blog.domain.post.entity.PostStatus;
import com.example.blog.domain.post.repository.PostRepository;
import com.example.blog.domain.user.entity.User;
import com.example.blog.domain.user.repository.UserRepository;
Expand Down Expand Up @@ -32,7 +33,8 @@ public class PostService {
public PostResponse create(Long userId, PostCreateRequest request) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND));
Post post = Post.of(user, request.title(), request.content(), request.status());
PostStatus status = parseStatus(request.status());
Post post = Post.of(user, request.title(), request.content(), status);
return PostResponse.from(postRepository.save(post));
}

Expand All @@ -41,7 +43,7 @@ public PostListResponse findAll(String status, int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
Page<Post> posts;
if (status != null && !status.isBlank()) {
posts = postRepository.findByStatus(status, pageable);
posts = postRepository.findByStatus(PostStatus.valueOf(status.toUpperCase()), pageable);
} else {
posts = postRepository.findAll(pageable);
}
Expand All @@ -64,7 +66,8 @@ public PostResponse update(Long userId, Long postId, PostUpdateRequest request)
if (!post.getUser().getId().equals(userId)) {
throw new BusinessException(ErrorCode.FORBIDDEN_ACCESS);
}
post.update(request.title(), request.content(), request.status());
PostStatus status = parseStatus(request.status());
post.update(request.title(), request.content(), status);
return PostResponse.from(post);
}

Expand All @@ -76,4 +79,21 @@ public void delete(Long userId, Long postId) {
}
postRepository.delete(post);
}

public PostResponse hidePost(Long userId, Long postId) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new NotFoundException(ErrorCode.POST_NOT_FOUND));
if (!post.getUser().getId().equals(userId)) {
throw new BusinessException(ErrorCode.FORBIDDEN_ACCESS);
}
post.hide();
return PostResponse.from(post);
}

private PostStatus parseStatus(String status) {
if (status == null || status.isBlank()) {
return null;
}
return PostStatus.valueOf(status.toUpperCase());
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.example.blog.domain.report.controller;

import com.example.blog.domain.report.dto.ReportCreateRequest;
import com.example.blog.domain.report.dto.ReportResponse;
import com.example.blog.domain.report.service.ReportService;
import com.example.blog.global.response.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -18,13 +15,12 @@ public class ReportController {

private final ReportService reportService;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<ReportResponse> create(
@RequestHeader("X-User-Id") Long reporterId,
@RequestBody @Valid ReportCreateRequest request
@PostMapping("/{reportId}/resolve")
public ApiResponse<ReportResponse> resolve(
@RequestHeader("X-User-Id") Long handlerId,
@PathVariable Long reportId
) {
return ApiResponse.success(reportService.create(reporterId, request));
return ApiResponse.success(reportService.resolveReport(handlerId, reportId));
}

@GetMapping
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.blog.domain.report.dto;

import jakarta.validation.constraints.NotBlank;

public record ReportCommentRequest(
@NotBlank(message = "신고 사유는 필수입니다.")
String reason
) {}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.blog.domain.report.dto;

import jakarta.validation.constraints.NotBlank;

public record ReportPostRequest(
@NotBlank(message = "신고 사유는 필수입니다.")
String reason
) {}
Loading