Skip to content

Commit d0aa66e

Browse files
authored
[Feat] 가입한 그룹 목록 조회 API 개발 (#60)
* feat: 가입한 그룹 목록 조회 API 응답 DTO 구현 (#55) * feat: 가입한 그룹 목록 조회용 QueryDSL 리포지토리 구현 (#55) * feat: 가입한 그룹 목록 조회 서비스 구현 (#55) * feat: 가입한 그룹 목록 조회 API 컨트롤러 구현 (#55)
1 parent d9045ad commit d0aa66e

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

src/main/java/com/moa/moa_server/domain/group/repository/GroupMemberRepositoryCustom.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import com.moa.moa_server.domain.global.cursor.GroupNameGroupIdCursor;
44
import com.moa.moa_server.domain.group.entity.Group;
5+
import com.moa.moa_server.domain.group.entity.GroupMember;
56
import com.moa.moa_server.domain.user.entity.User;
67
import jakarta.annotation.Nullable;
78

89
import java.util.List;
910

1011
public interface GroupMemberRepositoryCustom {
1112
List<Group> findJoinedGroupLabels(User user, @Nullable GroupNameGroupIdCursor cursor, int size);
13+
List<GroupMember> findJoinedGroups(User user, @Nullable GroupNameGroupIdCursor cursor, int size);
1214
}

src/main/java/com/moa/moa_server/domain/group/repository/impl/GroupMemberRepositoryImpl.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.moa.moa_server.domain.global.cursor.GroupNameGroupIdCursor;
44
import com.moa.moa_server.domain.group.entity.Group;
5+
import com.moa.moa_server.domain.group.entity.GroupMember;
56
import com.moa.moa_server.domain.group.entity.QGroup;
67
import com.moa.moa_server.domain.group.entity.QGroupMember;
78
import com.moa.moa_server.domain.user.entity.User;
@@ -45,4 +46,31 @@ public List<Group> findJoinedGroupLabels(User user, @Nullable GroupNameGroupIdCu
4546
.limit(size)
4647
.fetch();
4748
}
48-
}
49+
50+
@Override
51+
public List<GroupMember> findJoinedGroups(User user, @Nullable GroupNameGroupIdCursor cursor, int size) {
52+
QGroupMember member = QGroupMember.groupMember;
53+
QGroup group = QGroup.group;
54+
55+
BooleanBuilder builder = new BooleanBuilder()
56+
.and(member.user.eq(user))
57+
.and(member.deletedAt.isNull())
58+
.and(group.id.ne(1L)); // 공개 그룹 제외
59+
60+
if (cursor != null) {
61+
builder.and(
62+
group.name.gt(cursor.groupName())
63+
.or(group.name.eq(cursor.groupName())
64+
.and(group.id.gt(cursor.groupId())))
65+
);
66+
}
67+
68+
return queryFactory
69+
.selectFrom(member)
70+
.join(member.group, group).fetchJoin()
71+
.where(builder)
72+
.orderBy(group.name.asc(), group.id.asc())
73+
.limit(size)
74+
.fetch();
75+
}
76+
}

