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
@@ -1,13 +1,15 @@
package com.example.feeda.domain.comment.repository;

import com.example.feeda.domain.comment.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;

import com.example.feeda.domain.post.entity.Post;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CommentRepository extends JpaRepository<Comment, Long> {

List<Comment> findByPostIdOrderByCreatedAtDesc(Long postId); // 최신순

List<Comment> findByPostIdOrderByCreatedAtAsc(Long postId);

Long countByPost(Post findPost);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
import com.example.feeda.security.jwt.JwtPayload;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Expand Down Expand Up @@ -46,17 +48,17 @@ public ResponseEntity<PostResponseDto> createPost(@RequestBody PostRequestDto re

@PostMapping("/{id}/likes")
public ResponseEntity<PostLikeResponseDTO> makeLikes(
@PathVariable Long id,
@AuthenticationPrincipal JwtPayload jwtPayload) {
@PathVariable Long id,
@AuthenticationPrincipal JwtPayload jwtPayload) {

Long profileId = jwtPayload.getProfileId();
return new ResponseEntity<>(postService.makeLikes(id, jwtPayload), HttpStatus.OK);
}

@DeleteMapping("/{id}/likes")
public ResponseEntity<Void> deleteLikes(
@PathVariable Long id,
@AuthenticationPrincipal JwtPayload jwtPayload
@PathVariable Long id,
@AuthenticationPrincipal JwtPayload jwtPayload
) {
Long profileId = jwtPayload.getProfileId();
postService.deleteLikes(id, profileId);
Expand All @@ -73,12 +75,15 @@ public ResponseEntity<PostResponseDto> findPostById(@PathVariable @NotNull Long
public ResponseEntity<Page<PostResponseDto>> findAllPost(
@RequestParam(defaultValue = "1") @Min(1) int page,
@RequestParam(defaultValue = "10") @Min(1) int size,
@RequestParam(defaultValue = "") String keyword
@RequestParam(defaultValue = "") String keyword,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startUpdatedAt,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endUpdatedAt
) {

Pageable pageable = PageRequest.of(page - 1, size, Sort.Direction.DESC, "updatedAt");

return new ResponseEntity<>(postService.findAll(pageable, keyword), HttpStatus.OK);
return new ResponseEntity<>(
postService.findAll(pageable, keyword, startUpdatedAt, endUpdatedAt), HttpStatus.OK);
}

@GetMapping("/followings")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
package com.example.feeda.domain.post.dto;

import com.example.feeda.domain.post.entity.Post;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;

import java.time.LocalDateTime;
import lombok.Getter;

@Getter
public class PostResponseDto {
Expand All @@ -22,21 +17,24 @@ public class PostResponseDto {

private final Long likes;

private final Long comments;

private final LocalDateTime createdAt;

private final LocalDateTime updatedAt;

public PostResponseDto(Post post, Long likes) {
public PostResponseDto(Post post, Long likes, Long comments) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.category = post.getCategory();
this.likes = likes;
this.comments = comments;
this.createdAt = post.getCreatedAt();
this.updatedAt = post.getUpdatedAt();
}

public static PostResponseDto toDto(Post post, Long likes) {
return new PostResponseDto(post, likes);
public static PostResponseDto toDto(Post post, Long likes, Long comments) {
return new PostResponseDto(post, likes, comments);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.feeda.domain.post.repository;

import com.example.feeda.domain.post.entity.Post;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -11,4 +12,8 @@ public interface PostRepository extends JpaRepository<Post, Long> {
Page<Post> findAllByTitleContaining(String title, Pageable pageable);

Page<Post> findAllByProfile_IdIn(List<Long> followingProfileIds, Pageable pageable);

Page<Post> findAllByTitleContainingAndUpdatedAtBetween(String title,
LocalDateTime startUpdatedAt, LocalDateTime endUpdatedAt,
Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.example.feeda.domain.post.dto.PostRequestDto;
import com.example.feeda.domain.post.dto.PostResponseDto;
import com.example.feeda.security.jwt.JwtPayload;
import java.time.LocalDate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Expand All @@ -14,7 +15,8 @@ PostResponseDto createPost(PostRequestDto postRequestDto,

PostResponseDto findPostById(Long id);

Page<PostResponseDto> findAll(Pageable pageable, String keyword);
Page<PostResponseDto> findAll(Pageable pageable, String keyword, LocalDate startUpdatedAt,
LocalDate endUpdatedAt);

Page<PostResponseDto> findFollowingAllPost(Pageable pageable, JwtPayload jwtPayload);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.feeda.domain.post.service;

import com.example.feeda.domain.comment.repository.CommentRepository;
import com.example.feeda.domain.follow.entity.Follows;
import com.example.feeda.domain.follow.repository.FollowsRepository;
import com.example.feeda.domain.post.dto.PostLikeResponseDTO;
Expand All @@ -12,10 +13,9 @@
import com.example.feeda.domain.profile.entity.Profile;
import com.example.feeda.domain.profile.repository.ProfileRepository;
import com.example.feeda.security.jwt.JwtPayload;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand All @@ -35,27 +35,30 @@ public class PostServiceImpl implements PostService {
private final ProfileRepository profileRepository; // 현재 로그인 사용자 정보를 찾기 위해 필요
private final FollowsRepository followsRepository;
private final PostLikeRepository postLikeRepository;
private final CommentRepository commentRepository;

@Override
public PostResponseDto createPost(PostRequestDto postRequestDto, JwtPayload jwtPayload) {

Profile profile = profileRepository.findById(jwtPayload.getProfileId())
.orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 프로필입니다."));
.orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 프로필입니다."));

Post post = new Post(postRequestDto.getTitle(), postRequestDto.getContent(),
postRequestDto.getCategory(), profile);
postRequestDto.getCategory(), profile);

Post savedPost = postRepository.save(post);

return new PostResponseDto(savedPost, 0L);
return new PostResponseDto(savedPost, 0L, 0L);
}

@Override
@Transactional
public PostLikeResponseDTO makeLikes(Long id, JwtPayload jwtPayload) {
Post post = postRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글이 존재하지 않습니다."));
Profile profile = profileRepository.findById(jwtPayload.getProfileId()).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "프로필이 존재하지 않습니다."));
Post post = postRepository.findById(id).orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글이 존재하지 않습니다."));
Profile profile = profileRepository.findById(jwtPayload.getProfileId()).orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "프로필이 존재하지 않습니다."));
;

// 중복 좋아요 방지
Expand All @@ -71,13 +74,15 @@ public PostLikeResponseDTO makeLikes(Long id, JwtPayload jwtPayload) {
@Override
public void deleteLikes(Long id, Long profileId) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글이 존재하지 않습니다."));
.orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "게시글이 존재하지 않습니다."));

Profile profile = profileRepository.findById(profileId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 프로필"));
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 프로필"));

PostLike postLike = postLikeRepository.findByPostAndProfile(post, profile)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "해당 사용자의 좋아요가 존재하지 않습니다."));
.orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "해당 사용자의 좋아요가 존재하지 않습니다."));

postLikeRepository.delete(postLike);
}
Expand All @@ -94,42 +99,60 @@ public PostResponseDto findPostById(Long id) {
Post findPost = optionalPost.get();

Long likeCount = postLikeRepository.countByPost(findPost);
Long commentCount = commentRepository.countByPost(findPost);

return new PostResponseDto(findPost, likeCount);
return new PostResponseDto(findPost, likeCount, commentCount);
}

@Override
@Transactional(readOnly = true)
public Page<PostResponseDto> findAll(Pageable pageable, String keyword) {
public Page<PostResponseDto> findAll(Pageable pageable, String keyword,
LocalDate startUpdatedAt, LocalDate endUpdatedAt) {

if ((startUpdatedAt == null && endUpdatedAt != null) || (startUpdatedAt != null
&& endUpdatedAt == null)) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"startUpdatedAt과 endUpdatedAt은 둘 다 있어야 하거나 둘 다 없어야 합니다.");
}

if (startUpdatedAt != null) {
return postRepository.findAllByTitleContainingAndUpdatedAtBetween(
keyword, startUpdatedAt.atStartOfDay(), endUpdatedAt.atTime(23, 59, 59), pageable)
.map(post -> PostResponseDto.toDto(post, postLikeRepository.countByPost(post),
commentRepository.countByPost(post)));
}

return postRepository.findAllByTitleContaining(keyword, pageable)
.map(post -> PostResponseDto.toDto(post, postLikeRepository.countByPost(post)));
.map(post -> PostResponseDto.toDto(post, postLikeRepository.countByPost(post),
commentRepository.countByPost(post)));
}

@Override
@Transactional(readOnly = true)
public Page<PostResponseDto> findFollowingAllPost(Pageable pageable, JwtPayload jwtPayload) {

Page<Follows> followings = followsRepository.findAllByFollowers_Id(
jwtPayload.getProfileId(), pageable);
jwtPayload.getProfileId(), pageable);

List<Long> followingProfileIds = followings.stream()
.map(following -> following.getFollowings().getId())
.toList();
.map(following -> following.getFollowings().getId())
.toList();

Pageable newPageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(),
Sort.Direction.DESC, "updatedAt");
Sort.Direction.DESC, "updatedAt");

