Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public enum ErrorType {
POST_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "id에 해당하는 게시글이 존재하지 않습니다."),
TAGGED_USER_MAX_SIZE_20_ERROR(HttpStatus.BAD_REQUEST, "사용자 태그는 최대 20명까지 등록 가능합니다."),

// 리뷰 예외
NOT_TAGGED_USER_ERROR(HttpStatus.BAD_REQUEST, "원 게시글에 태그되지 않은 사용자입니다."),

// S3 예외
EMPTY_IMAGE_ERROR(HttpStatus.BAD_REQUEST, "이미지 파일이 비어있습니다."),
IMAGE_UPLOAD_FAILED_ERROR(HttpStatus.BAD_REQUEST, "이미지 업로드에 실패하였습니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.double_o.dambap.exception.review;

import com.double_o.dambap.exception.BusinessException;
import com.double_o.dambap.exception.dto.ErrorType;

public class ReviewInvalidException extends BusinessException {

public ReviewInvalidException(ErrorType errorType) {
super(errorType);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.double_o.dambap.post.domain;
package com.double_o.dambap.media;

import com.double_o.dambap.post.domain.Type;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand All @@ -24,13 +26,13 @@ public class Media {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "post_id")
private Long postId;
@Column(name = "target_id")
private Long targetId;

@Column(name = "media_url")
private String mediaUrl;

@Enumerated(EnumType.STRING)
@Enumerated(EnumType.STRING)
private Type type;

private int sequence; // 사용자가 이미지를 보낸 순서
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.double_o.dambap.post.infrastructure;
package com.double_o.dambap.media;

import com.double_o.dambap.post.domain.Media;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
Expand All @@ -10,7 +9,11 @@
@Transactional(readOnly = true)
public interface MediaRepository extends JpaRepository<Media, Long> {

void deleteAllByPostId(Long postId);
void deleteAllByTargetId(Long postId);

List<Media> findALLByPostIdOrderBySequenceAsc(Long postId);
void deleteByTargetId(Long targetId);

List<Media> findALLByTargetIdOrderBySequenceAsc(Long postId);

Media findByTargetId(Long postId);
}
90 changes: 44 additions & 46 deletions src/main/java/com/double_o/dambap/post/application/PostService.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
package com.double_o.dambap.post.application;

import static com.double_o.dambap.post.utils.TaggedUserConstants.TAGGED_USER_MAX_SIZE;

import com.double_o.dambap.auth.model.AuthUser;
import com.double_o.dambap.exception.dto.ErrorType;
import com.double_o.dambap.exception.post.PostInvalidException;
import com.double_o.dambap.post.domain.PostLike;
import com.double_o.dambap.post.domain.Media;
import com.double_o.dambap.recommendation.application.RecommendService;
import com.double_o.dambap.media.Media;
import com.double_o.dambap.post.domain.Post;
import com.double_o.dambap.post.domain.TaggedUser;
import com.double_o.dambap.post.domain.Type;
import com.double_o.dambap.post.dto.request.PostRequest;
import com.double_o.dambap.post.dto.response.PostInfoResponse;
import com.double_o.dambap.post.dto.response.PostLikeResponse;
import com.double_o.dambap.post.dto.response.PostPageResponse;
import com.double_o.dambap.post.infrastructure.PostLikeRepository;
import com.double_o.dambap.post.domain.Post;
import com.double_o.dambap.post.dto.request.PostRequest;
import com.double_o.dambap.post.dto.response.PostResponse;
import com.double_o.dambap.post.infrastructure.MediaRepository;
import com.double_o.dambap.post.infrastructure.PostRepository;
import com.double_o.dambap.auth.service.AuthValidationUtils;
import com.double_o.dambap.post.infrastructure.TaggedUserRepository;
import com.double_o.dambap.recommendation.dto.response.RecommendResponse;
import com.double_o.dambap.media.MediaRepository;
import com.double_o.dambap.auth.service.AuthValidationUtils;
import com.double_o.dambap.post.utils.TaggedUserConstants;
import com.double_o.dambap.user.domain.User;
import com.double_o.dambap.user.application.UserValidationService;
import com.double_o.dambap.common.dto.SuccessResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -41,9 +37,9 @@ public class PostService {

private final UserValidationService userValidationService;
private final PostRepository postRepository;
private final PostLikeRepository postLikeRepository;
private final TaggedUserRepository taggedUserRepository;
private final MediaRepository mediaRepository;
private final RecommendService recommendService;

/**
* 게시글 등록
Expand All @@ -59,7 +55,7 @@ public PostResponse createPost(AuthUser user, PostRequest request) {
.expireDays(request.getExpireDays())
.content(request.getContent())
.isPublic(request.isPublic())
.likeCnt(0)
.recommendationCnt(0)
.writerId(findUser.getId())
.build();

Expand Down Expand Up @@ -129,18 +125,25 @@ public SuccessResponse deletePost(AuthUser user, Long postId) {
* 게시글 좋아요
*/
@Transactional
public PostLikeResponse updatePostLike(AuthUser user, Long postId) {
public RecommendResponse updatePostRecommendStatus(AuthUser user, Long postId) {

User findUser = userValidationService.getUserOrThrowIfNotExist(user.getId());

Post findPost = getPostOrThrowIfNotExist(postId);

Optional<PostLike> postLike = postLikeRepository.findByPostIdAndLikerId(
findPost.getId(), findUser.getId());
recommendService.updateRecommendStatus(findPost, findUser, Type.POST);

updateLikeStatus(postLike, findPost, findUser);
return RecommendResponse.toResponse(findPost.getId(), findPost.getRecommendationCnt());
}

return PostLikeResponse.toResponse(findPost.getId(), findPost.getLikeCnt());
/**
* 게시글 추천 수 조회
*/
public RecommendResponse getRecommendationCnt(Long postId) {

Post findPost = getPostOrThrowIfNotExist(postId);

return RecommendResponse.toResponse(findPost.getId(), findPost.getRecommendationCnt());
}

/**
Expand All @@ -149,34 +152,38 @@ public PostLikeResponse updatePostLike(AuthUser user, Long postId) {
@Transactional
public SuccessResponse changePublicity(AuthUser user, Long postId) {

userValidationService.getUserOrThrowIfNotExist(user.getId());

Post findPost = getPostOrThrowIfNotExist(postId);

User findUser = userValidationService.getUserOrThrowIfNotExist(user.getId());

AuthValidationUtils.verifySameUser(findUser.getId(), findPost.getWriterId());

findPost.changePublicity();

return new SuccessResponse("공개여부가 성공적으로 전환되었습니다.");
}

/**
* 내가 나눈 음식 게시글 목록 최신순으로 반환
*/
public PostPageResponse getAllMySharedPost(AuthUser user, Pageable pageable) {
public PostPageResponse getAllMyPost(AuthUser user, Pageable pageable) {

User findUser = userValidationService.getUserOrThrowIfNotExist(user.getId());

Page<Post> findAllMySharedPost = postRepository.findAllByWriterIdOrderByCreatedAtDesc(
Page<Post> findAllMyPost = postRepository.findAllByWriterIdOrderByCreatedAtDesc(
findUser.getId(), pageable);

return PostPageResponse.toResponse(
pageable.getPageNumber(),
findAllMySharedPost.map(this::convertToPostInfoResponse).toList());
findAllMyPost.map(this::convertToPostInfoResponse).toList());
}

/**
* 전체 게시글 목록 최신순으로 반환
*/
@Transactional(readOnly = true)
public PostPageResponse getAllLatestPost(Pageable pageable) {

Page<Post> findAllPosts = postRepository.findAllByOrderByCreatedAtDesc(
pageable);

Expand All @@ -189,6 +196,7 @@ public PostPageResponse getAllLatestPost(Pageable pageable) {
// 게시글 응답 형변환
private PostResponse getPostResponse(Post post, List<String> mediaUrls,
List<Long> taggedUserIds) {

return PostResponse.toResponse(
post.getId(),
post.getCreatedAt(),
Expand All @@ -200,7 +208,7 @@ private PostResponse getPostResponse(Post post, List<String> mediaUrls,
mediaUrls,
taggedUserIds,
post.isPublic(),
post.getLikeCnt(),
post.getRecommendationCnt(),
post.getWriterId()
);
}
Expand All @@ -209,14 +217,14 @@ private PostResponse getPostResponse(Post post, List<String> mediaUrls,
private List<String> saveAndGetMediaUrls(PostRequest request, Post targetPost) {

// 기존 등록된 게시글 관련 미디어 전부 삭제
mediaRepository.deleteAllByPostId(targetPost.getId());
mediaRepository.deleteAllByTargetId(targetPost.getId());

// request 에서 받아온 미디어 목록에 시퀀스 반영(오름차순), 순서 보장하여 저장, 리스트로 가공하여 반환
List<Media> medias = IntStream.range(0, request.getMediaUrls().size())
.mapToObj(i -> Media.builder()
.postId(targetPost.getId())
.targetId(targetPost.getId())
.mediaUrl(request.getMediaUrls().get(i))
.type(Type.SHARED)
.type(Type.POST)
.sequence(i) // 순서 정보 부여
.build())
.toList();
Expand All @@ -230,7 +238,7 @@ private List<String> saveAndGetMediaUrls(PostRequest request, Post targetPost) {
private List<Long> saveAndGetTaggedUserIds(PostRequest request, Post targetPost) {

// 사용자 태그를 20명으로 제한
if (request.getTaggedUserIds().size() > TAGGED_USER_MAX_SIZE) {
if (request.getTaggedUserIds().size() > TaggedUserConstants.TAGGED_USER_MAX_SIZE) {
throw new PostInvalidException(ErrorType.TAGGED_USER_MAX_SIZE_20_ERROR);
}

Expand All @@ -253,42 +261,32 @@ private List<Long> saveAndGetTaggedUserIds(PostRequest request, Post targetPost)

// 게시글 연관 미디어 순서 보장하여 조회
private List<String> getMediaUrls(Post post) {
return mediaRepository.findALLByPostIdOrderBySequenceAsc(post.getId()).stream()

return mediaRepository.findALLByTargetIdOrderBySequenceAsc(post.getId()).stream()
.map(Media::getMediaUrl)
.toList();
}

// 게시글 연관 태그 순서 보장하여 조회
private List<Long> getTaggedUserIds(Post post) {

return taggedUserRepository.findAllByPostIdOrderBySequenceAsc(post.getId()).stream()
.map(TaggedUser::getTaggedUserId)
.toList();
}

// 기존 추천한 이력 유무에 따른 추천수 증감
private void updateLikeStatus(Optional<PostLike> postLike, Post findPost, User findUser) {
if (postLike.isEmpty()) {
postLikeRepository.save(PostLike.builder()
.likedAt(LocalDate.now())
.postId(findPost.getId())
.likerId(findUser.getId())
.build());
findPost.increaseRecommendationCnt();
} else {
postLikeRepository.deleteById(postLike.get().getId());
findPost.decreaseRecommendationCnt();
}
}

// 게시글 정보 응답 dto 로 변환
private PostInfoResponse convertToPostInfoResponse(Post post) {
Media thumbnailMedia = mediaRepository.findALLByPostIdOrderBySequenceAsc(post.getId()).get(0);

Media thumbnailMedia = mediaRepository.findALLByTargetIdOrderBySequenceAsc(post.getId())
.get(0);
return PostInfoResponse.toResponse(post.getId(), post.getContent(),
thumbnailMedia.getMediaUrl());
}

// 게시글 반환, 없으면 예외처리
public Post getPostOrThrowIfNotExist(Long postId) {

return postRepository.findById(postId).orElseThrow(
() -> new PostInvalidException(ErrorType.POST_NOT_FOUND_ERROR)
);
Expand Down
15 changes: 9 additions & 6 deletions src/main/java/com/double_o/dambap/post/domain/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.double_o.dambap.common.entity.BaseEntity;
import com.double_o.dambap.exception.dto.ErrorType;
import com.double_o.dambap.exception.post.PostInvalidException;
import com.double_o.dambap.recommendation.common.Recommendable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
Expand All @@ -21,7 +22,7 @@
@AllArgsConstructor
@Getter
@Builder
public class Post extends BaseEntity {
public class Post extends BaseEntity implements Recommendable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -38,8 +39,8 @@ public class Post extends BaseEntity {
private boolean isPublic;

// cnt 정보
@Column(name = "like_cnt")
private int likeCnt;
@Column(name = "recommendation_cnt", nullable = false)
private int recommendationCnt = 0;

// 참조 정보
@Column(name = "writer_id")
Expand All @@ -58,13 +59,15 @@ public void updatePost(
this.isPublic = isPublic;
}

@Override
public void increaseRecommendationCnt() {
this.likeCnt++;
this.recommendationCnt++;
}

@Override
public void decreaseRecommendationCnt() {
if (this.likeCnt > 0) {
this.likeCnt--;
if (this.recommendationCnt > 0) {
this.recommendationCnt--;
} else {
throw new PostInvalidException(ErrorType.CNT_NEGATIVE_ERROR);
}
Expand Down
45 changes: 0 additions & 45 deletions src/main/java/com/double_o/dambap/post/domain/PostLike.java

This file was deleted.

Loading