diff --git a/src/main/java/com/leets/X/domain/post/controller/PostController.java b/src/main/java/com/leets/X/domain/post/controller/PostController.java index 6bec614..9d9fd9e 100644 --- a/src/main/java/com/leets/X/domain/post/controller/PostController.java +++ b/src/main/java/com/leets/X/domain/post/controller/PostController.java @@ -5,6 +5,7 @@ import com.leets.X.domain.post.dto.response.ParentPostResponseDto; import com.leets.X.domain.post.dto.response.PostResponseDto; import com.leets.X.domain.post.service.PostService; +import com.leets.X.domain.post.service.RepostService; import com.leets.X.global.common.response.ResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -26,6 +27,7 @@ public class PostController { private final PostService postService; + private final RepostService repostService; // 게시물 상세 조회(자식 게시물 까지 함께 조회됨) @GetMapping("/{id}") @@ -37,37 +39,51 @@ public ResponseDto getPost(@PathVariable Long id, @Authenticati // 모든 부모게시물 조회 @GetMapping("/all") - @Operation(summary = "전체 부모 글 조회") + @Operation(summary = "[Home] 추천 게시글") public ResponseDto> getAllParentPosts(@AuthenticationPrincipal String email) { List posts = postService.getAllParentPosts(email); return ResponseDto.response(ResponseMessage.GET_ALL_PARENT_POSTS_SUCCESS.getCode(), ResponseMessage.GET_ALL_PARENT_POSTS_SUCCESS.getMessage(), posts); } + @GetMapping("/user/{userId}") + @Operation(summary = "[Profile] 유저 게시글 조회") + public ResponseDto> getAllUserPosts(@PathVariable Long userId) { + List posts = repostService.getUserFeed(userId); + return ResponseDto.response(ResponseMessage.GET_USER_POST.getCode(), ResponseMessage.GET_USER_POST.getMessage(), posts); + } - @GetMapping("/likes") - @Operation(summary = "좋아요 수로 정렬한 게시물 조회") - public ResponseDto> getPostsSortedByLikes(@AuthenticationPrincipal String email) { - List posts = postService.getPostsSortedByLikes(email); - return ResponseDto.response(ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getCode(), ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getMessage(), posts); + @GetMapping("/following") + @Operation(summary = "[Home] 팔로잉 게시글 조회") + public ResponseDto> getAllFollowingPosts(@AuthenticationPrincipal String email) { + List posts = repostService.getFollowingPost(email); + return ResponseDto.response(ResponseMessage.GET_FOLLOWING_POST.getCode(), ResponseMessage.GET_FOLLOWING_POST.getMessage(), posts); } - @GetMapping("/latest") - @Operation(summary = "최신 게시물 조회") - public ResponseDto> getLatestPosts(@AuthenticationPrincipal String email) { - List posts = postService.getLatestParentPosts(email); - return ResponseDto.response(ResponseMessage.GET_LATEST_POST_SUCCESS.getCode(), ResponseMessage.GET_LATEST_POST_SUCCESS.getMessage(), posts); - } +// @GetMapping("/likes") +// @Operation(summary = "좋아요 수로 정렬한 게시물 조회") +// public ResponseDto> getPostsSortedByLikes(@AuthenticationPrincipal String email) { +// List posts = postService.getPostsSortedByLikes(email); +// return ResponseDto.response(ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getCode(), ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getMessage(), posts); +// } + + +// @GetMapping("/latest") +// @Operation(summary = "최신 게시물 조회") +// public ResponseDto> getLatestPosts(@AuthenticationPrincipal String email) { +// List posts = postService.getLatestParentPosts(email); +// return ResponseDto.response(ResponseMessage.GET_LATEST_POST_SUCCESS.getCode(), ResponseMessage.GET_LATEST_POST_SUCCESS.getMessage(), posts); +// } @PostMapping(value = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "글 생성") - public ResponseDto createPost(@RequestPart PostRequestDTO postRequestDTO, + public ResponseDto createPost(@RequestPart PostRequestDTO postRequestDTO, @RequestPart(value = "files", required = false) List files, @AuthenticationPrincipal String email) throws IOException { // 인증된 사용자의 이메일을 `@AuthenticationPrincipal`을 통해 주입받음 - PostResponseDto postResponseDto = postService.createPost(postRequestDTO, files , email); - return ResponseDto.response(ResponseMessage.POST_SUCCESS.getCode(), ResponseMessage.POST_SUCCESS.getMessage(), postResponseDto); + postService.createPost(postRequestDTO, files , email); + return ResponseDto.response(ResponseMessage.POST_SUCCESS.getCode(), ResponseMessage.POST_SUCCESS.getMessage()); } @PostMapping("/{postId}/like") @@ -79,13 +95,13 @@ public ResponseDto addLike(@PathVariable Long postId, @AuthenticationPri @PostMapping(value = "/{postId}/reply", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "답글 생성") - public ResponseDto createReply(@PathVariable Long postId, + public ResponseDto createReply(@PathVariable Long postId, @RequestPart PostRequestDTO postRequestDTO, @RequestPart(value = "files", required = false) List files, @AuthenticationPrincipal String email) throws IOException { // 답글 생성 서비스 호출 (부모 ID를 직접 전달) - PostResponseDto postResponseDto = postService.createReply(postId, postRequestDTO, files, email); - return ResponseDto.response(ResponseMessage.REPLY_SUCCESS.getCode(), ResponseMessage.REPLY_SUCCESS.getMessage(), postResponseDto); + postService.createReply(postId, postRequestDTO, files, email); + return ResponseDto.response(ResponseMessage.REPLY_SUCCESS.getCode(), ResponseMessage.REPLY_SUCCESS.getMessage()); } @@ -104,4 +120,11 @@ public ResponseDto cancelLike(@PathVariable Long postId, @Authentication return ResponseDto.response(ResponseMessage.LIKE_CANCEL_SUCCESS.getCode(), responseMessage); } + @PostMapping("/repost/{postId}") + @Operation(summary = "Repost 하기") + public ResponseDto repost(@PathVariable Long postId, @AuthenticationPrincipal String email) { + repostService.rePost(postId, email); + return ResponseDto.response(ResponseMessage.REPOST_SUCCESS.getCode(), ResponseMessage.REPOST_SUCCESS.getMessage()); + } + } diff --git a/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java b/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java index d32c59d..6c74090 100644 --- a/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java +++ b/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java @@ -15,7 +15,10 @@ public enum ResponseMessage { POST_DELETED_SUCCESS(200, "게시물이 성공적으로 삭제되었습니다."), LIKE_CANCEL_SUCCESS(200, "좋아요가 성공적으로 취소되었습니다."), REPLY_SUCCESS(201, "답글이 생성되었습니다."), - GET_ALL_PARENT_POSTS_SUCCESS(200, "모든 게시글 조회에 성공하였습니다."); + GET_ALL_PARENT_POSTS_SUCCESS(200, "모든 게시글 조회에 성공하였습니다."), + REPOST_SUCCESS(200, "리포스트에 성공했습니다."), + GET_USER_POST(200, "해당 유저의 게시글 조회에 성공했습니다."), + GET_FOLLOWING_POST(200, "팔로우 하는 게시글 조회에 성공했습니다."); private final int code; private final String message; diff --git a/src/main/java/com/leets/X/domain/post/domain/Repost.java b/src/main/java/com/leets/X/domain/post/domain/Repost.java new file mode 100644 index 0000000..f26d7e1 --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/domain/Repost.java @@ -0,0 +1,33 @@ +package com.leets.X.domain.post.domain; + +import com.leets.X.domain.user.domain.User; +import jakarta.persistence.*; +import lombok.*; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +@Getter +public class Repost { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "repost_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; + + public static Repost of(User user, Post post) { + return Repost.builder() + .user(user) + .post(post) + .build(); + } +} diff --git a/src/main/java/com/leets/X/domain/post/domain/enums/Type.java b/src/main/java/com/leets/X/domain/post/domain/enums/Type.java new file mode 100644 index 0000000..5232862 --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/domain/enums/Type.java @@ -0,0 +1,5 @@ +package com.leets.X.domain.post.domain.enums; + +public enum Type { + POST, REPOST +} diff --git a/src/main/java/com/leets/X/domain/post/dto/mapper/PostMapper.java b/src/main/java/com/leets/X/domain/post/dto/mapper/PostMapper.java new file mode 100644 index 0000000..8e553f1 --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/dto/mapper/PostMapper.java @@ -0,0 +1,87 @@ +package com.leets.X.domain.post.dto.mapper; + +import com.leets.X.domain.image.dto.response.ImageResponse; +import com.leets.X.domain.like.repository.LikeRepository; +import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.post.domain.enums.Type; +import com.leets.X.domain.post.dto.response.ParentPostResponseDto; +import com.leets.X.domain.post.dto.response.PostResponseDto; +import com.leets.X.domain.post.dto.response.PostUserResponse; +import com.leets.X.domain.user.domain.User; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class PostMapper { + + public PostResponseDto toPostResponseDto(Post post, User user, LikeRepository likeRepository, Type postType) { + return PostResponseDto.builder() + .id(post.getId()) + .content(post.getContent()) + .views(post.getViews()) + .isDeleted(post.getIsDeleted()) + .createdAt(post.getCreatedAt()) + .user(toPostUserResponse(post.getUser())) + .likeCount(post.getLikeCount()) + .isLikedByUser(isLikedByUser(post, user, likeRepository)) + .postType(postType) + .myPost(isMyPost(post, user)) +// .replyTo(getCustomId(post)) + .images(toImageResponse(post)) + .replies(toReplies(post.getReplies(), user, likeRepository, postType)) + .build(); + } + + public ParentPostResponseDto toParentPostResponseDto(Post post, User user, LikeRepository likeRepository, Type postType, Long repostingUserId) { + return ParentPostResponseDto.builder() + .id(post.getId()) + .content(post.getContent()) + .views(post.getViews()) + .isDeleted(post.getIsDeleted()) + .createdAt(post.getCreatedAt()) + .user(toPostUserResponse(post.getUser())) + .likeCount(post.getLikeCount()) + .isLikedByUser(isLikedByUser(post, user, likeRepository)) + .repostingUserId(repostingUserId) + .postType(postType) + .myPost(isMyPost(post, user)) +// .replyTo(getCustomId(post)) + .images(toImageResponse(post)) + .build(); + } + + public PostUserResponse toPostUserResponse(User user) { + return PostUserResponse.from(user); + } + + public List toImageResponse(Post post) { + return post.getImages().stream() + .map(ImageResponse::from) + .toList(); + } + + private List toReplies(List replies, User user, LikeRepository likeRepository, Type postType) { + return replies.stream() + .map(reply -> toPostResponseDto(reply, user, likeRepository, postType)) + .collect(Collectors.toList()); + + } + + private boolean isLikedByUser(Post post, User user, LikeRepository likeRepository) { + return likeRepository.existsByPostAndUser(post, user); + } + + private boolean isMyPost(Post post, User user) { + return post.getUser().equals(user); + } + + private String getCustomId(Post post) { + if(post.getParent() == null){ + return null; + } + return post.getParent().getUser().getCustomId(); + } + +} diff --git a/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java deleted file mode 100644 index 46d9266..0000000 --- a/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.leets.X.domain.post.dto.response; - -import com.leets.X.domain.image.domain.Image; - - -public record ImageResponseDto( - Long imageId, - String url -) { - public static ImageResponseDto from(Image image) { - return new ImageResponseDto(image.getId(), image.getUrl()); - } -} diff --git a/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java index 72761dd..37ac13d 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java @@ -1,14 +1,14 @@ package com.leets.X.domain.post.dto.response; -import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.image.dto.response.ImageResponse; import com.leets.X.domain.post.domain.enums.IsDeleted; -import com.leets.X.domain.user.domain.User; +import com.leets.X.domain.post.domain.enums.Type; +import lombok.Builder; import java.time.LocalDateTime; -import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; +@Builder public record ParentPostResponseDto( Long id, String content, @@ -17,30 +17,12 @@ public record ParentPostResponseDto( LocalDateTime createdAt, PostUserResponse user, Long likeCount, + Long repostingUserId, + Type postType, + Boolean myPost, Boolean isLikedByUser, - List images +// String replyTo, + List images ) { - public static ParentPostResponseDto from(Post post, boolean isLikedByUser) { - return new ParentPostResponseDto( - post.getId(), - post.getContent(), - post.getViews(), - post.getIsDeleted(), - post.getCreatedAt(), - convertUser(post.getUser()), // User 변환 - post.getLikesCount(), - isLikedByUser, // 좋아요 여부 설정 - convertImagesToDtoList(post) // Images 변환 - ); -} - - private static PostUserResponse convertUser(User user) { - return user != null ? PostUserResponse.from(user) : null; - } - private static List convertImagesToDtoList(Post post) { - return post.getImages() != null ? post.getImages().stream() - .map(ImageResponseDto::from) - .collect(Collectors.toList()) : Collections.emptyList(); - } } diff --git a/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java index 0aad551..45dea72 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java @@ -2,18 +2,14 @@ import com.leets.X.domain.image.dto.response.ImageResponse; -import com.leets.X.domain.like.repository.LikeRepository; -import com.leets.X.domain.post.domain.Post; import com.leets.X.domain.post.domain.enums.IsDeleted; -import com.leets.X.domain.user.domain.User; - +import com.leets.X.domain.post.domain.enums.Type; +import lombok.Builder; import java.time.LocalDateTime; -import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; - +@Builder public record PostResponseDto( Long id, String content, @@ -23,61 +19,13 @@ public record PostResponseDto( PostUserResponse user, Long likeCount, Boolean isLikedByUser, // 좋아요 여부 확인 + Type postType, + Boolean myPost, +// String replyTo, List images, List replies ) { - - public static PostResponseDto from(Post post, boolean isLikedByUser) { - return new PostResponseDto( - post.getId(), - post.getContent(), - post.getViews(), - post.getIsDeleted(), - post.getCreatedAt(), - convertUser(post.getUser()), - post.getLikesCount(), - isLikedByUser, // 서비스에서 전달된 boolean 값 사용 - convertImagesToDtoList(post), - convertRepliesToDtoList(post.getReplies()) - ); - } - - - // 좋아요 여부를 확인하기 위한 메서드 오버로딩 - public static PostResponseDto from(Post post, User user, LikeRepository likeRepository) { - boolean isLikedByUser = user != null && likeRepository.existsByPostAndUser(post, user); // 좋아요 여부 확인 - - return new PostResponseDto( - post.getId(), - post.getContent(), - post.getViews(), - post.getIsDeleted(), - post.getCreatedAt(), - convertUser(post.getUser()), - post.getLikesCount(), - isLikedByUser, // 좋아요 여부를 동적으로 설정 - convertImagesToDtoList(post), - convertRepliesToDtoList(post.getReplies()) - ); - } - - - private static List convertRepliesToDtoList(List replies) { - return replies != null ? replies.stream() - .map(reply -> PostResponseDto.from(reply, false)) // 기본적으로 isLikedByUser를 false로 설정 - .collect(Collectors.toList()) : Collections.emptyList(); - } - private static PostUserResponse convertUser(User user) { - return user != null ? PostUserResponse.from(user) : null; - } - - private static List convertImagesToDtoList(Post post) { - return post.getImages().stream() - .map(ImageResponse::from) - .toList(); - } - } diff --git a/src/main/java/com/leets/X/domain/post/exception/AlreadyRepostException.java b/src/main/java/com/leets/X/domain/post/exception/AlreadyRepostException.java new file mode 100644 index 0000000..e41077e --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/exception/AlreadyRepostException.java @@ -0,0 +1,16 @@ +package com.leets.X.domain.post.exception; + +import com.leets.X.global.common.exception.BaseException; + +import static com.leets.X.domain.post.exception.ErrorMessage.ALREADY_REPOST; + +public class AlreadyRepostException extends BaseException { + + public AlreadyRepostException() { + super(ALREADY_REPOST.getCode(), ALREADY_REPOST.getMessage()); + } + + + + +} diff --git a/src/main/java/com/leets/X/domain/post/exception/ErrorMessage.java b/src/main/java/com/leets/X/domain/post/exception/ErrorMessage.java index f70d6b5..fe57d0b 100644 --- a/src/main/java/com/leets/X/domain/post/exception/ErrorMessage.java +++ b/src/main/java/com/leets/X/domain/post/exception/ErrorMessage.java @@ -10,7 +10,8 @@ public enum ErrorMessage { POST_NOT_FOUND(404, "존재하지 않는 게시글입니다."), UNAUTHORIZED_POST_DELETION(403, "게시물을 삭제할 권한이 없습니다."), ALREADY_LIKED(400, "이미 좋아요를 누른 게시물입니다."), - NOT_LIKED(400, "좋아요가 눌려 있지 않은 게시물입니다."); + NOT_LIKED(400, "좋아요가 눌려 있지 않은 게시물입니다."), + ALREADY_REPOST(400, "이미 repost 한 게시물입니다."); private final int code; private final String message; diff --git a/src/main/java/com/leets/X/domain/post/repository/RepostRepository.java b/src/main/java/com/leets/X/domain/post/repository/RepostRepository.java new file mode 100644 index 0000000..d3ace8c --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/repository/RepostRepository.java @@ -0,0 +1,9 @@ +package com.leets.X.domain.post.repository; + +import com.leets.X.domain.post.domain.Repost; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RepostRepository extends JpaRepository { + boolean existsByUserIdAndPostId(Long userId, Long postId); + +} diff --git a/src/main/java/com/leets/X/domain/post/service/PostService.java b/src/main/java/com/leets/X/domain/post/service/PostService.java index 25f9fa4..1c8609d 100644 --- a/src/main/java/com/leets/X/domain/post/service/PostService.java +++ b/src/main/java/com/leets/X/domain/post/service/PostService.java @@ -6,6 +6,8 @@ import com.leets.X.domain.like.repository.LikeRepository; import com.leets.X.domain.post.domain.Post; import com.leets.X.domain.post.domain.enums.IsDeleted; +import com.leets.X.domain.post.domain.enums.Type; +import com.leets.X.domain.post.dto.mapper.PostMapper; import com.leets.X.domain.post.dto.request.PostRequestDTO; import com.leets.X.domain.post.dto.response.ParentPostResponseDto; import com.leets.X.domain.post.dto.response.PostResponseDto; @@ -24,7 +26,6 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -36,67 +37,71 @@ public class PostService { private final UserService userService; private final LikeRepository likeRepository; private final ImageService imageService; + private final PostMapper postMapper; - // 모든 부모 글만 조회 (자식 글 제외) + // 추천 게시글 조회. following 되지 않은 글만 반환 public List getAllParentPosts(String email) { User user = userService.find(email); + List followedUserIds = user.getFollowingList().stream() + .map(follow -> follow.getFollowed().getId()) + .toList(); + List posts = postRepository.findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted.ACTIVE); return posts.stream() + .filter(post -> !followedUserIds.contains(post.getUser().getId())) .map(post -> { - boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); - return ParentPostResponseDto.from(post, isLikedByUser); + return postMapper.toParentPostResponseDto(post, user, likeRepository, Type.POST, null); }) .collect(Collectors.toList()); } - // 전체 게시물 조회 (자식 글 포함) + // 상세조회 public PostResponseDto getPostResponse(Long id, String email) { Post post = postRepository.findWithRepliesByIdAndIsDeleted(id, IsDeleted.ACTIVE) .orElseThrow(PostNotFoundException::new); User user = userService.find(email); - boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); - return PostResponseDto.from(post, isLikedByUser); + return postMapper.toPostResponseDto(post, user, likeRepository, Type.POST); } - // 좋아요 순으로 게시물 조회 - public List getPostsSortedByLikes(String email) { - User user = userService.find(email); - List posts = postRepository.findAll(); - - return posts.stream() - .filter(post -> post.getIsDeleted() == IsDeleted.ACTIVE) - .sorted(Comparator.comparing(Post::getLikesCount).reversed()) - .map(post -> { - boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); - return PostResponseDto.from(post, isLikedByUser); - }) - .collect(Collectors.toList()); - } - - // 최신 부모 글 10개 조회 (자식 글 제외) - public List getLatestParentPosts(String email) { - User user = userService.find(email); - - List posts = postRepository.findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted.ACTIVE) - .stream() - .limit(10) - .collect(Collectors.toList()); - - return posts.stream() - .map(post -> { - boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); - return ParentPostResponseDto.from(post, isLikedByUser); - }) - .collect(Collectors.toList()); - } +// // 좋아요 순으로 게시물 조회 +// public List getPostsSortedByLikes(String email) { +// User user = userService.find(email); +// List posts = postRepository.findAll(); +// +// return posts.stream() +// .filter(post -> post.getIsDeleted() == IsDeleted.ACTIVE) +// .sorted(Comparator.comparing(Post::getLikesCount).reversed()) +// .map(post -> { +// boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); +// return PostResponseDto.from(post, isLikedByUser); +// }) +// .collect(Collectors.toList()); +// } +// +// // 최신 부모 글 10개 조회 (자식 글 제외) +// public List getLatestParentPosts(String email) { +// User user = userService.find(email); +// +// List posts = postRepository.findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted.ACTIVE) +// .stream() +// .limit(10) +// .collect(Collectors.toList()); +// +// return posts.stream() +// .map(post -> { +// boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); +// return ParentPostResponseDto.from(post, isLikedByUser); +// }) +// .collect(Collectors.toList()); +// } // 글 생성 @Transactional - public PostResponseDto createPost(PostRequestDTO postRequestDTO,List files, String email) throws IOException { + public void createPost(PostRequestDTO postRequestDTO,List files, String email) throws IOException { User user = userService.find(email); if (user == null) { throw new UserNotFoundException(); @@ -109,8 +114,6 @@ public PostResponseDto createPost(PostRequestDTO postRequestDTO,List images = imageService.save(files, savedPost); savedPost.addImage(images); } - - return PostResponseDto.from(savedPost, false); } // 좋아요 추가 @@ -131,7 +134,7 @@ public String addLike(Long postId, String email) { // 답글 생성 @Transactional - public PostResponseDto createReply(Long parentId, PostRequestDTO postRequestDTO, List files, String email) throws IOException { + public void createReply(Long parentId, PostRequestDTO postRequestDTO, List files, String email) throws IOException { User user = userService.find(email); Post parentPost = findPost(parentId); @@ -142,8 +145,6 @@ public PostResponseDto createReply(Long parentId, PostRequestDTO postRequestDTO, List images = imageService.save(files, savedReply); savedReply.addImage(images); } - - return PostResponseDto.from(savedReply, false); } // 게시물 삭제 @@ -194,4 +195,5 @@ public PostUserResponse findUser(String email) { return PostUserResponse.from(user); } + } diff --git a/src/main/java/com/leets/X/domain/post/service/RepostService.java b/src/main/java/com/leets/X/domain/post/service/RepostService.java new file mode 100644 index 0000000..e03e971 --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/service/RepostService.java @@ -0,0 +1,125 @@ +package com.leets.X.domain.post.service; + +import com.leets.X.domain.follow.domain.Follow; +import com.leets.X.domain.like.repository.LikeRepository; +import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.post.domain.Repost; +import com.leets.X.domain.post.domain.enums.Type; +import com.leets.X.domain.post.dto.mapper.PostMapper; +import com.leets.X.domain.post.dto.response.ParentPostResponseDto; +import com.leets.X.domain.post.exception.AlreadyRepostException; +import com.leets.X.domain.post.repository.PostRepository; +import com.leets.X.domain.post.repository.RepostRepository; +import com.leets.X.domain.user.domain.User; +import com.leets.X.domain.user.service.UserService; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class RepostService { + private final RepostRepository repostRepository; + private final PostRepository postRepository; + private final LikeRepository likeRepository; + private final PostService postService; + private final UserService userService; + private final PostMapper postMapper; + + @Transactional + public void rePost(Long postId, String email) { + User user = userService.find(email); + Post post = postService.findPost(postId); + + Repost repost = repostRepository.save(Repost.of(user, post)); + user.addRepost(repost); + } + + public List getFollowingPost(String email) { + User user = userService.find(email); + + // 자신의 게시물과 리포스트 가져오기 + List myPosts = getUserPosts(user, true); + List myReposts = getUserReposts(user, true); + + // 팔로잉한 사용자들의 게시물과 리포스트 가져오기 + List followingPosts = getFollowingUsersPosts(user); + List followingReposts = getFollowingUsersReposts(user); + + // 모든 게시물 합치고 정렬 + List allPosts = mergeAndSortPosts(myPosts, myReposts, followingPosts, followingReposts); + + return allPosts; + } + + public List getUserFeed(Long userId) { + User user = userService.find(userId); + + // 해당 사용자의 게시물과 리포스트 가져오기 + List userPosts = getUserPosts(user, false); + List userReposts = getUserReposts(user, false); + + // 모든 게시물 합치고 정렬 + List allPosts = mergeAndSortPosts(userPosts, userReposts); + + return allPosts; + } + + // 내 글을 리포스트 하는 것도 가능하기에 제거 + private void check(Long userId, Long postId){ + if(repostRepository.existsByUserIdAndPostId(userId, postId)) { + throw new AlreadyRepostException(); + } + } + + // 사용자의 게시물을 가져오는 메서드 + private List getUserPosts(User user, boolean isOwner) { + return user.getPosts().stream() + .filter(post -> post.getParent() == null) + .map(post -> postMapper.toParentPostResponseDto(post, user, likeRepository, Type.POST, null)) + .collect(Collectors.toList()); + } + + // 사용자의 리포스트를 가져오는 메서드 + private List getUserReposts(User user, boolean isOwner) { + return user.getReposts().stream() + .map(repost -> postMapper.toParentPostResponseDto(repost.getPost(), user, likeRepository, Type.REPOST, repost.getUser().getId())) + .collect(Collectors.toList()); + } + + // 팔로잉한 사용자들의 게시물을 가져오는 메서드 + private List getFollowingUsersPosts(User user) { + return user.getFollowingList().stream() + .map(Follow::getFollowed) + .flatMap(followedUser -> followedUser.getPosts().stream()) + .filter(post -> post.getParent() == null) + .map(post -> postMapper.toParentPostResponseDto(post, user, likeRepository, Type.POST, null)) + .collect(Collectors.toList()); + } + + // 팔로잉한 사용자들의 리포스트를 가져오는 메서드 + private List getFollowingUsersReposts(User user) { + return user.getFollowingList().stream() + .map(Follow::getFollowed) + .flatMap(followedUser -> followedUser.getReposts().stream()) + .map(repost -> postMapper.toParentPostResponseDto(repost.getPost(), user, likeRepository, Type.REPOST, repost.getUser().getId())) + .collect(Collectors.toList()); + } + + // 여러 리스트의 게시물을 합치고 정렬하는 메서드 + private List mergeAndSortPosts(List... postLists) { + List allPosts = new ArrayList<>(); + for (List posts : postLists) { + allPosts.addAll(posts); + } + return allPosts.stream() + .sorted(Comparator.comparing(ParentPostResponseDto::createdAt).reversed()) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/leets/X/domain/user/domain/User.java b/src/main/java/com/leets/X/domain/user/domain/User.java index 24e1f44..f819441 100644 --- a/src/main/java/com/leets/X/domain/user/domain/User.java +++ b/src/main/java/com/leets/X/domain/user/domain/User.java @@ -3,6 +3,7 @@ import com.leets.X.domain.follow.domain.Follow; import com.leets.X.domain.like.domain.Like; import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.post.domain.Repost; import com.leets.X.domain.user.dto.request.UserInitializeRequest; import com.leets.X.domain.user.dto.request.UserUpdateRequest; import com.leets.X.global.common.domain.BaseTimeEntity; @@ -65,6 +66,9 @@ public class User extends BaseTimeEntity { @OneToMany(mappedBy = "follower", cascade = CascadeType.REMOVE, orphanRemoval = true) private List followingList = new ArrayList<>(); + @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true) + private List reposts = new ArrayList<>(); + public void initProfile(UserInitializeRequest dto){ this.birth = dto.birth(); this.customId = dto.customId(); @@ -112,5 +116,8 @@ public void decreaseFollowingCount() { this.followingCount--; } } + public void addRepost(Repost repost) { + this.reposts.add(repost); + } }