return postRepository.findAllByProfile_IdIn(followingProfileIds, newPageable)
.map(post -> PostResponseDto.toDto(post, postLikeRepository.countByPost(post)));
.map(post -> PostResponseDto.toDto(post, postLikeRepository.countByPost(post),
commentRepository.countByPost(post)));
}

@Override
@Transactional
public PostResponseDto updatePost(Long id, PostRequestDto requestDto, JwtPayload jwtPayload) {

Post findPost = postRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 게시글"));
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 게시글"));

if (!findPost.getProfile().getId().equals(jwtPayload.getProfileId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "권한이 없습니다.");
Expand All @@ -139,16 +162,17 @@ public PostResponseDto updatePost(Long id, PostRequestDto requestDto, JwtPayload
Post savedPost = postRepository.save(findPost);

Long likeCount = postLikeRepository.countByPost(findPost);
Long commentCount = commentRepository.countByPost(findPost);

return new PostResponseDto(savedPost, likeCount);
return new PostResponseDto(savedPost, likeCount, commentCount);
}

@Override
@Transactional
public void deletePost(Long id, JwtPayload jwtPayload) {

Post findPost = postRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 게시글"));
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 게시글"));

if (!findPost.getProfile().getId().equals(jwtPayload.getProfileId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "권한이 없습니다.");
Expand Down