From 6b9f0961985277bcb107f3c7d5b66cc5192ad7b6 Mon Sep 17 00:00:00 2001 From: msk226 Date: Wed, 21 Jan 2026 12:30:37 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[Feature]=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=8B=9C,=20=ED=98=B8=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=97=AC=EB=B6=80=20=ED=95=A8=EA=BB=98=20=EC=9D=91=EB=8B=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/application/mapper/StudyDTOMapper.java | 12 +++--------- .../application/query/GetMyStudyInfoService.java | 12 ++++++++++-- .../jpa/associations/StudyMemberRepository.java | 4 ++++ .../query/dto/response/GetStudyOverviewResponse.java | 3 +++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/modules/study/src/main/java/kr/spot/study/application/mapper/StudyDTOMapper.java b/modules/study/src/main/java/kr/spot/study/application/mapper/StudyDTOMapper.java index 7094ddb8..f159424d 100644 --- a/modules/study/src/main/java/kr/spot/study/application/mapper/StudyDTOMapper.java +++ b/modules/study/src/main/java/kr/spot/study/application/mapper/StudyDTOMapper.java @@ -12,11 +12,13 @@ public class StudyDTOMapper { public static GetStudyOverviewResponse toDTO( List studies, Set likedStudyIds, + Set ownedStudyIds, boolean hasNext, Long nextCursor, Long totalElements ) { Set safelikedIds = likedStudyIds != null ? likedStudyIds : Collections.emptySet(); + Set safeOwnedStudyIds = ownedStudyIds != null ? ownedStudyIds : Collections.emptySet(); List list = studies.stream().map( study -> StudyOverview.of( @@ -27,6 +29,7 @@ public static GetStudyOverviewResponse toDTO( study.getCurrentMembers(), 0, safelikedIds.contains(study.getId()), + safeOwnedStudyIds.contains(study.getId()), 0, study.getImageUrl() ) @@ -34,13 +37,4 @@ public static GetStudyOverviewResponse toDTO( return GetStudyOverviewResponse.of(list, hasNext, nextCursor, totalElements); } - - public static GetStudyOverviewResponse toDTO( - List studies, - boolean hasNext, - Long nextCursor, - Long totalElements - ) { - return toDTO(studies, Collections.emptySet(), hasNext, nextCursor, totalElements); - } } diff --git a/modules/study/src/main/java/kr/spot/study/application/query/GetMyStudyInfoService.java b/modules/study/src/main/java/kr/spot/study/application/query/GetMyStudyInfoService.java index e0cb93bf..6dd68082 100644 --- a/modules/study/src/main/java/kr/spot/study/application/query/GetMyStudyInfoService.java +++ b/modules/study/src/main/java/kr/spot/study/application/query/GetMyStudyInfoService.java @@ -14,6 +14,7 @@ import kr.spot.study.domain.enums.SortBy; import kr.spot.study.domain.enums.StudyMemberStatus; import kr.spot.study.infrastructure.jpa.associations.StudyLikeRepository; +import kr.spot.study.infrastructure.jpa.associations.StudyMemberRepository; import kr.spot.study.infrastructure.jpa.querydsl.StudyQueryRepository; import kr.spot.study.presentation.query.dto.response.GetStudyOverviewResponse; import lombok.RequiredArgsConstructor; @@ -31,6 +32,7 @@ public class GetMyStudyInfoService { private final GetPreferredCategoryPort getPreferredCategoryPort; private final StudyQueryRepository studyQueryRepository; private final StudyLikeRepository studyLikeRepository; + private final StudyMemberRepository studyMemberRepository; public GetStudyOverviewResponse getMyStudyOverview( long viewerId, @@ -196,7 +198,10 @@ public GetStudyOverviewResponse getRecommendedStudies(long viewerId) { fillWithPopularStudies(result, recommendCount); Set likedStudyIds = studyLikeRepository.findStudyIdsByMemberId(viewerId); - return StudyDTOMapper.toDTO(result, likedStudyIds, false, null, (long) result.size()); + Set ownedStudyIds = studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus( + viewerId, StudyMemberStatus.OWNER); + return StudyDTOMapper.toDTO(result, likedStudyIds, ownedStudyIds, false, null, + (long) result.size()); } private List getPreferredCategories(long memberId) { @@ -240,7 +245,10 @@ private GetStudyOverviewResponse toCursorPage(List rows, long viewerId, i List pageContent = hasNext ? rows.subList(0, pageSize) : rows; Long nextCursor = hasNext ? pageContent.getLast().getId() : null; Set likedStudyIds = studyLikeRepository.findStudyIdsByMemberId(viewerId); - return StudyDTOMapper.toDTO(pageContent, likedStudyIds, hasNext, nextCursor, totalElements); + Set ownedStudyIds = studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus( + viewerId, StudyMemberStatus.OWNER); + return StudyDTOMapper.toDTO(pageContent, likedStudyIds, ownedStudyIds, hasNext, nextCursor, + totalElements); } private List filterPreferredRegionCodes(List regionCodes, diff --git a/modules/study/src/main/java/kr/spot/study/infrastructure/jpa/associations/StudyMemberRepository.java b/modules/study/src/main/java/kr/spot/study/infrastructure/jpa/associations/StudyMemberRepository.java index e33c9858..1d2d9af5 100644 --- a/modules/study/src/main/java/kr/spot/study/infrastructure/jpa/associations/StudyMemberRepository.java +++ b/modules/study/src/main/java/kr/spot/study/infrastructure/jpa/associations/StudyMemberRepository.java @@ -1,6 +1,7 @@ package kr.spot.study.infrastructure.jpa.associations; import java.util.List; +import java.util.Set; import kr.spot.code.status.ErrorStatus; import kr.spot.exception.GeneralException; import kr.spot.study.domain.associations.StudyMember; @@ -26,4 +27,7 @@ long countByMemberIdAndStudyMemberStatusIn(long memberId, long countByMemberIdAndStudyMemberStatus(long memberId, StudyMemberStatus studyMemberStatus); void deleteByMemberId(long memberId); + + Set findStudyIdsByMemberIdAndStudyMemberStatus(long memberId, + StudyMemberStatus studyMemberStatus); } diff --git a/modules/study/src/main/java/kr/spot/study/presentation/query/dto/response/GetStudyOverviewResponse.java b/modules/study/src/main/java/kr/spot/study/presentation/query/dto/response/GetStudyOverviewResponse.java index bc6d333f..ffa4b0cc 100644 --- a/modules/study/src/main/java/kr/spot/study/presentation/query/dto/response/GetStudyOverviewResponse.java +++ b/modules/study/src/main/java/kr/spot/study/presentation/query/dto/response/GetStudyOverviewResponse.java @@ -26,6 +26,7 @@ public record StudyOverview( int currentMembers, long likeCount, boolean isLiked, + boolean isOwner, long hitCount, String profileImageUrl ) { @@ -38,6 +39,7 @@ public static StudyOverview of( int currentMembers, long likeCount, boolean isLiked, + boolean isOwner, long hitCount, String profileImageUrl ) { @@ -49,6 +51,7 @@ public static StudyOverview of( currentMembers, likeCount, isLiked, + isOwner, hitCount, profileImageUrl ); From c65fe322f247f7178589b1a9c79916a2262e3ebe Mon Sep 17 00:00:00 2001 From: msk226 Date: Wed, 21 Jan 2026 12:34:24 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[Feature]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../query/GetMyStudyInfoServiceTest.java | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/modules/study/src/test/java/kr/spot/study/application/query/GetMyStudyInfoServiceTest.java b/modules/study/src/test/java/kr/spot/study/application/query/GetMyStudyInfoServiceTest.java index 33c437ba..23c4ce86 100644 --- a/modules/study/src/test/java/kr/spot/study/application/query/GetMyStudyInfoServiceTest.java +++ b/modules/study/src/test/java/kr/spot/study/application/query/GetMyStudyInfoServiceTest.java @@ -21,6 +21,7 @@ import kr.spot.study.domain.enums.SortBy; import kr.spot.study.domain.enums.StudyMemberStatus; import kr.spot.study.infrastructure.jpa.associations.StudyLikeRepository; +import kr.spot.study.infrastructure.jpa.associations.StudyMemberRepository; import kr.spot.study.infrastructure.jpa.querydsl.StudyQueryRepository; import kr.spot.study.presentation.query.dto.response.GetStudyOverviewResponse; import org.junit.jupiter.api.DisplayName; @@ -45,6 +46,8 @@ class GetMyStudyInfoServiceTest { private StudyQueryRepository studyQueryRepository; @Mock private StudyLikeRepository studyLikeRepository; + @Mock + private StudyMemberRepository studyMemberRepository; @Nested @DisplayName("내 스터디 목록 조회 (getMyStudyOverview)") @@ -67,6 +70,9 @@ void should_return_first_page_with_next_page() { (long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); + // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyStudyOverview(viewerId, List.of(status), @@ -92,7 +98,8 @@ void should_return_last_page() { given(studyQueryRepository.countMyStudies(viewerId, List.of(status))).willReturn( (long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); - + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyStudyOverview(viewerId, List.of(status), @@ -120,6 +127,8 @@ void should_return_next_page_with_cursor() { given(studyQueryRepository.countMyStudies(viewerId, List.of(status))).willReturn( (long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyStudyOverview(viewerId, @@ -147,6 +156,8 @@ void should_cap_page_size_at_max_page_size() { given(studyQueryRepository.countMyStudies(viewerId, List.of(status))).willReturn( (long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyStudyOverview(viewerId, @@ -184,6 +195,8 @@ void should_find_studies_in_all_preferred_regions_when_no_filter() { eq(preferredRegions))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyPreferredRegionStudies( @@ -219,6 +232,8 @@ void should_find_studies_in_filtered_preferred_regions() { eq(expectedRegions))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyPreferredRegionStudies( @@ -247,6 +262,8 @@ void should_return_empty_when_no_preferred_regions() { eq(Collections.emptyList()))) .willReturn(0L); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyPreferredRegionStudies( @@ -289,6 +306,8 @@ void should_find_studies_in_all_preferred_regions_when_no_filter() { eq(preferredCategory))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyPreferredCategoryStudies( @@ -320,6 +339,8 @@ void should_return_empty_when_no_preferred_regions() { eq(Collections.emptyList()))) .willReturn(0L); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getMyPreferredCategoryStudies( @@ -356,6 +377,8 @@ void should_not_fetch_popular_when_enough_preferred_studies() { given(studyQueryRepository.findRecruitingStudiesByCategories(preferredCategories, 20)) .willReturn(candidates); given(studyLikeRepository.findStudyIdsByMemberId(memberId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(memberId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecommendedStudies(memberId); @@ -384,6 +407,8 @@ void should_fill_with_popular_studies_when_not_enough_preferred() { List.of(preferredStudies.getFirst().getId()), 2)) .willReturn(popularStudies); given(studyLikeRepository.findStudyIdsByMemberId(memberId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(memberId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecommendedStudies(memberId); @@ -406,6 +431,8 @@ void should_return_popular_studies_when_no_preferred_categories() { given(studyQueryRepository.findPopularRecruitingStudies(Collections.emptyList(), 3)) .willReturn(popularStudies); given(studyLikeRepository.findStudyIdsByMemberId(memberId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(memberId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecommendedStudies(memberId); @@ -430,6 +457,8 @@ void should_return_empty_when_no_studies_at_all() { given(studyQueryRepository.findPopularRecruitingStudies(Collections.emptyList(), 3)) .willReturn(Collections.emptyList()); given(studyLikeRepository.findStudyIdsByMemberId(memberId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(memberId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecommendedStudies(memberId); @@ -464,6 +493,8 @@ void should_find_recruiting_studies_with_filters() { eq(FeeCategory.NONE), eq(List.of(Category.LANGUAGE)), eq(true))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecruitingStudies( @@ -491,6 +522,8 @@ void should_find_recruiting_studies_without_filters() { given(studyQueryRepository.countRecruitingStudies(eq(null), eq(null), eq(null))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecruitingStudies( @@ -515,6 +548,8 @@ void should_mark_liked_studies() { given(studyQueryRepository.countRecruitingStudies(any(), any(), any())) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of(likedStudyId)); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getRecruitingStudies( @@ -550,6 +585,8 @@ void should_find_studies_by_category() { eq(RecruitingStatus.RECRUITING), eq(FeeCategory.NONE), eq(Category.LANGUAGE), eq(false))) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getStudiesByCategory( @@ -576,6 +613,8 @@ void should_return_empty_when_no_studies() { given(studyQueryRepository.countStudiesByCategory(any(), any(), any(), any())) .willReturn(0L); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getStudiesByCategory( @@ -612,6 +651,8 @@ void should_find_liked_studies() { given(studyQueryRepository.countLikedStudies(viewerId)) .willReturn((long) studies.size()); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(likedStudyIds); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getLikedStudies(viewerId, null, @@ -634,6 +675,8 @@ void should_return_empty_when_no_liked_studies() { given(studyQueryRepository.countLikedStudies(viewerId)) .willReturn(0L); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getLikedStudies(viewerId, null, @@ -658,6 +701,8 @@ void should_find_next_page_with_cursor() { given(studyQueryRepository.countLikedStudies(viewerId)) .willReturn(15L); given(studyLikeRepository.findStudyIdsByMemberId(viewerId)).willReturn(Set.of()); + given(studyMemberRepository.findStudyIdsByMemberIdAndStudyMemberStatus(viewerId, + StudyMemberStatus.OWNER)).willReturn(Set.of()); // when GetStudyOverviewResponse response = getMyStudyInfoService.getLikedStudies(viewerId, cursor,