Skip to content

Commit 2de9c43

Browse files
committed
feat: add unified datasource available members endpoint
1 parent 9a52ed3 commit 2de9c43

File tree

4 files changed

+146
-21
lines changed

4 files changed

+146
-21
lines changed

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceApiService.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package org.lowcoder.api.datasource;
22

3-
import jakarta.annotation.Nullable;
3+
import java.util.List;
4+
import java.util.Set;
5+
46
import org.lowcoder.api.permission.view.CommonPermissionView;
57
import org.lowcoder.domain.datasource.model.Datasource;
68
import org.lowcoder.domain.permission.model.ResourceRole;
79
import org.lowcoder.domain.plugin.client.dto.GetPluginDynamicConfigRequestDTO;
810
import org.lowcoder.sdk.models.DatasourceTestResult;
9-
import org.springframework.web.bind.annotation.RequestParam;
11+
12+
import jakarta.annotation.Nullable;
1013
import reactor.core.publisher.Flux;
1114
import reactor.core.publisher.Mono;
1215

13-
import java.util.List;
14-
import java.util.Set;
15-
1616
public interface DatasourceApiService {
1717
Mono<Datasource> create(Datasource datasource);
1818

@@ -41,4 +41,6 @@ public interface DatasourceApiService {
4141
Mono<Boolean> updatePermission(String permissionId, ResourceRole role);
4242

4343
Mono<Boolean> deletePermission(String permissionId);
44+
45+
Mono<List<Object>> getGroupsOrMembersWithoutPermissions(String datasourceId);
4446
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceApiServiceImpl.java

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
package org.lowcoder.api.datasource;
22

3-
import com.github.f4b6a3.uuid.UuidCreator;
4-
import jakarta.annotation.Nullable;
5-
import lombok.RequiredArgsConstructor;
3+
import static org.lowcoder.domain.permission.model.ResourceAction.MANAGE_DATASOURCES;
4+
import static org.lowcoder.domain.permission.model.ResourceAction.READ_APPLICATIONS;
5+
import static org.lowcoder.domain.permission.model.ResourceAction.USE_DATASOURCES;
6+
import static org.lowcoder.sdk.exception.BizError.NOT_AUTHORIZED;
7+
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
8+
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.HashMap;
12+
import java.util.List;
13+
import java.util.Map;
14+
import java.util.Set;
15+
import java.util.stream.Collectors;
16+
617
import org.apache.commons.collections4.CollectionUtils;
718
import org.apache.commons.lang3.StringUtils;
819
import org.lowcoder.api.application.ApplicationApiService;
920
import org.lowcoder.api.home.SessionUserService;
1021
import org.lowcoder.api.permission.PermissionHelper;
1122
import org.lowcoder.api.permission.view.CommonPermissionView;
1223
import org.lowcoder.api.permission.view.PermissionItemView;
24+
import org.lowcoder.api.usermanagement.GroupApiService;
25+
import org.lowcoder.api.usermanagement.OrgApiService;
1326
import org.lowcoder.api.usermanagement.OrgDevChecker;
27+
import org.lowcoder.api.usermanagement.view.GroupView;
28+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
1429
import org.lowcoder.domain.application.service.ApplicationService;
1530
import org.lowcoder.domain.datasource.model.Datasource;
1631
import org.lowcoder.domain.datasource.model.DatasourceStatus;
@@ -38,18 +53,13 @@
3853
import org.lowcoder.sdk.models.HasIdAndAuditing;
3954
import org.lowcoder.sdk.models.JsDatasourceConnectionConfig;
4055
import org.springframework.stereotype.Service;
41-
import reactor.core.publisher.Flux;
42-
import reactor.core.publisher.Mono;
4356

44-
import java.util.Collections;
45-
import java.util.List;
46-
import java.util.Map;
47-
import java.util.Set;
48-
import java.util.stream.Collectors;
57+
import com.github.f4b6a3.uuid.UuidCreator;
4958

50-
import static org.lowcoder.domain.permission.model.ResourceAction.*;
51-
import static org.lowcoder.sdk.exception.BizError.NOT_AUTHORIZED;
52-
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
59+
import jakarta.annotation.Nullable;
60+
import lombok.RequiredArgsConstructor;
61+
import reactor.core.publisher.Flux;
62+
import reactor.core.publisher.Mono;
5363

5464
@RequiredArgsConstructor
5565
@Service
@@ -71,6 +81,8 @@ public class DatasourceApiServiceImpl implements DatasourceApiService {
7181
private final DatasourcePluginClient datasourcePluginClient;
7282
private final DatasourceRepository datasourceRepository;
7383
private final ApplicationApiService applicationApiService;
84+
private final OrgApiService orgApiService;
85+
private final GroupApiService groupApiService;
7486

7587
@Override
7688
public Mono<Datasource> create(Datasource datasource) {
@@ -267,6 +279,66 @@ public Mono<Boolean> grantPermission(String datasourceId, @Nullable Set<String>
267279
.thenReturn(true);
268280
}
269281

282+
@Override
283+
public Mono<List<Object>> getGroupsOrMembersWithoutPermissions(String datasourceId) {
284+
return datasourceService.getById(datasourceId)
285+
.switchIfEmpty(Mono.error(new ServerException("data source not exist. {}", datasourceId)))
286+
.flatMap(datasource -> {
287+
String orgId = datasource.getOrganizationId();
288+
Mono<List<ResourcePermission>> datasourcePermissions = resourcePermissionService.getByDataSourceId(datasource.getId()).cache();
289+
290+
Mono<List<PermissionItemView>> groupPermissionPairsMono = datasourcePermissions
291+
.flatMap(permissionHelper::getGroupPermissions);
292+
293+
Mono<List<PermissionItemView>> userPermissionPairsMono = datasourcePermissions
294+
.flatMap(permissionHelper::getUserPermissions);
295+
Mono<OrgMemberListView> orgMemberListViewMono = orgApiService.getOrganizationMembers(orgId, 1, 0);
296+
Mono<List<GroupView>> groupsViewMono = groupApiService.getGroups();
297+
298+
return Mono.zip(groupPermissionPairsMono, userPermissionPairsMono, orgMemberListViewMono, groupsViewMono)
299+
.map(tuple -> {
300+
List<PermissionItemView> groupPermissionPairs = tuple.getT1();
301+
List<PermissionItemView> userPermissionPairs = tuple.getT2();
302+
OrgMemberListView orgMemberListViews = tuple.getT3();
303+
List<GroupView> groupListViews = tuple.getT4();
304+
305+
Set<String> groupIdsWithPerm = groupPermissionPairs.stream()
306+
.map(PermissionItemView::getId)
307+
.collect(java.util.stream.Collectors.toSet());
308+
309+
List<java.util.Map<String, Object>> filteredGroups = groupListViews.stream()
310+
.filter(group -> !groupIdsWithPerm.contains(group.getGroupId()))
311+
.map(group -> {
312+
java.util.Map<String, Object> map = new java.util.HashMap<>();
313+
map.put("type", "Group");
314+
map.put("data", group);
315+
return map;
316+
})
317+
.toList();
318+
319+
Set<String> userIdsWithPerm = userPermissionPairs.stream()
320+
.map(PermissionItemView::getId)
321+
.collect(java.util.stream.Collectors.toSet());
322+
323+
List<Map<String, Object>> filteredMembers = orgMemberListViews.getMembers().stream()
324+
.filter(member -> !userIdsWithPerm.contains(member.getUserId()))
325+
.map(member -> {
326+
Map<String, Object> map = new HashMap<>();
327+
map.put("type", "User");
328+
map.put("data", member);
329+
return map;
330+
})
331+
.toList();
332+
333+
List<Object> result = new ArrayList<>();
334+
result.addAll(filteredGroups);
335+
result.addAll(filteredMembers);
336+
return result;
337+
});
338+
});
339+
}
340+
341+
270342
@Override
271343
public Mono<Boolean> updatePermission(String permissionId, ResourceRole role) {
272344
return checkBeforePermissionDeleteOrUpdate(permissionId)

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import org.lowcoder.api.framework.view.PageResponseView;
1111
import org.lowcoder.api.framework.view.ResponseView;
1212
import org.lowcoder.api.permission.view.CommonPermissionView;
13+
import org.lowcoder.api.usermanagement.view.GroupView;
14+
import org.lowcoder.api.usermanagement.view.OrgMemberListView;
1315
import org.lowcoder.api.usermanagement.view.UpdateGroupRequest;
1416
import org.lowcoder.api.util.BusinessEventPublisher;
1517
import org.lowcoder.api.util.GidService;
@@ -26,17 +28,17 @@
2628
import org.springframework.web.bind.annotation.RequestBody;
2729
import org.springframework.web.bind.annotation.RequestParam;
2830
import org.springframework.web.bind.annotation.RestController;
31+
import reactor.core.publisher.Flux;
2932
import reactor.core.publisher.Mono;
3033

31-
import java.util.Collections;
32-
import java.util.List;
33-
import java.util.Locale;
34+
import java.util.*;
3435

3536
import static org.lowcoder.api.util.Pagination.fluxToPageResponseView;
3637
import static org.lowcoder.plugin.api.event.LowcoderEvent.EventType.*;
3738
import static org.lowcoder.sdk.exception.BizError.INVALID_PARAMETER;
3839
import static org.lowcoder.sdk.util.ExceptionUtils.ofError;
3940
import static org.lowcoder.sdk.util.LocaleUtils.getLocale;
41+
import static reactor.core.publisher.Flux.fromIterable;
4042

4143
@RequiredArgsConstructor
4244
@RestController
@@ -227,4 +229,38 @@ public Mono<ResponseView<Object>> info(@RequestParam(required = false) String da
227229
Mono.just(ResponseView.success(datasourceApiService.info(objectId))));
228230
}
229231

232+
@Override
233+
public Mono<PageResponseView<?>> getGroupsOrMembersWithoutPermissions(
234+
@PathVariable String datasourceId,
235+
@RequestParam(required = false) String search,
236+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
237+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize) {
238+
239+
return gidService.convertDatasourceIdToObjectId(datasourceId).flatMap(dsId -> {
240+
var flx = datasourceApiService.getGroupsOrMembersWithoutPermissions(dsId)
241+
.flatMapMany(Flux::fromIterable)
242+
.filter(item -> {
243+
if (search == null || search.isBlank()) return true;
244+
if (!(item instanceof Map map)) return false;
245+
Object type = map.get("type");
246+
Object data = map.get("data");
247+
if ("Group".equals(type) && data instanceof GroupView group) {
248+
return group.getGroupName() != null && group.getGroupName().toLowerCase().contains(search.toLowerCase());
249+
}
250+
if ("User".equals(type) && data instanceof OrgMemberListView.OrgMemberView user) {
251+
return user.getName() != null && user.getName().toLowerCase().contains(search.toLowerCase());
252+
}
253+
return false;
254+
})
255+
.cache();
256+
var countMono = flx.count();
257+
var flux1 = flx.skip((long) (pageNum - 1) * pageSize);
258+
if (pageSize > 0) flux1 = flux1.take(pageSize);
259+
return flux1.collectList()
260+
.zipWith(countMono)
261+
.map(tuple -> PageResponseView.success(tuple.getT1(), pageNum, pageSize, Math.toIntExact(tuple.getT2())));
262+
});
263+
}
264+
265+
230266
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceEndpoints.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,21 @@ public Mono<ResponseView<Boolean>> updatePermission(@PathVariable("permissionId"
190190
@GetMapping("/info")
191191
public Mono<ResponseView<Object>> info(@RequestParam(required = false) String datasourceId);
192192

193+
194+
@Operation(
195+
tags = TAG_DATASOURCE_PERMISSIONS,
196+
operationId = "listGroupsOrMembersWithoutPermissionsForDatasource",
197+
summary = "Get groups or members without permissions for datasource",
198+
description = "Retrieve the groups or members of a specific datasource identified by its ID that do not have permissions."
199+
)
200+
@GetMapping("/{datasourceId}/available")
201+
public Mono<PageResponseView<?>> getGroupsOrMembersWithoutPermissions(
202+
@PathVariable String datasourceId,
203+
@RequestParam(required = false) String search,
204+
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
205+
@RequestParam(required = false, defaultValue = "1000") Integer pageSize
206+
);
207+
193208
public record BatchAddPermissionRequest(String role, Set<String> userIds, Set<String> groupIds) {
194209
}
195210

0 commit comments

Comments
 (0)
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