Skip to content

Commit bb0312d

Browse files
EpicFnEpicFn
andauthored
[Feat/OPS-376] 스페이스 목록 참여 인원 반환 api 구성 (#109)
* refactor : dto 이름 일부 변경 * feat : 구현 완료 * feat : 관련 테스트 케이스 추가 * fix : 테스트 케이스 수정 --------- Co-authored-by: EpicFn <[email protected]>
1 parent 7fb05c1 commit bb0312d

File tree

9 files changed

+107
-34
lines changed

9 files changed

+107
-34
lines changed

src/main/java/org/tuna/zoopzoop/backend/domain/space/membership/controller/ApiV1InviteController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.tuna.zoopzoop.backend.domain.space.membership.service.MembershipService;
1111
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceInviteList;
1212
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceSave;
13-
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfoWithoutAuthority;
13+
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceInfoWithoutAuthority;
1414
import org.tuna.zoopzoop.backend.domain.space.space.service.SpaceService;
1515
import org.tuna.zoopzoop.backend.global.rsData.RsData;
1616
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
@@ -81,8 +81,8 @@ public RsData<ResBodyForSpaceInviteList> getMyInvites(
8181

8282
// 멤버십(초대) 목록 조회
8383
List<Membership> invitations = membershipService.findByMember(member, "PENDING");
84-
List<SpaceMembershipInfoWithoutAuthority> invitationInfos = invitations.stream()
85-
.map(membership -> new SpaceMembershipInfoWithoutAuthority(
84+
List<SpaceInfoWithoutAuthority> invitationInfos = invitations.stream()
85+
.map(membership -> new SpaceInfoWithoutAuthority(
8686
membership.getSpace().getId(),
8787
membership.getSpace().getName(),
8888
membership.getSpace().getThumbnailUrl()

src/main/java/org/tuna/zoopzoop/backend/domain/space/space/controller/ApiV1SpaceController.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@
99
import org.springframework.data.domain.Sort;
1010
import org.springframework.data.web.PageableDefault;
1111
import org.springframework.security.core.annotation.AuthenticationPrincipal;
12-
import org.springframework.transaction.annotation.Transactional;
1312
import org.springframework.web.bind.annotation.*;
1413
import org.springframework.web.multipart.MultipartFile;
1514
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
15+
import org.tuna.zoopzoop.backend.domain.space.membership.dto.etc.SpaceMemberInfo;
1616
import org.tuna.zoopzoop.backend.domain.space.membership.entity.Membership;
1717
import org.tuna.zoopzoop.backend.domain.space.membership.enums.Authority;
1818
import org.tuna.zoopzoop.backend.domain.space.membership.enums.JoinState;
1919
import org.tuna.zoopzoop.backend.domain.space.membership.service.MembershipService;
2020
import org.tuna.zoopzoop.backend.domain.space.space.dto.req.ReqBodyForSpaceSave;
2121
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceInfo;
22-
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceList;
23-
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfo;
22+
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceInfo;
2423
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceListPage;
2524
import org.tuna.zoopzoop.backend.domain.space.space.dto.res.ResBodyForSpaceSave;
2625
import org.tuna.zoopzoop.backend.domain.space.space.entity.Space;
@@ -30,7 +29,6 @@
3029

3130
import java.nio.file.AccessDeniedException;
3231
import java.util.List;
33-
import java.util.Map;
3432
import java.util.stream.Collectors;
3533

3634
@RestController
@@ -131,6 +129,7 @@ public RsData<Void> updateSpaceThumbnail(
131129
public RsData<ResBodyForSpaceListPage> getAllSpaces(
132130
@AuthenticationPrincipal CustomUserDetails userDetails,
133131
@RequestParam(required = false) JoinState state,
132+
@RequestParam(defaultValue = "false") boolean includeMembers,
134133
@PageableDefault(size = 10, sort = "createDate", direction = Sort.Direction.DESC) Pageable pageable
135134
) {
136135
// 현재 로그인한 사용자 정보 가져오기
@@ -141,13 +140,32 @@ public RsData<ResBodyForSpaceListPage> getAllSpaces(
141140
Page<Membership> membershipsPage = membershipService.findByMember(member, stateStr, pageable);
142141

143142
// Page<Membership>를 Page<SpaceMembershipInfo>로 변환
144-
// Page 객체의 map() 메서드를 사용하면 페이징 정보는 그대로 유지하면서 내용물만 쉽게 바꿀 수 있습니다.
145-
Page<SpaceMembershipInfo> spaceInfosPage = membershipsPage.map(membership -> new SpaceMembershipInfo(
146-
membership.getSpace().getId(),
147-
membership.getSpace().getName(),
148-
membership.getSpace().getThumbnailUrl(),
149-
membership.getAuthority()
150-
));
143+
Page<SpaceInfo> spaceInfosPage = membershipsPage.map(membership -> {
144+
Space space = membership.getSpace();
145+
List<SpaceMemberInfo> memberInfos = null;
146+
147+
if (includeMembers) {
148+
// 스페이스에 속한 멤버 목록 조회 (가입 상태만)
149+
List<Membership> spaceMemberships = membershipService.findMembersBySpace(space);
150+
// 멤버 목록을 DTO로 변환
151+
memberInfos = spaceMemberships.stream()
152+
.map(spaceMembership -> new SpaceMemberInfo(
153+
spaceMembership.getMember().getId(),
154+
spaceMembership.getMember().getName(),
155+
spaceMembership.getMember().getProfileImageUrl(),
156+
spaceMembership.getAuthority()
157+
))
158+
.collect(Collectors.toList());
159+
}
160+
161+
return new SpaceInfo(
162+
space.getId(),
163+
space.getName(),
164+
space.getThumbnailUrl(),
165+
membership.getAuthority(),
166+
memberInfos // 조회된 멤버 목록 (null일 수도 있음)
167+
);
168+
});
151169

152170
// 새로운 응답 DTO 생성
153171
ResBodyForSpaceListPage resBody = new ResBodyForSpaceListPage(spaceInfosPage);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.tuna.zoopzoop.backend.domain.space.space.dto.etc;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import org.tuna.zoopzoop.backend.domain.space.membership.dto.etc.SpaceMemberInfo;
5+
import org.tuna.zoopzoop.backend.domain.space.membership.enums.Authority;
6+
7+
import java.util.List;
8+
9+
@JsonInclude(JsonInclude.Include.NON_NULL)
10+
public record SpaceInfo(
11+
Integer id,
12+
String name,
13+
String thumbnailUrl,
14+
Authority authority,
15+
List<SpaceMemberInfo> members
16+
) {
17+
public SpaceInfo(Integer id, String name, String thumbnailUrl, Authority authority) {
18+
this(id, name, thumbnailUrl, authority, null);
19+
}
20+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.tuna.zoopzoop.backend.domain.space.space.dto.etc;
22

3-
public record SpaceMembershipInfoWithoutAuthority(
3+
public record SpaceInfoWithoutAuthority(
44
Integer id,
55
String name,
66
String thumbnailUrl

src/main/java/org/tuna/zoopzoop/backend/domain/space/space/dto/etc/SpaceMembershipInfo.java

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.tuna.zoopzoop.backend.domain.space.space.dto.res;
22

3-
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfoWithoutAuthority;
3+
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceInfoWithoutAuthority;
44

55
import java.util.List;
66

77
public record ResBodyForSpaceInviteList(
8-
List<SpaceMembershipInfoWithoutAuthority> spaces
8+
List<SpaceInfoWithoutAuthority> spaces
99
) {
1010
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.tuna.zoopzoop.backend.domain.space.space.dto.res;
22

3-
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfo;
3+
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceInfo;
44

55
import java.util.List;
66

77
public record ResBodyForSpaceList(
8-
List<SpaceMembershipInfo> spaces
8+
List<SpaceInfo> spaces
99
) {
1010
}

src/main/java/org/tuna/zoopzoop/backend/domain/space/space/dto/res/ResBodyForSpaceListPage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
import lombok.Getter;
44
import org.springframework.data.domain.Page;
5-
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceMembershipInfo;
5+
import org.tuna.zoopzoop.backend.domain.space.space.dto.etc.SpaceInfo;
66

77
import java.util.List;
88

99
@Getter
1010
public class ResBodyForSpaceListPage {
11-
private final List<SpaceMembershipInfo> spaces; // 현재 페이지의 데이터
11+
private final List<SpaceInfo> spaces; // 현재 페이지의 데이터
1212
private final int page; // 현재 페이지 번호 (0부터 시작)
1313
private final int size; // 페이지 크기
1414
private final long totalElements; // 전체 요소 수
1515
private final int totalPages; // 전체 페이지 수
1616
private final boolean isLast; // 마지막 페이지 여부
1717

18-
public ResBodyForSpaceListPage(Page<SpaceMembershipInfo> page) {
18+
public ResBodyForSpaceListPage(Page<SpaceInfo> page) {
1919
this.spaces = page.getContent();
2020
this.page = page.getNumber();
2121
this.size = page.getSize();

src/test/java/org/tuna/zoopzoop/backend/domain/space/space/controller/ApiV1SpaceControllerTest.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.tuna.zoopzoop.backend.testSupport.ControllerTestSupport;
1919

2020
import static org.hamcrest.Matchers.nullValue;
21+
import static org.hamcrest.Matchers.startsWith;
2122
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
2223
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
2324
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -81,6 +82,12 @@ void setUpMembership() {
8182
spaceService.findByName("기존 스페이스 1_forSpaceControllerTest"),
8283
Authority.PENDING
8384
);
85+
// test3 -> 스페이스 1 가입 (READ_ONLY)
86+
membershipService.addMemberToSpace(
87+
memberService.findByKakaoKey("sc3333"),
88+
spaceService.findByName("기존 스페이스 1_forSpaceControllerTest"),
89+
Authority.READ_ONLY
90+
);
8491
// test1 -> 스페이스 2 가입 (PENDING)
8592
membershipService.addMemberToSpace(
8693
memberService.findByKakaoKey("sc1111"),
@@ -408,6 +415,45 @@ void getMySpaces_Success() throws Exception {
408415
.andExpect(jsonPath("$.data.spaces[1].thumbnailUrl").value("thumbnailUrl2"));
409416
}
410417

418+
@Test
419+
@WithUserDetails(value = "KAKAO:sc1111", setupBefore = TestExecutionEvent.TEST_METHOD)
420+
@DisplayName("나의 스페이스 전체 조회 (멤버 포함) - 성공")
421+
void getMySpaces_withMembers_Success() throws Exception {
422+
// Given
423+
String url = "/api/v1/space?includeMembers=true";
424+
425+
// When
426+
ResultActions resultActions = performGet(url);
427+
428+
// Then
429+
expectOk(
430+
resultActions,
431+
"스페이스 목록이 조회됐습니다."
432+
);
433+
resultActions
434+
.andExpect(jsonPath("$.data.spaces").isArray())
435+
.andExpect(jsonPath("$.data.spaces.length()").value(2));
436+
437+
// 첫 번째 스페이스 (기존 스페이스 1) 검증
438+
resultActions
439+
.andExpect(jsonPath("$.data.spaces[0].name").value("기존 스페이스 1_forSpaceControllerTest"))
440+
.andExpect(jsonPath("$.data.spaces[0].authority").value("ADMIN"))
441+
.andExpect(jsonPath("$.data.spaces[0].members").isArray())
442+
.andExpect(jsonPath("$.data.spaces[0].members.length()").value(2)) // PENDING 제외 2명
443+
.andExpect(jsonPath("$.data.spaces[0].members[0].name", startsWith("spaceControllerTester1")))
444+
.andExpect(jsonPath("$.data.spaces[0].members[0].authority").value("ADMIN"))
445+
.andExpect(jsonPath("$.data.spaces[0].members[1].name", startsWith("spaceControllerTester3")))
446+
.andExpect(jsonPath("$.data.spaces[0].members[1].authority").value("READ_ONLY"));
447+
448+
449+
// 두 번째 스페이스 (기존 스페이스 2) 검증
450+
resultActions
451+
.andExpect(jsonPath("$.data.spaces[1].name").value("기존 스페이스 2_forSpaceControllerTest"))
452+
.andExpect(jsonPath("$.data.spaces[1].authority").value("PENDING"))
453+
.andExpect(jsonPath("$.data.spaces[1].members").isArray())
454+
.andExpect(jsonPath("$.data.spaces[1].members.length()").value(0)); // 가입된 멤버 없음
455+
}
456+
411457
@Test
412458
@WithUserDetails(value = "KAKAO:sc1111", setupBefore = TestExecutionEvent.TEST_METHOD)
413459
@DisplayName("초대받은 스페이스 전체 조회 - 성공")
@@ -544,7 +590,7 @@ void getSpace_Fail_NotFound() throws Exception {
544590
@DisplayName("스페이스 단건 조회 - 실패 : 스페이스 멤버가 아닌 사용자")
545591
void getSpace_Fail_NotMember() throws Exception {
546592
// Given
547-
Space space = spaceService.findByName("기존 스페이스 1_forSpaceControllerTest");
593+
Space space = spaceService.findByName("기존 스페이스 2_forSpaceControllerTest");
548594
Integer spaceId = space.getId();
549595
String url = String.format("/api/v1/space/%d", spaceId);
550596

0 commit comments

Comments
 (0)