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 @@ -8,7 +8,9 @@
import com.example.solidconnection.post.dto.PostLikeResponse;
import com.example.solidconnection.post.dto.PostUpdateRequest;
import com.example.solidconnection.post.dto.PostUpdateResponse;
import com.example.solidconnection.post.service.PostService;
import com.example.solidconnection.post.service.PostCommandService;
import com.example.solidconnection.post.service.PostLikeService;
import com.example.solidconnection.post.service.PostQueryService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -32,7 +34,9 @@
@RequestMapping("/communities")
public class PostController {

private final PostService postService;
private final PostQueryService postQueryService;
private final PostCommandService postCommandService;
private final PostLikeService postLikeService;

@PostMapping(value = "/{code}/posts")
public ResponseEntity<?> createPost(
Expand All @@ -44,7 +48,7 @@ public ResponseEntity<?> createPost(
if (imageFile == null) {
imageFile = Collections.emptyList();
}
PostCreateResponse post = postService
PostCreateResponse post = postCommandService
.createPost(principal.getName(), code, postCreateRequest, imageFile);
return ResponseEntity.ok().body(post);
}
Expand All @@ -60,19 +64,18 @@ public ResponseEntity<?> updatePost(
if (imageFile == null) {
imageFile = Collections.emptyList();
}
PostUpdateResponse postUpdateResponse = postService
PostUpdateResponse postUpdateResponse = postCommandService
.updatePost(principal.getName(), code, postId, postUpdateRequest, imageFile);
return ResponseEntity.ok().body(postUpdateResponse);
}


@GetMapping("/{code}/posts/{post_id}")
public ResponseEntity<?> findPostById(
Principal principal,
@PathVariable("code") String code,
@PathVariable("post_id") Long postId) {

PostFindResponse postFindResponse = postService
PostFindResponse postFindResponse = postQueryService
.findPostById(principal.getName(), code, postId);
return ResponseEntity.ok().body(postFindResponse);
}
Expand All @@ -83,7 +86,7 @@ public ResponseEntity<?> deletePostById(
@PathVariable("code") String code,
@PathVariable("post_id") Long postId) {

PostDeleteResponse postDeleteResponse = postService.deletePostById(principal.getName(), code, postId);
PostDeleteResponse postDeleteResponse = postCommandService.deletePostById(principal.getName(), code, postId);
return ResponseEntity.ok().body(postDeleteResponse);
}

Expand All @@ -94,7 +97,7 @@ public ResponseEntity<?> likePost(
@PathVariable("post_id") Long postId
) {

PostLikeResponse postLikeResponse = postService.likePost(principal.getName(), code, postId);
PostLikeResponse postLikeResponse = postLikeService.likePost(principal.getName(), code, postId);
return ResponseEntity.ok().body(postLikeResponse);
}

Expand All @@ -105,7 +108,7 @@ public ResponseEntity<?> dislikePost(
@PathVariable("post_id") Long postId
) {

PostDislikeResponse postDislikeResponse = postService.dislikePost(principal.getName(), code, postId);
PostDislikeResponse postDislikeResponse = postLikeService.dislikePost(principal.getName(), code, postId);
return ResponseEntity.ok().body(postDislikeResponse);
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
package com.example.solidconnection.post.service;

import com.example.solidconnection.board.domain.Board;
import com.example.solidconnection.board.dto.PostFindBoardResponse;
import com.example.solidconnection.board.repository.BoardRepository;
import com.example.solidconnection.comment.dto.PostFindCommentResponse;
import com.example.solidconnection.comment.service.CommentService;
import com.example.solidconnection.custom.exception.CustomException;
import com.example.solidconnection.entity.PostImage;
import com.example.solidconnection.post.domain.Post;
import com.example.solidconnection.post.domain.PostLike;
import com.example.solidconnection.post.dto.PostCreateRequest;
import com.example.solidconnection.post.dto.PostCreateResponse;
import com.example.solidconnection.post.dto.PostDeleteResponse;
import com.example.solidconnection.post.dto.PostDislikeResponse;
import com.example.solidconnection.post.dto.PostFindPostImageResponse;
import com.example.solidconnection.post.dto.PostFindResponse;
import com.example.solidconnection.post.dto.PostLikeResponse;
import com.example.solidconnection.post.dto.PostUpdateRequest;
import com.example.solidconnection.post.dto.PostUpdateResponse;
import com.example.solidconnection.post.repository.PostLikeRepository;
import com.example.solidconnection.post.repository.PostRepository;
import com.example.solidconnection.s3.S3Service;
import com.example.solidconnection.s3.UploadedFileUrlResponse;
import com.example.solidconnection.service.RedisService;
import com.example.solidconnection.siteuser.domain.SiteUser;
import com.example.solidconnection.siteuser.dto.PostFindSiteUserResponse;
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
import com.example.solidconnection.type.BoardCode;
import com.example.solidconnection.type.ImgType;
Expand All @@ -33,80 +23,31 @@
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_DELETE_OR_UPDATE_QUESTION;
import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_UPLOAD_MORE_THAN_FIVE_IMAGES;
import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_POST_LIKE;
import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_BOARD_CODE;
import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_ACCESS;
import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_CATEGORY;

@Service
@RequiredArgsConstructor
public class PostService {
public class PostCommandService {

private final PostRepository postRepository;
private final SiteUserRepository siteUserRepository;
private final BoardRepository boardRepository;
private final S3Service s3Service;
private final CommentService commentService;
private final RedisService redisService;
private final RedisUtils redisUtils;
private final PostLikeRepository postLikeRepository;

private String validateCode(String code) {
try {
return String.valueOf(BoardCode.valueOf(code));
} catch (IllegalArgumentException ex) {
throw new CustomException(INVALID_BOARD_CODE);
}
}

private void validateOwnership(Post post, String email) {
if (!post.getSiteUser().getEmail().equals(email)) {
throw new CustomException(INVALID_POST_ACCESS);
}
}

private void validateFileSize(List<MultipartFile> imageFile) {
if (imageFile.isEmpty()) {
return;
}
if (imageFile.size() > 5) {
throw new CustomException(CAN_NOT_UPLOAD_MORE_THAN_FIVE_IMAGES);
}
}

private void validateQuestion(Post post) {
if (post.getIsQuestion()) {
throw new CustomException(CAN_NOT_DELETE_OR_UPDATE_QUESTION);
}
}

private void validatePostCategory(String category) {
if (!EnumUtils.isValidEnum(PostCategory.class, category) || category.equals(PostCategory.전체.toString())) {
throw new CustomException(INVALID_POST_CATEGORY);
}
}

private Boolean getIsOwner(Post post, String email) {
return post.getSiteUser().getEmail().equals(email);
}

private Boolean getIsLiked(Post post, SiteUser siteUser) {
return postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser)
.isPresent();
}

@Transactional
public PostCreateResponse createPost(String email, String code, PostCreateRequest postCreateRequest,
List<MultipartFile> imageFile) {

// 유효성 검증
String boardCode = validateCode(code);
validatePostCategory(postCreateRequest.postCategory());
Expand All @@ -126,7 +67,6 @@ public PostCreateResponse createPost(String email, String code, PostCreateReques
@Transactional
public PostUpdateResponse updatePost(String email, String code, Long postId, PostUpdateRequest postUpdateRequest,
List<MultipartFile> imageFile) {

// 유효성 검증
String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
Expand Down Expand Up @@ -155,40 +95,8 @@ private void savePostImages(List<MultipartFile> imageFile, Post post) {
}
}

private void removePostImages(Post post) {
for (PostImage postImage : post.getPostImageList()) {
s3Service.deletePostImage(postImage.getUrl());
}
post.getPostImageList().clear();
}

@Transactional(readOnly = true)
public PostFindResponse findPostById(String email, String code, Long postId) {

String boardCode = validateCode(code);

Post post = postRepository.getByIdUsingEntityGraph(postId);
SiteUser siteUser = siteUserRepository.getByEmail(email);
Boolean isOwner = getIsOwner(post, email);
Boolean isLiked = getIsLiked(post, siteUser);

PostFindBoardResponse boardPostFindResultDTO = PostFindBoardResponse.from(post.getBoard());
PostFindSiteUserResponse siteUserPostFindResultDTO = PostFindSiteUserResponse.from(post.getSiteUser());
List<PostFindPostImageResponse> postImageFindResultDTOList = PostFindPostImageResponse.from(post.getPostImageList());
List<PostFindCommentResponse> commentFindResultDTOList = commentService.findCommentsByPostId(email, postId);

// caching && 어뷰징 방지
if (redisService.isPresent(redisUtils.getValidatePostViewCountRedisKey(email, postId))) {
redisService.increaseViewCount(redisUtils.getPostViewCountRedisKey(postId));
}

return PostFindResponse.from(
post, isOwner, isLiked, boardPostFindResultDTO, siteUserPostFindResultDTO, commentFindResultDTOList, postImageFindResultDTOList);
}

@Transactional
public PostDeleteResponse deletePostById(String email, String code, Long postId) {

String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
validateOwnership(post, email);
Expand All @@ -203,40 +111,45 @@ public PostDeleteResponse deletePostById(String email, String code, Long postId)
return new PostDeleteResponse(postId);
}

@Transactional(isolation = Isolation.READ_COMMITTED)
public PostLikeResponse likePost(String email, String code, Long postId) {

String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
SiteUser siteUser = siteUserRepository.getByEmail(email);
validateDuplicatePostLike(post, siteUser);

PostLike postLike = new PostLike();
postLike.setPostAndSiteUser(post, siteUser);
postLikeRepository.save(postLike);
postRepository.increaseLikeCount(post.getId());

return PostLikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회
private String validateCode(String code) {
try {
return String.valueOf(BoardCode.valueOf(code));
} catch (IllegalArgumentException ex) {
throw new CustomException(INVALID_BOARD_CODE);
}
}

private void validateDuplicatePostLike(Post post, SiteUser siteUser) {
if (postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser).isPresent()) {
throw new CustomException(DUPLICATE_POST_LIKE);
private void validateOwnership(Post post, String email) {
if (!post.getSiteUser().getEmail().equals(email)) {
throw new CustomException(INVALID_POST_ACCESS);
}
}

@Transactional(isolation = Isolation.READ_COMMITTED)
public PostDislikeResponse dislikePost(String email, String code, Long postId) {
private void validateFileSize(List<MultipartFile> imageFile) {
if (imageFile.isEmpty()) {
return;
}
if (imageFile.size() > 5) {
throw new CustomException(CAN_NOT_UPLOAD_MORE_THAN_FIVE_IMAGES);
}
}

String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
SiteUser siteUser = siteUserRepository.getByEmail(email);
private void validateQuestion(Post post) {
if (post.getIsQuestion()) {
throw new CustomException(CAN_NOT_DELETE_OR_UPDATE_QUESTION);
}
}

PostLike postLike = postLikeRepository.getByPostAndSiteUser(post, siteUser);
postLike.resetPostAndSiteUser();
postLikeRepository.deleteById(postLike.getId());
postRepository.decreaseLikeCount(post.getId());
private void validatePostCategory(String category) {
if (!EnumUtils.isValidEnum(PostCategory.class, category) || category.equals(PostCategory.전체.toString())) {
throw new CustomException(INVALID_POST_CATEGORY);
}
}

return PostDislikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회
private void removePostImages(Post post) {
for (PostImage postImage : post.getPostImageList()) {
s3Service.deletePostImage(postImage.getUrl());
}
post.getPostImageList().clear();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.example.solidconnection.post.service;

import com.example.solidconnection.custom.exception.CustomException;
import com.example.solidconnection.post.domain.Post;
import com.example.solidconnection.post.domain.PostLike;
import com.example.solidconnection.post.dto.PostDislikeResponse;
import com.example.solidconnection.post.dto.PostLikeResponse;
import com.example.solidconnection.post.repository.PostLikeRepository;
import com.example.solidconnection.post.repository.PostRepository;
import com.example.solidconnection.siteuser.domain.SiteUser;
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
import com.example.solidconnection.type.BoardCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_POST_LIKE;
import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_BOARD_CODE;

@Service
@RequiredArgsConstructor
public class PostLikeService {

private final PostRepository postRepository;
private final SiteUserRepository siteUserRepository;
private final PostLikeRepository postLikeRepository;

@Transactional(isolation = Isolation.READ_COMMITTED)
public PostLikeResponse likePost(String email, String code, Long postId) {
String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
SiteUser siteUser = siteUserRepository.getByEmail(email);
validateDuplicatePostLike(post, siteUser);

PostLike postLike = new PostLike();
postLike.setPostAndSiteUser(post, siteUser);
postLikeRepository.save(postLike);
postRepository.increaseLikeCount(post.getId());

return PostLikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회
}

@Transactional(isolation = Isolation.READ_COMMITTED)
public PostDislikeResponse dislikePost(String email, String code, Long postId) {
String boardCode = validateCode(code);
Post post = postRepository.getById(postId);
SiteUser siteUser = siteUserRepository.getByEmail(email);

PostLike postLike = postLikeRepository.getByPostAndSiteUser(post, siteUser);
postLike.resetPostAndSiteUser();
postLikeRepository.deleteById(postLike.getId());
postRepository.decreaseLikeCount(post.getId());

return PostDislikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회
}

private String validateCode(String code) {
try {
return String.valueOf(BoardCode.valueOf(code));
} catch (IllegalArgumentException ex) {
throw new CustomException(INVALID_BOARD_CODE);
}
}

private void validateDuplicatePostLike(Post post, SiteUser siteUser) {
if (postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser).isPresent()) {
throw new CustomException(DUPLICATE_POST_LIKE);
}
}
}
Loading