Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix: group members filtering and sorting #1802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 23, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ public interface GroupMemberService {

Mono<Boolean> bulkRemoveMember(String groupId, Collection<String> userIds);

Mono<List<GroupMember>> getGroupMembersByIdAndRole(String groupId, String role);

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public Mono<List<GroupMember>> getGroupMembers(String groupId) {
.collectList();
}

@Override
public Mono<List<GroupMember>> getGroupMembersByIdAndRole(String groupId, String role) {
return biRelationService.getBySourceIdAndRelation(GROUP_MEMBER, groupId, role)
.map(GroupMember::from)
.collectList();
}

@Override
public Mono<Boolean> addMember(String orgId, String groupId, String userId, MemberRole memberRole) {
return biRelationService.addBiRelation(GROUP_MEMBER, groupId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ public Mono<Boolean> updateState(BiRelationBizType bizType, String sourceId, Str

@Override
public Flux<BiRelation> getBySourceIdAndRelation(BiRelationBizType bizType, String sourceId, String relation) {
if (relation == null || relation.isBlank()) {
return biRelationRepository.findByBizTypeAndSourceId(bizType, sourceId);
}
Query query = new Query();
query.addCriteria(where(BIZ_TYPE).is(bizType));
query.addCriteria(where(SOURCE_ID).is(sourceId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
public interface GroupApiService {
Mono<GroupMemberAggregateView> getGroupMembers(String groupId, int page, int count);

Mono<GroupMemberAggregateView> getGroupMembersForSearch(String groupId, String search, String role, String sort, String order, Integer pageNum, Integer pageSize);

Mono<Boolean> addGroupMember(String groupId, String newUserId, String roleName);

Mono<Boolean> updateRoleForMember(String groupId, UpdateRoleRequest updateRoleRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,91 @@ public Mono<GroupMemberAggregateView> getGroupMembers(String groupId, int page,
});
}

@Override
public Mono<GroupMemberAggregateView> getGroupMembersForSearch(String groupId, String search, String role, String sort, String order, Integer pageNum, Integer pageSize) {
Mono<Tuple2<GroupMember, OrgMember>> groupAndOrgMemberInfo = getGroupAndOrgMemberInfo(groupId).cache();

Mono<MemberRole> visitorRoleMono = groupAndOrgMemberInfo.flatMap(tuple -> {
GroupMember groupMember = tuple.getT1();
OrgMember orgMember = tuple.getT2();
if (groupMember.isSuperAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(MemberRole.SUPER_ADMIN);
}
if (groupMember.isAdmin() || orgMember.isAdmin()) {
return Mono.just(MemberRole.ADMIN);
}
if (groupMember.isValid()) {
return Mono.just(MemberRole.MEMBER);
}
return ofError(BizError.NOT_AUTHORIZED, NOT_AUTHORIZED);
});

return groupAndOrgMemberInfo
.filter(this::hasReadPermission)
.switchIfEmpty(deferredError(BizError.NOT_AUTHORIZED, NOT_AUTHORIZED))
.flatMap(groupMember -> groupMemberService.getGroupMembersByIdAndRole(groupId, role))
.<Pair<List<GroupMemberView>, Integer>> flatMap(members -> {
if (members.isEmpty()) {
return Mono.just(Pair.of(emptyList(), 0));
}

List<String> userIds = collectList(members, GroupMember::getUserId);
Mono<Map<String, User>> userMapMono = userService.getByIds(userIds);
return userMapMono.map(map -> {
var list = members.stream()
.map(orgMember -> {
User user = map.get(orgMember.getUserId());
if (user == null) {
return null;
}
return new GroupMemberView(orgMember, user);
})
.filter(Objects::nonNull)
.filter(view -> {
if (search == null || search.isBlank()) return true;
return view.getUserName() != null &&
view.getUserName().toLowerCase().contains(search.toLowerCase());
})
.toList();
List<GroupMemberView> mutableList = new ArrayList<>(list);
if (sort != null && !sort.isBlank()) {
Comparator<GroupMemberView> comparator = null;
if ("userName".equalsIgnoreCase(sort)) {
comparator = Comparator.comparing(GroupMemberView::getUserName, Comparator.nullsLast(String::compareToIgnoreCase));
} else if ("role".equalsIgnoreCase(sort)) {
comparator = Comparator.comparing(GroupMemberView::getRole, Comparator.nullsLast(String::compareToIgnoreCase));
} else if ("joinTime".equalsIgnoreCase(sort)) {
comparator = Comparator.comparing(GroupMemberView::getJoinTime, Comparator.nullsLast(Long::compareTo));
}
if (comparator != null && "desc".equalsIgnoreCase(order)) {
comparator = comparator.reversed();
}
if (comparator != null) {
mutableList.sort(comparator);
}
}

int pageTotal = mutableList.size();
int fromIndex = Math.max(0, (pageNum - 1) * pageSize);
int toIndex = pageSize == 0 ? pageTotal : Math.min(pageNum * pageSize, pageTotal);
List<GroupMemberView> pagedList = fromIndex < toIndex ? mutableList.subList(fromIndex, toIndex) : emptyList();

return Pair.of(pagedList, pageTotal);
});
})
.zipWith(visitorRoleMono)
.map(tuple -> {
Pair<List<GroupMemberView>, Integer> t1 = tuple.getT1();
return GroupMemberAggregateView.builder()
.members(t1.getLeft())
.total(t1.getRight())
.pageNum(pageNum)
.pageSize(pageSize)
.visitorRole(tuple.getT2().getValue())
.build();
});
}

private boolean hasReadPermission(Tuple2<GroupMember, OrgMember> tuple) {
GroupMember groupMember = tuple.getT1();
OrgMember orgMember = tuple.getT2();
Expand Down Expand Up @@ -366,4 +451,5 @@ public Mono<OrgMemberListView> getPotentialGroupMembers(String groupId, String s
});
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,16 @@ public Mono<GroupListResponseView<List<GroupView>>> getOrgGroups(@RequestParam(r


@Override
public Mono<ResponseView<GroupMemberAggregateView>> getGroupMembers(@PathVariable String groupId,
@RequestParam(required = false, defaultValue = "1") int pageNum,
@RequestParam(required = false, defaultValue = "100") int pageSize) {
public Mono<ResponseView<GroupMemberAggregateView>> getGroupMembers(
@PathVariable String groupId,
@RequestParam(required = false) String search,
@RequestParam(required = false) String role,
@RequestParam(required = false) String sort,
@RequestParam(required = false) String order,
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
@RequestParam(required = false, defaultValue = "100") Integer pageSize) {
return gidService.convertGroupIdToObjectId(groupId).flatMap(objectId ->
groupApiService.getGroupMembers(objectId, pageNum, pageSize)
groupApiService.getGroupMembersForSearch(objectId, search, role, sort, order, pageNum, pageSize)
.map(ResponseView::success));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,20 @@ public Mono<GroupListResponseView<List<GroupView>>> getOrgGroups(@RequestParam(r

@Operation(
tags = TAG_GROUP_MEMBERS,
operationId = "listGroupMembers",
summary = "List User Group Members",
description = "Retrieve a list of Users / Members within a specific User Group in Lowcoder, showing the group's composition."
operationId = "listGroupMembersWithSearchAndSort",
summary = "List User Group Members with Search and Sort",
description = "Retrieve a paginated, searchable, and sortable list of Users / Members within a specific User Group in Lowcoder."
)
@GetMapping("/{groupId}/members")
public Mono<ResponseView<GroupMemberAggregateView>> getGroupMembers(@PathVariable String groupId,
@RequestParam(required = false, defaultValue = "1") int pageNum,
@RequestParam(required = false, defaultValue = "100") int pageSize);
@GetMapping("/{groupId}/members")
public Mono<ResponseView<GroupMemberAggregateView>> getGroupMembers(
@PathVariable String groupId,
@RequestParam(required = false) String search,
@RequestParam(required = false) String role,
@RequestParam(required = false) String sort,
@RequestParam(required = false) String order,
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
@RequestParam(required = false, defaultValue = "100") Integer pageSize
);

@Operation(
tags = TAG_GROUP_MEMBERS,
Expand Down
Loading