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

Skip to content

Commit 096a7d2

Browse files
dragonpooludomikula
authored andcommitted
Feat: add API to list groups and users without permissions, with search and pagination support
1 parent 27ea453 commit 096a7d2

File tree

4 files changed

+120
-5
lines changed

4 files changed

+120
-5
lines changed

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import reactor.core.publisher.Flux;
1616
import reactor.core.publisher.Mono;
1717

18+
import java.util.List;
1819
import java.util.Set;
1920

2021
public interface ApplicationApiService {
@@ -66,4 +67,6 @@ Mono<Boolean> grantPermission(String applicationId,
6667
Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile);
6768

6869
Mono<Application> updateSlug(String applicationId, String slug);
70+
71+
Mono<List<Object>> getGroupsOrMembersWithoutPermissions(String appId);
6972
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiServiceImpl.java

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,22 @@
2222
import org.lowcoder.api.home.UserHomeApiService;
2323
import org.lowcoder.api.permission.PermissionHelper;
2424
import org.lowcoder.api.permission.view.PermissionItemView;
25+
import org.lowcoder.api.usermanagement.GroupApiService;
26+
import org.lowcoder.api.usermanagement.OrgApiService;
2527
import org.lowcoder.api.usermanagement.OrgDevChecker;
28+
import org.lowcoder.api.usermanagement.view.GroupView;
29+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
2630
import org.lowcoder.domain.application.model.*;
2731
import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService;
2832
import org.lowcoder.domain.application.service.ApplicationRecordService;
2933
import org.lowcoder.domain.application.service.ApplicationService;
3034
import org.lowcoder.domain.datasource.model.Datasource;
3135
import org.lowcoder.domain.datasource.service.DatasourceService;
3236
import org.lowcoder.domain.folder.service.FolderElementRelationService;
37+
import org.lowcoder.domain.group.model.Group;
38+
import org.lowcoder.domain.group.model.GroupMember;
3339
import org.lowcoder.domain.interaction.UserApplicationInteractionService;
40+
import org.lowcoder.domain.organization.model.OrgMember;
3441
import org.lowcoder.domain.organization.model.Organization;
3542
import org.lowcoder.domain.organization.service.OrgMemberService;
3643
import org.lowcoder.domain.organization.service.OrganizationService;
@@ -54,13 +61,11 @@
5461
import reactor.core.publisher.Flux;
5562
import reactor.core.publisher.Mono;
5663
import reactor.core.scheduler.Schedulers;
64+
import reactor.util.function.Tuple2;
5765

5866
import java.time.Duration;
5967
import java.time.Instant;
60-
import java.util.HashSet;
61-
import java.util.List;
62-
import java.util.Map;
63-
import java.util.Set;
68+
import java.util.*;
6469
import java.util.stream.Collectors;
6570

6671
import static org.lowcoder.domain.application.model.ApplicationStatus.NORMAL;
@@ -99,6 +104,8 @@ public class ApplicationApiServiceImpl implements ApplicationApiService {
99104
private final ApplicationHistorySnapshotService applicationHistorySnapshotService;
100105
private final ApplicationRecordService applicationRecordService;
101106
private final FolderElementRelationService folderElementRelationService;
107+
private final GroupApiService groupApiService;
108+
private final OrgApiService orgApiService;
102109

103110
@Override
104111
public Mono<ApplicationView> create(CreateApplicationRequest createApplicationRequest) {
@@ -743,4 +750,62 @@ private Mono<Void> checkDatasourcePermissions(Application application) {
743750
});
744751
});
745752
}
753+
754+
@Override
755+
public Mono<List<Object>> getGroupsOrMembersWithoutPermissions(String appId) {
756+
return applicationService.findById(appId)
757+
.flatMap(application -> {
758+
String orgId = application.getOrganizationId();
759+
Mono<List<ResourcePermission>> applicationPermissions = resourcePermissionService.getByApplicationId(application.getId()).cache();
760+
761+
Mono<List<PermissionItemView>> groupPermissionPairsMono = applicationPermissions
762+
.flatMap(permissionHelper::getGroupPermissions);
763+
764+
Mono<List<PermissionItemView>> userPermissionPairsMono = applicationPermissions
765+
.flatMap(permissionHelper::getUserPermissions);
766+
Mono<OrgMemberListView> orgMemberListViewMono = orgApiService.getOrganizationMembers(orgId, 1, 0);
767+
Mono<List<GroupView>> groupsViewMono = groupApiService.getGroups();
768+
769+
return Mono.zip(groupPermissionPairsMono, userPermissionPairsMono, orgMemberListViewMono, groupsViewMono)
770+
.map(tuple -> {
771+
List<PermissionItemView> groupPermissionPairs = tuple.getT1();
772+
List<PermissionItemView> userPermissionPairs = tuple.getT2();
773+
OrgMemberListView orgMemberListViews = tuple.getT3();
774+
List<GroupView> groupListViews = tuple.getT4();
775+
776+
Set<String> groupIdsWithPerm = groupPermissionPairs.stream()
777+
.map(PermissionItemView::getId)
778+
.collect(Collectors.toSet());
779+
780+
List<Map<String, Object>> filteredGroups = groupListViews.stream()
781+
.filter(group -> !groupIdsWithPerm.contains(group.getGroupId()))
782+
.map(group -> {
783+
Map<String, Object> map = new HashMap<>();
784+
map.put("type", "Group");
785+
map.put("data", group);
786+
return map;
787+
})
788+
.toList();
789+
790+
Set<String> userIdsWithPerm = userPermissionPairs.stream()
791+
.map(PermissionItemView::getId)
792+
.collect(Collectors.toSet());
793+
794+
List<Map<String, Object>> filteredMembers = orgMemberListViews.getMembers().stream()
795+
.filter(member -> !userIdsWithPerm.contains(member.getUserId()))
796+
.map(member -> {
797+
Map<String, Object> map = new HashMap<>();
798+
map.put("type", "User");
799+
map.put("data", member);
800+
return map;
801+
})
802+
.toList();
803+
804+
List<Object> result = new ArrayList<>();
805+
result.addAll(filteredGroups);
806+
result.addAll(filteredMembers);
807+
return result;
808+
});
809+
});
810+
}
746811
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import static org.lowcoder.plugin.api.event.LowcoderEvent.EventType.*;
2828
import static org.lowcoder.sdk.exception.BizError.INVALID_PARAMETER;
2929
import static org.lowcoder.sdk.util.ExceptionUtils.ofError;
30+
import reactor.core.publisher.Flux;
31+
import java.util.Map;
3032

3133
@RequiredArgsConstructor
3234
@RestController
@@ -298,5 +300,36 @@ public Mono<ResponseView<Boolean>> setApplicationAsAgencyProfile(@PathVariable S
298300
.map(ResponseView::success));
299301
}
300302

301-
303+
@Override
304+
public Mono<ResponseView<List<Object>>> getGroupsOrMembersWithoutPermissions(
305+
@PathVariable String applicationId,
306+
@RequestParam(required = false) String search,
307+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
308+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize) {
309+
310+
return gidService.convertLibraryQueryIdToObjectId(applicationId).flatMap(appId -> {
311+
var flx = applicationApiService.getGroupsOrMembersWithoutPermissions(appId)
312+
.flatMapMany(Flux::fromIterable)
313+
.filter(item -> {
314+
if (search == null || search.isBlank()) return true;
315+
if (!(item instanceof Map map)) return false;
316+
Object type = map.get("type");
317+
Object data = map.get("data");
318+
if ("Group".equals(type) && data instanceof org.lowcoder.api.usermanagement.view.GroupView group) {
319+
return group.getGroupName() != null && group.getGroupName().toLowerCase().contains(search.toLowerCase());
320+
}
321+
if ("User".equals(type) && data instanceof org.lowcoder.api.usermanagement.view.OrgMemberListView.OrgMemberView user) {
322+
return user.getName() != null && user.getName().toLowerCase().contains(search.toLowerCase());
323+
}
324+
return false;
325+
})
326+
.cache();
327+
var countMono = flx.count();
328+
var flux1 = flx.skip((long) (pageNum - 1) * pageSize);
329+
if (pageSize > 0) flux1 = flux1.take(pageSize);
330+
return flux1.collectList()
331+
.zipWith(countMono)
332+
.map(tuple -> PageResponseView.success(tuple.getT1(), pageNum, pageSize, Math.toIntExact(tuple.getT2())));
333+
});
334+
}
302335
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ public Mono<ResponseView<Boolean>> grantPermission(
245245
@GetMapping("/{applicationId}/permissions")
246246
public Mono<ResponseView<ApplicationPermissionView>> getApplicationPermissions(@PathVariable String applicationId);
247247

248+
@Operation(
249+
tags = ApplicationEndpoints.TAG_APPLICATION_PERMISSIONS,
250+
operationId = "listGroupsOrMembersWithoutPermissions",
251+
summary = "Get groups or members without permissions",
252+
description = "Retrieve the groups or members of a specific Lowcoder Application identified by its ID that do not have permissions."
253+
)
254+
@GetMapping("/{applicationId}/get_groups_or_members_without_permissions")
255+
public Mono<ResponseView<List<Object>>> getGroupsOrMembersWithoutPermissions(
256+
@PathVariable String applicationId,
257+
@RequestParam(required = false) String search,
258+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
259+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize
260+
);
261+
248262
@Operation(
249263
tags = TAG_APPLICATION_MANAGEMENT,
250264
operationId = "setApplicationAsPublic",

0 commit comments

Comments
 (0)