src/main/java/com/moa/moa_server/domain/user/controller/UserController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.moa.moa_server.domain.global.dto.ApiResponse;
44
import com.moa.moa_server.domain.user.dto.response.GroupLabelResponse;
5+
import com.moa.moa_server.domain.user.dto.response.JoinedGroupResponse;
56
import com.moa.moa_server.domain.user.service.UserService;
67
import lombok.RequiredArgsConstructor;
78
import org.springframework.http.ResponseEntity;
@@ -27,4 +28,14 @@ public ResponseEntity<ApiResponse> getJoinedGroupLabels(
2728
GroupLabelResponse response = userService.getJoinedGroupLabels(userId, cursor, size);
2829
return ResponseEntity.ok(new ApiResponse("SUCCESS", response));
2930
}
31+
32+
@GetMapping("/groups")
33+
public ResponseEntity<ApiResponse> getJoinedGroups(
34+
@AuthenticationPrincipal Long userId,
35+
@RequestParam(required = false) String cursor,
36+
@RequestParam(required = false) Integer size
37+
) {
38+
JoinedGroupResponse response = userService.getJoinedGroups(userId, cursor, size);
39+
return ResponseEntity.ok(new ApiResponse("SUCCESS", response));
40+
}
3041
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.moa.moa_server.domain.user.dto.response;
2+
3+
import com.moa.moa_server.domain.group.entity.Group;
4+
import com.moa.moa_server.domain.group.entity.GroupMember;
5+
6+
public record GroupDetail(
7+
Long groupId,
8+
String name,
9+
String description,
10+
String imageUrl,
11+
String inviteCode,
12+
String role
13+
) {
14+
public static GroupDetail from(Group group, GroupMember.Role role) {
15+
return new GroupDetail(
16+
group.getId(),
17+
group.getName(),
18+
group.getDescription(),
19+
group.getImageUrl(),
20+
group.getInviteCode(),
21+
role.name()
22+
);
23+
}
24+
25+
public static GroupDetail from(GroupMember member) {
26+
return from(member.getGroup(), member.getRole());
27+
}
28+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.moa.moa_server.domain.user.dto.response;
2+
3+
import java.util.List;
4+
5+
public record JoinedGroupResponse(
6+
List<GroupDetail> groups,
7+
String nextCursor,
8+
boolean hasNext,
9+
int size
10+
) {}

src/main/java/com/moa/moa_server/domain/user/service/UserService.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import com.moa.moa_server.domain.global.cursor.GroupNameGroupIdCursor;
44
import com.moa.moa_server.domain.group.entity.Group;
5+
import com.moa.moa_server.domain.group.entity.GroupMember;
56
import com.moa.moa_server.domain.group.repository.GroupMemberRepository;
67
import com.moa.moa_server.domain.group.service.GroupService;
8+
import com.moa.moa_server.domain.user.dto.response.GroupDetail;
79
import com.moa.moa_server.domain.user.dto.response.GroupLabel;
810
import com.moa.moa_server.domain.user.dto.response.GroupLabelResponse;
11+
import com.moa.moa_server.domain.user.dto.response.JoinedGroupResponse;
912
import com.moa.moa_server.domain.user.entity.User;
1013
import com.moa.moa_server.domain.user.handler.UserErrorCode;
1114
import com.moa.moa_server.domain.user.handler.UserException;
@@ -62,4 +65,34 @@ public GroupLabelResponse getJoinedGroupLabels(Long userId, @Nullable String cur
6265

6366
return new GroupLabelResponse(labels, nextCursor, hasNext, labels.size());
6467
}
65-
}
68+
69+
@Transactional(readOnly = true)
70+
public JoinedGroupResponse getJoinedGroups(Long userId, @Nullable String cursor, @Nullable Integer size) {
71+
int pageSize = (size == null || size <= 0) ? DEFAULT_PAGE_SIZE : size;
72+
GroupNameGroupIdCursor parsedCursor = cursor != null ? GroupNameGroupIdCursor.parse(cursor) : null;
73+
74+
// 유저 조회 및 검증
75+
User user = userRepository.findById(userId)
76+
.orElseThrow(() -> new UserException(UserErrorCode.USER_NOT_FOUND));
77+
AuthUserValidator.validateActive(user);
78+
79+
// 그룹 멤버 목록 조회
80+
List<GroupMember> members = groupMemberRepository.findJoinedGroups(user, parsedCursor, pageSize + 1);
81+
82+
// 응답 구성
83+
boolean hasNext = members.size() > pageSize;
84+
if (hasNext) members = members.subList(0, pageSize);
85+
86+
String nextCursor = members.isEmpty() ? null :
87+
new GroupNameGroupIdCursor(
88+
members.getLast().getGroup().getName(),
89+
members.getLast().getGroup().getId()
90+
).encode();
91+
92+
List<GroupDetail> groups = members.stream()
93+
.map(GroupDetail::from)
94+
.toList();
95+
96+
return new JoinedGroupResponse(groups, nextCursor, hasNext, groups.size());
97+
}
98+
}

0 commit comments

Comments
 (0)