From 247a89935ea95f300108c852809d5cb20dc3ee36 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 20 Jun 2025 18:22:31 -0400 Subject: [PATCH] Get users who do not belong to this group among the members of the organization. Removed "/{orgId}/{searchMemberName}/{searchGroupId}/members" endpoint. --- .../user/repository/UserRepository.java | 9 +++ .../domain/user/service/UserService.java | 10 +-- .../domain/user/service/UserServiceImpl.java | 10 +++ .../api/usermanagement/GroupApiService.java | 3 + .../usermanagement/GroupApiServiceImpl.java | 77 ++++++++++++++++--- .../api/usermanagement/GroupController.java | 17 +++- .../api/usermanagement/GroupEndpoints.java | 15 ++++ .../api/usermanagement/OrgApiService.java | 2 - .../api/usermanagement/OrgApiServiceImpl.java | 72 ----------------- .../OrganizationController.java | 10 --- .../usermanagement/OrganizationEndpoints.java | 7 -- 11 files changed, 121 insertions(+), 111 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/repository/UserRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/repository/UserRepository.java index 9536f52e78..896c278cd7 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/repository/UserRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/repository/UserRepository.java @@ -1,13 +1,16 @@ package org.lowcoder.domain.user.repository; import java.util.Collection; +import java.util.List; import org.lowcoder.domain.user.model.User; +import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.data.mongodb.repository.Query; @Repository public interface UserRepository extends ReactiveMongoRepository { @@ -23,4 +26,10 @@ public interface UserRepository extends ReactiveMongoRepository { //email1 and email2 should be equal Flux findByEmailOrConnections_Email(String email1, String email2); + + @Query("{ '_id': { $in: ?0 }, 'state': ?1, 'isEnabled': ?2, $or: [ { 'name': { $regex: ?3, $options: 'i' } }, { '_id': { $regex: ?3, $options: 'i' } } ] }") + Flux findUsersByIdsAndSearchNameForPagination(Collection ids, String state, boolean isEnabled, String searchRegex, Pageable pageable); + + @Query(value = "{ '_id': { $in: ?0 }, 'state': ?1, 'isEnabled': ?2, $or: [ { 'name': { $regex: ?3, $options: 'i' } }, { '_id': { $regex: ?3, $options: 'i' } } ] }", count = true) + Mono countUsersByIdsAndSearchName(Collection ids, String state, boolean isEnabled, String searchRegex); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java index 52a1ba05c5..e5057ab51a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java @@ -3,12 +3,10 @@ import java.util.Collection; import java.util.Map; -import org.lowcoder.domain.user.model.AuthUser; -import org.lowcoder.domain.user.model.Connection; -import org.lowcoder.domain.user.model.User; -import org.lowcoder.domain.user.model.UserDetail; +import org.lowcoder.domain.user.model.*; import org.lowcoder.infra.annotation.NonEmptyMono; import org.lowcoder.infra.mongo.MongoUpsertHelper.PartialResourceWithId; +import org.springframework.data.domain.Pageable; import org.springframework.http.codec.multipart.Part; import org.springframework.web.server.ServerWebExchange; @@ -68,5 +66,7 @@ public interface UserService { Flux findBySourceAndIds(String connectionSource, Collection connectionSourceUuids); -} + Flux findUsersByIdsAndSearchNameForPagination(Collection ids, String state, boolean isEnabled, String searchRegex, Pageable pageable); + Mono countUsersByIdsAndSearchName(Collection ids, String state, boolean isEnabled, String searchRegex); +} \ No newline at end of file diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java index 1a8dcf566e..1df76dfccf 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java @@ -36,6 +36,7 @@ import org.lowcoder.sdk.util.HashUtils; import org.lowcoder.sdk.util.LocaleUtils; import org.springframework.dao.DuplicateKeyException; +import org.springframework.data.domain.Pageable; import org.springframework.http.codec.multipart.Part; import org.springframework.stereotype.Service; import org.springframework.web.server.ServerWebExchange; @@ -473,4 +474,13 @@ public Flux findBySourceAndIds(String connectionSource, Collection return repository.findByConnections_SourceAndConnections_RawIdIn(connectionSource, connectionSourceUuids); } + @Override + public Flux findUsersByIdsAndSearchNameForPagination(Collection ids, String state, boolean isEnabled, String searchRegex, Pageable pageable) { + return repository.findUsersByIdsAndSearchNameForPagination(ids, state, isEnabled, searchRegex, pageable); + } + + @Override + public Mono countUsersByIdsAndSearchName(Collection ids, String state, boolean isEnabled, String searchRegex) { + return repository.countUsersByIdsAndSearchName(ids, state, isEnabled, searchRegex); + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java index 549d2105e7..e227e5d117 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java @@ -1,6 +1,7 @@ package org.lowcoder.api.usermanagement; import org.lowcoder.api.usermanagement.view.*; +import org.lowcoder.api.usermanagement.view.OrgMemberListView; import org.lowcoder.domain.group.model.Group; import reactor.core.publisher.Mono; @@ -24,4 +25,6 @@ public interface GroupApiService { Mono update(String groupId, UpdateGroupRequest updateGroupRequest); Mono removeUser(String groupId, String userId); + + Mono getPotentialGroupMembers(String groupId, String searchName, Integer pageNum, Integer pageSize); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiServiceImpl.java index 55b5f2adb1..3dbd8b6dd1 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiServiceImpl.java @@ -9,9 +9,8 @@ import static org.lowcoder.sdk.util.StreamUtils.collectList; import static org.lowcoder.sdk.util.StreamUtils.collectMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.regex.Pattern; import java.util.stream.Collectors; import com.github.f4b6a3.uuid.UuidCreator; @@ -19,24 +18,22 @@ import org.apache.commons.lang3.tuple.Pair; import org.lowcoder.api.bizthreshold.AbstractBizThresholdChecker; import org.lowcoder.api.home.SessionUserService; -import org.lowcoder.api.usermanagement.view.CreateGroupRequest; -import org.lowcoder.api.usermanagement.view.GroupMemberAggregateView; -import org.lowcoder.api.usermanagement.view.GroupMemberView; -import org.lowcoder.api.usermanagement.view.GroupView; -import org.lowcoder.api.usermanagement.view.UpdateGroupRequest; -import org.lowcoder.api.usermanagement.view.UpdateRoleRequest; +import org.lowcoder.api.usermanagement.view.*; import org.lowcoder.domain.group.model.Group; import org.lowcoder.domain.group.model.GroupMember; +import org.lowcoder.domain.user.model.UserState; +import org.lowcoder.api.usermanagement.view.OrgMemberListView; import org.lowcoder.domain.group.service.GroupMemberService; import org.lowcoder.domain.group.service.GroupService; import org.lowcoder.domain.organization.model.MemberRole; import org.lowcoder.domain.organization.model.OrgMember; import org.lowcoder.domain.organization.service.OrgMemberService; -import org.lowcoder.domain.organization.service.OrganizationService; import org.lowcoder.domain.user.model.User; import org.lowcoder.domain.user.service.UserService; import org.lowcoder.infra.util.TupleUtils; import org.lowcoder.sdk.exception.BizError; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; @@ -53,7 +50,6 @@ public class GroupApiServiceImpl implements GroupApiService { private final UserService userService; private final GroupService groupService; private final AbstractBizThresholdChecker bizThresholdChecker; - private final OrganizationService organizationService; private final OrgMemberService orgMemberService; @Override @@ -311,4 +307,63 @@ public Mono removeUser(String groupId, String userId) { return groupMemberService.removeMember(groupId, userId); }); } + + @Override + public Mono getPotentialGroupMembers(String groupId, String searchName, Integer pageNum, Integer pageSize) { + return groupService.getById(groupId) + .flatMap(group -> { + String orgId = group.getOrganizationId(); + Mono> orgMemberUserIdsMono = orgMemberService.getOrganizationMembers(orgId).collectList(); + Mono> groupMemberUserIdsMono = groupMemberService.getGroupMembers(groupId); + + return Mono.zip(orgMemberUserIdsMono, groupMemberUserIdsMono) + .flatMap(tuple -> { + List orgMembers = tuple.getT1(); + List groupMembers = tuple.getT2(); + + Set groupMemberUserIds = groupMembers.stream() + .map(GroupMember::getUserId) + .collect(Collectors.toSet()); + + Collection potentialUserIds = orgMembers.stream() + .map(OrgMember::getUserId) + .filter(uid -> !groupMemberUserIds.contains(uid)) + .collect(Collectors.toList()); + + if (potentialUserIds.isEmpty()) { + return Mono.just(OrgMemberListView.builder() + .members(List.of()) + .total(0) + .pageNum(pageNum) + .pageSize(pageSize) + .build()); + } + + Pageable pageable = PageRequest.of(pageNum - 1, pageSize); + String searchRegex = searchName != null && !searchName.isBlank() ? ".*" + Pattern.quote(searchName) + ".*" : ".*"; + + return userService.findUsersByIdsAndSearchNameForPagination( + potentialUserIds, String.valueOf(UserState.ACTIVATED), true, searchRegex, pageable) + .collectList() + .zipWith(userService.countUsersByIdsAndSearchName( + potentialUserIds, String.valueOf(UserState.ACTIVATED), true, searchRegex)) + .map(tupleUser -> { + List users = tupleUser.getT1(); + long total = tupleUser.getT2(); + List memberViews = users.stream() + .map(u -> OrgMemberListView.OrgMemberView.builder() + .userId(u.getId()) + .name(u.getName()) + .build()) + .collect(Collectors.toList()); + return OrgMemberListView.builder() + .members(memberViews) + .total((int) total) + .pageNum(pageNum) + .pageSize(pageSize) + .build(); + }); + }); + }); + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java index 110a838378..992bba1fe0 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java @@ -20,10 +20,8 @@ import org.lowcoder.domain.organization.service.OrgMemberService; import org.lowcoder.sdk.exception.BizError; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.lowcoder.api.usermanagement.view.OrgMemberListView; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; @@ -180,4 +178,15 @@ public Mono> removeUser(@PathVariable String groupId, .map(Tuple2::getT2) .map(ResponseView::success)); } + + @Override + public Mono> searchPotentialGroupMembers( + @PathVariable String groupId, + @RequestParam(required = false) String searchName, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, + @RequestParam(required = false, defaultValue = "1000") Integer pageSize) { + return gidService.convertGroupIdToObjectId(groupId).flatMap(id -> + groupApiService.getPotentialGroupMembers(id, searchName, pageNum, pageSize) + .map(ResponseView::success)); + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java index 89e294628d..3a4b90d567 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java @@ -115,4 +115,19 @@ public Mono> updateRoleForMember(@RequestBody UpdateRoleRe @DeleteMapping("/{groupId}/remove") public Mono> removeUser(@PathVariable String groupId, @RequestParam String userId); + + @Operation( + tags = TAG_GROUP_MEMBERS, + operationId = "searchPotentialGroupMembers", + summary = "Search Potential Group Members", + description = "Retrieve a list of users who are not currently members of the specified group within an organization." + ) + + @GetMapping("/{groupId}/potential-members") + public Mono> searchPotentialGroupMembers( + @PathVariable String groupId, + @RequestParam(required = false) String searchName, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, + @RequestParam(required = false, defaultValue = "1000") Integer pageSize + ); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java index c87732d35c..2901aeb0dc 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java @@ -53,7 +53,5 @@ public interface OrgApiService { Mono getOrganizationConfigs(String orgId); Mono getApiUsageCount(String orgId, Boolean lastMonthOnly); - - Mono getOrganizationMembersForSearch(String orgId, String searchMemberName, String searchGroupId, Integer pageNum, Integer pageSize); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java index 2a5b0d0c30..2d2b6cd2d5 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java @@ -90,78 +90,6 @@ public Mono getOrganizationMembers(String orgId, int page, in .then(getOrgMemberListView(orgId, page, count)); } -// Update getOrgMemberListViewForSearch to filter by group membership -private Mono getOrgMemberListViewForSearch(String orgId, String searchMemberName, String searchGroupId, Integer page, Integer pageSize) { - return orgMemberService.getOrganizationMembers(orgId) - .collectList() - .flatMap(orgMembers -> { - List userIds = orgMembers.stream() - .map(OrgMember::getUserId) - .collect(Collectors.toList()); - Mono> users = userService.getByIds(userIds); - - // If searchGroupId is provided, fetch group members - Mono> groupUserIdsMono = StringUtils.isBlank(searchGroupId) - ? Mono.just(Collections.emptySet()) - : groupMemberService.getGroupMembers(searchGroupId) - .map(list -> list.stream() - .map(GroupMember::getUserId) - .collect(Collectors.toSet())); - - return Mono.zip(users, groupUserIdsMono) - .map(tuple -> { - Map userMap = tuple.getT1(); - Set groupUserIds = tuple.getT2(); - - var list = orgMembers.stream() - .map(orgMember -> { - User user = userMap.get(orgMember.getUserId()); - if (user == null) { - log.warn("user {} not exist and will be removed from the result.", orgMember.getUserId()); - return null; - } - return buildOrgMemberView(user, orgMember); - }) - .filter(Objects::nonNull) - .filter(orgMemberView -> { - // Filter by name - boolean matchesName = StringUtils.isBlank(searchMemberName) || - StringUtils.containsIgnoreCase(orgMemberView.getName(), searchMemberName); - - // Filter by group - boolean matchesGroup = StringUtils.isBlank(searchGroupId) || - groupUserIds.contains(orgMemberView.getUserId()); - - return matchesName && matchesGroup; - }) - .collect(Collectors.toList()); - var pageTotal = list.size(); - list = list.subList((page - 1) * pageSize, pageSize == 0 ? pageTotal : Math.min(page * pageSize, pageTotal)); - return Pair.of(list, pageTotal); - }); - }) - .zipWith(sessionUserService.getVisitorOrgMemberCache()) - .map(tuple -> { - List memberViews = tuple.getT1().getLeft(); - var pageTotal = tuple.getT1().getRight(); - OrgMember orgMember = tuple.getT2(); - return OrgMemberListView.builder() - .members(memberViews) - .total(pageTotal) - .pageNum(page) - .pageSize(pageSize) - .visitorRole(orgMember.getRole().getValue()) - .build(); - }); - } - @Override - public Mono getOrganizationMembersForSearch(String orgId, String searchMemberName, String searchGroupId, Integer page, Integer pageSize) { - return sessionUserService.getVisitorId() - .flatMap(visitorId -> orgMemberService.getOrgMember(orgId, visitorId)) - .switchIfEmpty(deferredError(BizError.NOT_AUTHORIZED, "NOT_AUTHORIZED")) - .then(getOrgMemberListViewForSearch(orgId, searchMemberName, searchGroupId, page, pageSize)); - } - private Mono getOrgMemberListView(String orgId, int page, int count) { return orgMemberService.getOrganizationMembers(orgId) .collectList() diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java index f73758127d..15637f364b 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java @@ -118,16 +118,6 @@ public Mono> getOrgMembers(@PathVariable String orgApiService.getOrganizationMembers(id, pageNum, pageSize) .map(ResponseView::success)); } - @Override - public Mono> getOrgMembersForSearch(@PathVariable String orgId, - @PathVariable String searchMemberName, - @PathVariable String searchGroupId, - @RequestParam(required = false, defaultValue = "1") int pageNum, - @RequestParam(required = false, defaultValue = "1000") int pageSize) { - return gidService.convertOrganizationIdToObjectId(orgId).flatMap(id -> - orgApiService.getOrganizationMembersForSearch(id, searchMemberName, searchGroupId, pageNum, pageSize) - .map(ResponseView::success)); - } @Override public Mono> updateRoleForMember(@RequestBody UpdateRoleRequest updateRoleRequest, diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java index 6fee2a511f..86ed6888b2 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java @@ -98,13 +98,6 @@ public Mono> getOrgMembers(@PathVariable String @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "1000") int pageSize); - @GetMapping("/{orgId}/{searchMemberName}/{searchGroupId}/members") - public Mono> getOrgMembersForSearch(@PathVariable String orgId, - @PathVariable String searchMemberName, - @PathVariable String searchGroupId, - @RequestParam(required = false, defaultValue = "1") int pageNum, - @RequestParam(required = false, defaultValue = "1000") int pageSize); - @Operation( tags = TAG_ORGANIZATION_MEMBERS, operationId = "updateOrganizationMemberRole", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy