diff --git a/gateway/src/main/java/com/oing/controller/MainViewController.java b/gateway/src/main/java/com/oing/controller/MainViewController.java index ff8c998f..9d43bc59 100644 --- a/gateway/src/main/java/com/oing/controller/MainViewController.java +++ b/gateway/src/main/java/com/oing/controller/MainViewController.java @@ -183,9 +183,11 @@ public FamilyMemberMonthlyRankingResponse getFamilyMemberMonthlyRanking(String l } LocalDate mostRecentSurvivalPostDate = null; - List mostRecentPosts = postController.fetchDailyFeeds(1, 1, null, null, "desc", PostType.SURVIVAL, loginMemberId, false).results().stream().toList(); - if (!mostRecentPosts.isEmpty()) { - mostRecentSurvivalPostDate = mostRecentPosts.get(0).createdAt().toLocalDate(); + LocalDate startOfMonth = ZonedDateTime.now().withDayOfMonth(1).toLocalDate(); + LocalDate tomorrow = ZonedDateTime.now().plusDays(1).toLocalDate(); + PostResponse mostRecentPost = postController.findLatestPost(startOfMonth, tomorrow, PostType.SURVIVAL, loginFamilyId); + if (mostRecentPost != null) { + mostRecentSurvivalPostDate = mostRecentPost.createdAt().toLocalDate(); } return new FamilyMemberMonthlyRankingResponse( diff --git a/gateway/src/main/java/com/oing/repository/PostRepositoryCustomImpl.java b/gateway/src/main/java/com/oing/repository/PostRepositoryCustomImpl.java index f47101ae..9b2a5ba4 100644 --- a/gateway/src/main/java/com/oing/repository/PostRepositoryCustomImpl.java +++ b/gateway/src/main/java/com/oing/repository/PostRepositoryCustomImpl.java @@ -51,7 +51,19 @@ public List findLatestPostOfEveryday(LocalDateTime startDate, LocalDateTim )) .orderBy(post.createdAt.asc()) .fetch(); + } + @Override + public Post findLatestPost(LocalDateTime startDate, LocalDateTime endDate, PostType postType, String familyId) { + return queryFactory + .selectFrom(post) + .where( + post.type.eq(postType), + post.familyId.eq(familyId), + post.createdAt.between(startDate, endDate) + ) + .orderBy(post.createdAt.desc()) + .fetchFirst(); } @Override diff --git a/gateway/src/main/resources/db/migration/V202405092310__add_createdAt_idx_in_post_tbl.sql b/gateway/src/main/resources/db/migration/V202405092310__add_createdAt_idx_in_post_tbl.sql new file mode 100644 index 00000000..247a99c2 --- /dev/null +++ b/gateway/src/main/resources/db/migration/V202405092310__add_createdAt_idx_in_post_tbl.sql @@ -0,0 +1 @@ +ALTER TABLE post ADD INDEX post_idx2 (created_at); \ No newline at end of file diff --git a/gateway/src/test/java/com/oing/repository/PostRepositoryCustomTest.java b/gateway/src/test/java/com/oing/repository/PostRepositoryCustomTest.java index 923d98f9..30802c72 100644 --- a/gateway/src/test/java/com/oing/repository/PostRepositoryCustomTest.java +++ b/gateway/src/test/java/com/oing/repository/PostRepositoryCustomTest.java @@ -6,6 +6,7 @@ import com.oing.domain.Post; import com.oing.domain.PostType; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; @@ -18,6 +19,7 @@ import java.time.LocalDateTime; import java.util.List; +import static com.oing.domain.PostType.*; import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest @@ -112,6 +114,51 @@ void setup() { .containsExactly("2", "4"); } + @Nested + class findLatestPost { + @Test + void 생존신고_게시물_정상_조회_테스트() { + // given + String familyId = testMember1.getFamilyId(); + LocalDateTime inclusiveStart = LocalDate.of(2023, 11, 1).atStartOfDay(); + LocalDateTime exclusiveEnd = LocalDate.of(2023, 11, 2).atStartOfDay(); + + // when + Post post = postRepositoryCustomImpl.findLatestPost(inclusiveStart, exclusiveEnd, SURVIVAL, familyId); + + // then + assertThat(post.getId()).isEqualTo("2"); + } + + @Test + void 시작날짜는_포함하고_종료날짜는_포함하지_않는다() { + // given + String familyId = testMember1.getFamilyId(); + LocalDateTime inclusiveStart = LocalDate.of(2023, 11, 1).atStartOfDay(); + LocalDateTime exclusiveEnd = LocalDate.of(2023, 11, 1).atStartOfDay(); + + // when + Post post = postRepositoryCustomImpl.findLatestPost(inclusiveStart, exclusiveEnd, SURVIVAL, familyId); + + // then + assertThat(post).isNull(); + } + + @Test + void 해당_날짜에_게시글이_없는_경우_null을_반환한다() { + // given + String familyId = testMember1.getFamilyId(); + LocalDateTime inclusiveStart = LocalDate.of(9999, 11, 3).atStartOfDay(); + LocalDateTime exclusiveEnd = LocalDate.of(9999, 11, 4).atStartOfDay(); + + // when + Post post = postRepositoryCustomImpl.findLatestPost(inclusiveStart, exclusiveEnd, SURVIVAL, familyId); + + // then + assertThat(post).isNull(); + } + } + @Test void 특정_날짜에_게시글이_존재하는지_확인한다() { // given @@ -119,7 +166,7 @@ void setup() { // when boolean exists = postRepositoryCustomImpl.existsByMemberIdAndFamilyIdAndTypeAndCreatedAt(testMember1.getId(), - testMember1.getFamilyId(), PostType.SURVIVAL, postDate); + testMember1.getFamilyId(), SURVIVAL, postDate); // then assertThat(exists).isTrue(); @@ -132,7 +179,7 @@ void setup() { // when boolean exists = postRepositoryCustomImpl.existsByMemberIdAndFamilyIdAndTypeAndCreatedAt(testMember1.getId(), - testMember1.getFamilyId(), PostType.SURVIVAL, postDate); + testMember1.getFamilyId(), SURVIVAL, postDate); // then assertThat(exists).isFalse(); diff --git a/gateway/src/test/java/com/oing/restapi/MainViewApiTest.java b/gateway/src/test/java/com/oing/restapi/MainViewApiTest.java index 67be7526..0c462102 100644 --- a/gateway/src/test/java/com/oing/restapi/MainViewApiTest.java +++ b/gateway/src/test/java/com/oing/restapi/MainViewApiTest.java @@ -104,7 +104,7 @@ void setUp() { @Nested - class 금월의_가족구성원_월간_랭킹_조회 { + class getFamilyMemberMonthlyRanking { @Test void 정상_조회() throws Exception { // given diff --git a/post/src/main/java/com/oing/controller/PostController.java b/post/src/main/java/com/oing/controller/PostController.java index 8081b3ee..500f759f 100644 --- a/post/src/main/java/com/oing/controller/PostController.java +++ b/post/src/main/java/com/oing/controller/PostController.java @@ -97,6 +97,14 @@ public PostResponse getPost(String postId, String loginMemberId) { return PostResponse.from(memberPostProjection); } + @Override + public PostResponse findLatestPost(LocalDate inclusiveStartDate, LocalDate exclusiveEndDate, PostType postType, String loginFamilyId) { + Post latestPost = postService.findLatestPost(inclusiveStartDate, exclusiveEndDate, postType, loginFamilyId); + if (latestPost == null) return null; + + return PostResponse.from(latestPost); + } + @Override public SurvivalUploadStatusResponse getSurvivalUploadStatus(String memberId, String loginMemberId, String loginFamilyId) { validateMemberId(loginMemberId, memberId); diff --git a/post/src/main/java/com/oing/repository/PostRepositoryCustom.java b/post/src/main/java/com/oing/repository/PostRepositoryCustom.java index 64038258..8a912308 100644 --- a/post/src/main/java/com/oing/repository/PostRepositoryCustom.java +++ b/post/src/main/java/com/oing/repository/PostRepositoryCustom.java @@ -13,6 +13,8 @@ public interface PostRepositoryCustom { List findLatestPostOfEveryday(LocalDateTime startDate, LocalDateTime endDate, String familyId); + Post findLatestPost(LocalDateTime startDate, LocalDateTime endDate, PostType postType, String familyId); + QueryResults searchPosts(int page, int size, LocalDate date, String memberId, String requesterMemberId, String familyId, boolean asc, PostType type); diff --git a/post/src/main/java/com/oing/restapi/PostApi.java b/post/src/main/java/com/oing/restapi/PostApi.java index a951e737..feb2afc9 100644 --- a/post/src/main/java/com/oing/restapi/PostApi.java +++ b/post/src/main/java/com/oing/restapi/PostApi.java @@ -8,7 +8,6 @@ import com.oing.util.security.LoginMemberId; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; @@ -115,6 +114,27 @@ PostResponse getPost( String loginMemberId ); + @Operation(summary = "가장 최근 게시물 조회", description = "(결과가 없을시, null 반환)\n 특정 기간 안에서 가장 최근에 업로드된 게시물을 조회합니다.") + PostResponse findLatestPost( + @RequestParam + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + @Parameter(description = "조회 시작 날짜", example = "2023-12-05") + LocalDate inclusiveStartDate, + + @RequestParam + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + @Parameter(description = "조회 종료 날짜", example = "2023-12-05") + LocalDate exclusiveEndDate, + + @RequestParam + @Parameter(description = "게시물 타입", example = "SURVIVAL") + PostType type, + + @Parameter(hidden = true) + @LoginFamilyId + String loginFamilyId + ); + @Operation(summary = "회원 생존신고 게시글 업로드 여부 응답 조회", description = "회원 생존신고 게시글 업로드 여부를 조회합니다.") @GetMapping("/{memberId}/survival-uploaded") SurvivalUploadStatusResponse getSurvivalUploadStatus( diff --git a/post/src/main/java/com/oing/service/PostService.java b/post/src/main/java/com/oing/service/PostService.java index 2d7888c4..9b72330d 100644 --- a/post/src/main/java/com/oing/service/PostService.java +++ b/post/src/main/java/com/oing/service/PostService.java @@ -116,6 +116,10 @@ public Post getMemberPostById(String postId) { return postRepository.findById(postId).orElseThrow(PostNotFoundException::new); } + public Post findLatestPost(LocalDate inclusiveStartDate, LocalDate exclusiveEndDate, PostType postType, String loginFamilyId) { + return postRepository.findLatestPost(inclusiveStartDate.atStartOfDay(), exclusiveEndDate.atStartOfDay(), postType, loginFamilyId); + } + public PaginationDTO searchMemberPost(int page, int size, LocalDate date, String memberId, String requesterMemberId, String familyId, boolean asc, PostType type) { QueryResults results = null;