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
10 changes: 10 additions & 0 deletions src/main/java/com/codeit/todo/repository/CompleteRepository.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package com.codeit.todo.repository;

import com.codeit.todo.domain.Complete;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CompleteRepository extends JpaRepository<Complete, Integer> {
List<Complete> findByTodo_TodoId(int todoId);

@Query("select c from Complete c where c.todo.goal.user.userId in :userIds order by c.createdAt desc")
Slice<Complete> findByFollowees(@Param("userIds") List<Integer> userIds, Pageable pageable);

@Query("select c from Complete c where c.todo.goal.user.userId in :userIds and c.completeId > :completeId order by c.createdAt desc")
Slice<Complete> findByFolloweesAfterCompleteId(@Param("userIds")List<Integer> followeeIds, @Param("completeId") Integer completeId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface FollowRepository extends JpaRepository<Follow, Integer> {
@Query(
"SELECT COUNT(f) > 0 " +
Expand All @@ -24,5 +26,7 @@ public interface FollowRepository extends JpaRepository<Follow, Integer> {
int countByFollowee(@Param("userId") int userId);


@Query("select f.followee.userId from Follow f where f.follower.userId = :userId")
List<Integer> findFolloweeIdsByFollowerId(@Param("userId") int userId);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.codeit.todo.service.follow;

import com.codeit.todo.web.dto.request.follow.ReadFollowRequest;
import com.codeit.todo.web.dto.response.follow.ReadFollowResponse;
import org.springframework.data.domain.Slice;

public interface FollowService {
Slice<ReadFollowResponse> readFollows(int userId, ReadFollowRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.codeit.todo.service.follow.impl;

import com.codeit.todo.domain.Complete;
import com.codeit.todo.repository.CompleteRepository;
import com.codeit.todo.repository.FollowRepository;
import com.codeit.todo.repository.LikesRepository;
import com.codeit.todo.service.follow.FollowService;
import com.codeit.todo.web.dto.request.follow.ReadFollowRequest;
import com.codeit.todo.web.dto.response.follow.ReadFollowResponse;
import com.codeit.todo.web.dto.response.slice.CustomSlice;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Transactional
public class FollowServiceImpl implements FollowService {

private final FollowRepository followRepository;
private final CompleteRepository completeRepository;
private final LikesRepository likesRepository;

@Transactional(readOnly = true)
@Override
public Slice<ReadFollowResponse> readFollows(int userId, ReadFollowRequest request) {
List<Integer> followeeIds = followRepository.findFolloweeIdsByFollowerId(userId);

Pageable pageable = PageRequest.of(0, request.size());

Slice<Complete> completes;
if (Objects.isNull(request.lastCompleteId()) || request.lastCompleteId() <= 0) {
completes = completeRepository.findByFollowees(followeeIds, pageable);
} else {
completes = completeRepository.findByFolloweesAfterCompleteId(followeeIds, request.lastCompleteId(), pageable);
}

List<ReadFollowResponse> responses = completes.stream()
.map(complete -> {
Boolean likeStatus = likesRepository.existsByUser_UserIdAndComplete_CompleteId(userId, complete.getCompleteId());

return ReadFollowResponse.from(complete, likeStatus);
})
.toList();

Integer nextCursor = completes.hasNext()
? completes.getContent().get(completes.getContent().size() - 1).getCompleteId()
: null;

return new CustomSlice<>(responses, pageable, completes.hasNext(), nextCursor);
}
}
35 changes: 35 additions & 0 deletions src/main/java/com/codeit/todo/web/controller/FollowController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.codeit.todo.web.controller;

import com.codeit.todo.repository.CustomUserDetails;
import com.codeit.todo.service.follow.FollowService;
import com.codeit.todo.web.dto.request.follow.ReadFollowRequest;
import com.codeit.todo.web.dto.request.todo.ReadTodoCompleteWithGoalRequest;
import com.codeit.todo.web.dto.response.Response;
import com.codeit.todo.web.dto.response.follow.ReadFollowResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Slice;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/follows")
public class FollowController {

private final FollowService followService;


@GetMapping
public Response<Slice<ReadFollowResponse>> getFollows(
@AuthenticationPrincipal CustomUserDetails userDetails,
@Valid @ModelAttribute ReadFollowRequest request
) {

int userId = userDetails.getUserId();
return Response.ok(followService.readFollows(userId, request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.codeit.todo.web.dto.request.follow;

import jakarta.validation.constraints.Min;
import lombok.Builder;

@Builder
public record ReadFollowRequest(
Integer lastCompleteId,
@Min(1)
int size
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.codeit.todo.web.dto.response.follow;

import com.codeit.todo.domain.Complete;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record ReadFollowResponse(
int completeId,
String completePic,
LocalDateTime createdAt,
Boolean likeStatus,
int likeCount,
int commentCount
) {


public static ReadFollowResponse from(Complete complete, Boolean likeStatus) {
return ReadFollowResponse.builder()
.completeId(complete.getCompleteId())
.completePic(complete.getCompletePic())
.createdAt(complete.getCreatedAt())
.likeStatus(likeStatus)
.likeCount(complete.getLikes().size())
.commentCount(complete.getComments().size())
.build();
}
}
Loading