Skip to content

Commit e617349

Browse files
author
Sebastian Reid
committed
Bundle API
- Permission - create/delete/recycle/restore/update - list(recycle, published)
1 parent 7508807 commit e617349

23 files changed

+835
-73
lines changed

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/bundle/model/Bundle.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,25 @@
55
import lombok.Getter;
66
import lombok.NoArgsConstructor;
77
import lombok.Setter;
8+
import lombok.experimental.SuperBuilder;
89
import org.lowcoder.sdk.models.HasIdAndAuditing;
910
import org.springframework.data.mongodb.core.mapping.Document;
1011

1112
@Getter
1213
@Setter
1314
@Document
1415
@NoArgsConstructor
16+
@SuperBuilder
1517
public class Bundle extends HasIdAndAuditing {
16-
17-
private String userId;
18+
private String organizationId;
1819
@Nullable
1920
private String name;
2021
private String title;
2122
private String description;
2223
private String category;
23-
private String type;
2424
private String image;
25+
private BundleStatus bundleStatus;
26+
private Boolean publicToAll;
27+
private Boolean publicToMarketplace;
28+
private Boolean agencyProfile;
2529
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.lowcoder.domain.bundle.model;
2+
3+
public enum BundleRequestType {
4+
PUBLIC_TO_ALL,
5+
PUBLIC_TO_MARKETPLACE,
6+
AGENCY_PROFILE,
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.lowcoder.domain.bundle.model;
2+
3+
public enum BundleStatus {
4+
5+
NORMAL, // default
6+
RECYCLED,
7+
DELETED,
8+
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/bundle/model/BundleType.java

Lines changed: 0 additions & 7 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
package org.lowcoder.domain.bundle.repository;
22

3+
import org.lowcoder.domain.application.model.Application;
34
import org.lowcoder.domain.bundle.model.Bundle;
45
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
56
import org.springframework.stereotype.Repository;
67
import reactor.core.publisher.Flux;
78

9+
import java.util.Collection;
10+
811
@Repository
912
public interface BundleRepository extends ReactiveMongoRepository<Bundle, String> {
1013

1114
Flux<Bundle> findByUserId(String userId);
15+
/**
16+
* Filter marketplace bundles from list of supplied IDs
17+
*/
18+
Flux<Bundle> findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(Collection<String> ids);
19+
/**
20+
* Filter public bundles from list of supplied IDs
21+
*/
22+
Flux<Bundle> findByPublicToAllIsTrueAndIdIn(Collection<String> ids);
23+
Flux<Bundle> findByCreatedByAndIdIn(String userId, Collection<String> ids);
24+
/**
25+
* Filter agency bundles from list of supplied IDs
26+
*/
27+
Flux<Bundle> findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(Collection<String> ids);
1228
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/bundle/service/BundleService.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package org.lowcoder.domain.bundle.service;
22

3+
import org.lowcoder.domain.application.model.ApplicationRequestType;
34
import org.lowcoder.domain.bundle.model.Bundle;
5+
import org.lowcoder.domain.bundle.model.BundleRequestType;
6+
import org.lowcoder.infra.annotation.NonEmptyMono;
47
import reactor.core.publisher.Flux;
58
import reactor.core.publisher.Mono;
69

710
import java.util.Collection;
11+
import java.util.Set;
812

913
public interface BundleService {
1014
Mono<Boolean> updateById(String id, Bundle resource);
@@ -18,4 +22,23 @@ public interface BundleService {
1822
Mono<Void> deleteAllById(Collection<String> ids);
1923

2024
Mono<Boolean> exist(String id);
25+
26+
@NonEmptyMono
27+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
28+
Mono<Set<String>> getFilteredPublicBundleIds(BundleRequestType requestType, Collection<String> bundleIds, String userId, Boolean isPrivateMarketplace);
29+
@NonEmptyMono
30+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
31+
Mono<Set<String>> getPublicBundleIds(Collection<String> bundleIds);
32+
33+
@NonEmptyMono
34+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
35+
Mono<Set<String>> getPrivateBundleIds(Collection<String> bundleIds, String userId);
36+
37+
@NonEmptyMono
38+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
39+
Mono<Set<String>> getPublicMarketplaceBundleIds(Collection<String> bundleIds, boolean isAnonymous, boolean isPrivateMarketplace);
40+
41+
@NonEmptyMono
42+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
43+
Mono<Set<String>> getPublicAgencyBundleIds(Collection<String> bundleIds);
2144
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/bundle/service/BundleServiceImpl.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package org.lowcoder.domain.bundle.service;
22

33
import lombok.RequiredArgsConstructor;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.lowcoder.domain.application.model.ApplicationRequestType;
46
import org.lowcoder.domain.bundle.model.Bundle;
7+
import org.lowcoder.domain.bundle.model.BundleRequestType;
58
import org.lowcoder.domain.bundle.repository.BundleRepository;
9+
import org.lowcoder.infra.annotation.NonEmptyMono;
610
import org.lowcoder.infra.mongo.MongoUpsertHelper;
711
import org.lowcoder.sdk.constants.FieldName;
812
import org.lowcoder.sdk.exception.BizError;
913
import org.lowcoder.sdk.exception.BizException;
14+
import org.lowcoder.sdk.models.HasIdAndAuditing;
1015
import org.springframework.stereotype.Service;
1116
import reactor.core.publisher.Flux;
1217
import reactor.core.publisher.Mono;
1318

1419
import java.util.Collection;
20+
import java.util.Set;
21+
import java.util.stream.Collectors;
1522

1623
import static org.lowcoder.sdk.exception.BizError.NO_RESOURCE_FOUND;
1724

@@ -67,4 +74,93 @@ public Mono<Boolean> exist(String id) {
6774
return Mono.error(throwable);
6875
});
6976
}
77+
78+
79+
@Override
80+
@NonEmptyMono
81+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
82+
public Mono<Set<String>> getFilteredPublicBundleIds(BundleRequestType requestType, Collection<String> bundleIds, String userId, Boolean isPrivateMarketplace) {
83+
boolean isAnonymous = StringUtils.isBlank(userId);
84+
switch(requestType)
85+
{
86+
case PUBLIC_TO_ALL:
87+
if (isAnonymous)
88+
{
89+
return getPublicBundleIds(bundleIds);
90+
}
91+
else
92+
{
93+
return getPrivateBundleIds(bundleIds, userId);
94+
}
95+
case PUBLIC_TO_MARKETPLACE:
96+
return getPublicMarketplaceBundleIds(bundleIds, isAnonymous, isPrivateMarketplace);
97+
case AGENCY_PROFILE:
98+
return getPublicAgencyBundleIds(bundleIds);
99+
default:
100+
return Mono.empty();
101+
}
102+
}
103+
104+
/**
105+
* Find all public bundles - doesn't matter if user is anonymous, because these apps are public
106+
*/
107+
@Override
108+
@NonEmptyMono
109+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
110+
public Mono<Set<String>> getPublicBundleIds(Collection<String> bundleIds) {
111+
112+
return repository.findByPublicToAllIsTrueAndIdIn(bundleIds)
113+
.map(HasIdAndAuditing::getId)
114+
.collect(Collectors.toSet());
115+
}
116+
117+
118+
/**
119+
* Find all private bundles for viewing.
120+
*/
121+
@Override
122+
@NonEmptyMono
123+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
124+
public Mono<Set<String>> getPrivateBundleIds(Collection<String> bundleIds, String userId) {
125+
126+
// TODO: in 2.4.0 we need to check whether the app was published or not
127+
return repository.findByCreatedByAndIdIn(userId, bundleIds)
128+
.map(HasIdAndAuditing::getId)
129+
.collect(Collectors.toSet());
130+
131+
// return repository.findByIdIn(bundleIds)
132+
// .map(HasIdAndAuditing::getId)
133+
// .collect(Collectors.toSet());
134+
}
135+
136+
137+
/**
138+
* Find all marketplace bundles - filter based on whether user is anonymous and whether it's a private marketplace
139+
*/
140+
@Override
141+
@NonEmptyMono
142+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
143+
public Mono<Set<String>> getPublicMarketplaceBundleIds(Collection<String> bundleIds, boolean isAnonymous, boolean isPrivateMarketplace) {
144+
145+
if ((isAnonymous && !isPrivateMarketplace) || !isAnonymous)
146+
{
147+
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(bundleIds)
148+
.map(HasIdAndAuditing::getId)
149+
.collect(Collectors.toSet());
150+
}
151+
return Mono.empty();
152+
}
153+
154+
/**
155+
* Find all agency bundles
156+
*/
157+
@Override
158+
@NonEmptyMono
159+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
160+
public Mono<Set<String>> getPublicAgencyBundleIds(Collection<String> bundleIds) {
161+
162+
return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(bundleIds)
163+
.map(HasIdAndAuditing::getId)
164+
.collect(Collectors.toSet());
165+
}
70166
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceAction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,20 @@ public enum ResourceAction {
2121
EXPORT_APPLICATIONS(ResourceRole.EDITOR, ResourceType.APPLICATION),
2222
EDIT_APPLICATIONS(ResourceRole.EDITOR, ResourceType.APPLICATION),
2323

24+
MANAGE_BUNDLES(ResourceRole.OWNER, ResourceType.BUNDLE),
25+
READ_BUNDLES(ResourceRole.VIEWER, ResourceType.BUNDLE),
26+
PUBLISH_BUNDLES(ResourceRole.EDITOR, ResourceType.BUNDLE),
27+
EXPORT_BUNDLES(ResourceRole.EDITOR, ResourceType.BUNDLE),
28+
EDIT_BUNDLES(ResourceRole.EDITOR, ResourceType.BUNDLE),
29+
2430
SET_APPLICATIONS_PUBLIC(ResourceRole.EDITOR, ResourceType.APPLICATION),
2531
SET_APPLICATIONS_PUBLIC_TO_MARKETPLACE(ResourceRole.EDITOR, ResourceType.APPLICATION),
2632
SET_APPLICATIONS_AS_AGENCY_PROFILE(ResourceRole.EDITOR, ResourceType.APPLICATION),
2733

34+
SET_BUNDLES_PUBLIC(ResourceRole.EDITOR, ResourceType.BUNDLE),
35+
SET_BUNDLES_PUBLIC_TO_MARKETPLACE(ResourceRole.EDITOR, ResourceType.BUNDLE),
36+
SET_BUNDLES_AS_AGENCY_PROFILE(ResourceRole.EDITOR, ResourceType.BUNDLE),
37+
2838
// datasource action
2939
MANAGE_DATASOURCES(ResourceRole.OWNER, ResourceType.DATASOURCE),
3040
USE_DATASOURCES(ResourceRole.VIEWER, ResourceType.DATASOURCE),

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.lowcoder.domain.application.model.Application;
55
import org.lowcoder.domain.application.model.ApplicationRequestType;
66
import org.lowcoder.domain.application.service.ApplicationService;
7+
import org.lowcoder.domain.bundle.model.BundleRequestType;
78
import org.lowcoder.domain.permission.model.ResourceAction;
89
import org.lowcoder.domain.permission.model.ResourcePermission;
910
import org.lowcoder.domain.permission.model.ResourceRole;
@@ -99,7 +100,17 @@ protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserApplica
99100
});
100101
}
101102

102-
private List<ResourcePermission> getAnonymousUserPermission(String applicationId) {
103+
@Override
104+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserBundlePermissions(Collection<String> resourceIds, ResourceAction resourceAction, BundleRequestType requestType) {
105+
return Mono.just(Collections.emptyMap());
106+
}
107+
108+
@Override
109+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserBundlePublicResourcePermissions(Collection<String> resourceIds, ResourceAction resourceAction, BundleRequestType requestType, String userId) {
110+
return Mono.just(Collections.emptyMap());
111+
}
112+
113+
private List<ResourcePermission> getAnonymousUserPermission(String applicationId) {
103114
return Collections.singletonList(ResourcePermission.builder()
104115
.resourceId(applicationId)
105116
.resourceType(ResourceType.APPLICATION)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.lowcoder.domain.permission.service;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.lowcoder.domain.application.model.ApplicationRequestType;
5+
import org.lowcoder.domain.bundle.model.Bundle;
6+
import org.lowcoder.domain.bundle.model.BundleRequestType;
7+
import org.lowcoder.domain.bundle.service.BundleService;
8+
import org.lowcoder.domain.permission.model.ResourceAction;
9+
import org.lowcoder.domain.permission.model.ResourcePermission;
10+
import org.lowcoder.domain.permission.model.ResourceRole;
11+
import org.lowcoder.domain.permission.model.ResourceType;
12+
import org.lowcoder.domain.solutions.TemplateSolutionService;
13+
import org.springframework.context.annotation.Lazy;
14+
import org.springframework.stereotype.Component;
15+
import reactor.core.publisher.Mono;
16+
17+
import java.util.*;
18+
19+
import static com.google.common.collect.Sets.newHashSet;
20+
import static java.util.Collections.emptyMap;
21+
import static java.util.function.Function.identity;
22+
import static org.apache.commons.collections4.SetUtils.union;
23+
import static org.lowcoder.domain.permission.model.ResourceHolder.USER;
24+
import static org.lowcoder.sdk.constants.Authentication.ANONYMOUS_USER_ID;
25+
import static org.lowcoder.sdk.util.StreamUtils.collectMap;
26+
27+
@RequiredArgsConstructor
28+
@Component
29+
class BundlePermissionHandler extends ResourcePermissionHandler {
30+
31+
private static final ResourceRole ANONYMOUS_USER_ROLE = ResourceRole.VIEWER;
32+
33+
@Lazy
34+
private final BundleService bundleService;
35+
private final TemplateSolutionService templateSolutionService;
36+
37+
@Override
38+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserPermissions(Collection<String> resourceIds,
39+
ResourceAction resourceAction) {
40+
if (!ANONYMOUS_USER_ROLE.canDo(resourceAction)) {
41+
return Mono.just(emptyMap());
42+
}
43+
44+
Set<String> bundleIds = newHashSet(resourceIds);
45+
return bundleService.getPublicBundleIds(bundleIds)
46+
.map(publicAppIds -> collectMap(publicAppIds, identity(), this::getAnonymousUserPermission));
47+
}
48+
49+
// This is for PTM apps that are public but only available to logged-in users
50+
@Override
51+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserPublicResourcePermissions
52+
(Collection<String> resourceIds, ResourceAction resourceAction, String userId) {
53+
54+
Set<String> bundleIds = newHashSet(resourceIds);
55+
return bundleService.getPrivateBundleIds(bundleIds, userId)
56+
.map(publicAppIds -> collectMap(publicAppIds, identity(), this::getAnonymousUserPermission));
57+
}
58+
59+
@Override
60+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserApplicationPermissions(Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) {
61+
return Mono.just(Collections.emptyMap());
62+
}
63+
64+
@Override
65+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserApplicationPublicResourcePermissions(Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType, String userId) {
66+
return Mono.just(Collections.emptyMap());
67+
}
68+
69+
70+
@Override
71+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserBundlePermissions(
72+
Collection<String> resourceIds, ResourceAction resourceAction, BundleRequestType requestType)
73+
{
74+
if (!ANONYMOUS_USER_ROLE.canDo(resourceAction)) {
75+
return Mono.just(emptyMap());
76+
}
77+
78+
Set<String> bundleIds = newHashSet(resourceIds);
79+
return bundleService.getFilteredPublicBundleIds(requestType, bundleIds, null, config.getMarketplace().isPrivateMode())
80+
.defaultIfEmpty(new HashSet<>()).map(publicAppIds -> collectMap(publicAppIds, identity(), this::getAnonymousUserPermission));
81+
}
82+
83+
@Override
84+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserBundlePublicResourcePermissions(
85+
Collection<String> resourceIds, ResourceAction resourceAction, BundleRequestType requestType, String userId) {
86+
Set<String> bundleIds = newHashSet(resourceIds);
87+
return bundleService.getFilteredPublicBundleIds(requestType, bundleIds, userId, config.getMarketplace().isPrivateMode())
88+
.map(publicAppIds -> collectMap(publicAppIds, identity(), this::getAnonymousUserPermission));
89+
}
90+
91+
private List<ResourcePermission> getAnonymousUserPermission(String bundleId) {
92+
return Collections.singletonList(ResourcePermission.builder()
93+
.resourceId(bundleId)
94+
.resourceType(ResourceType.BUNDLE)
95+
.resourceHolder(USER)
96+
.resourceHolderId(ANONYMOUS_USER_ID)
97+
.resourceRole(ANONYMOUS_USER_ROLE)
98+
.build());
99+
}
100+
101+
@Override
102+
protected Mono<String> getOrgId(String resourceId) {
103+
return bundleService.findById(resourceId)
104+
.map(Bundle::getOrganizationId);
105+
}
106+
}

0 commit comments

Comments
 (0)