Skip to content

Commit 120fbc9

Browse files
committed
fix: sorted out application view rights for all cases
1 parent cc5333c commit 120fbc9

File tree

11 files changed

+258
-137
lines changed

11 files changed

+258
-137
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.lowcoder.domain.application.model;
2+
3+
public enum ApplicationRequestType {
4+
PUBLIC_TO_ALL,
5+
PUBLIC_TO_MARKETPLACE,
6+
AGENCY_PROFILE,
7+
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,28 @@ public interface ApplicationRepository extends ReactiveMongoRepository<Applicati
4545
// this we do not need
4646
// Flux<Application> findByPublicToAllIsTrueAndPublicToMarketplaceIsAndAgencyProfileIsAndIdIn(Boolean publicToMarketplace, Boolean agencyProfile, Collection<String> ids);
4747

48-
// Find all Public Applications
49-
Flux<Application> findByPublicToAllIsTrue();
50-
51-
// Find all Marketplace Apps
48+
/**
49+
* Filter public applications from list of supplied IDs
50+
*/
51+
Flux<Application> findByPublicToAllIsTrueAndIdIn(Collection<String> ids);
52+
53+
/**
54+
* Filter marketplace applications from list of supplied IDs
55+
*/
56+
Flux<Application> findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(Collection<String> ids);
57+
58+
/**
59+
* Filter agency applications from list of supplied IDs
60+
*/
61+
Flux<Application> findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(Collection<String> ids);
62+
63+
/**
64+
* Find all marketplace applications
65+
*/
5266
Flux<Application> findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue();
53-
54-
// Find all Agencies
67+
68+
/**
69+
* Find all agency applications
70+
*/
5571
Flux<Application> findByPublicToAllIsTrueAndAgencyProfileIsTrue();
56-
5772
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java

Lines changed: 42 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.stream.Collectors;
88

99
import org.lowcoder.domain.application.model.Application;
10+
import org.lowcoder.domain.application.model.ApplicationRequestType;
1011
import org.lowcoder.domain.application.model.ApplicationStatus;
1112
import org.lowcoder.domain.application.repository.ApplicationRepository;
1213
import org.lowcoder.domain.permission.model.ResourceRole;
@@ -157,8 +158,6 @@ public Mono<Boolean> setApplicationPublicToMarketplace(String applicationId, Boo
157158

158159
return findById(applicationId)
159160

160-
// Falk: question - do we need Map<String, Object> applicationDsl = application.getEditingApplicationDSL(); and .editingApplicationDSL(applicationDsl) - or is .publicToMarketplace(publicToMarketplace).build(); enough?
161-
162161
.map(application -> {
163162

164163
Map<String, Object> applicationDsl = application.getEditingApplicationDSL();
@@ -204,81 +203,64 @@ public Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean
204203
return mongoUpsertHelper.updateById(application, applicationId);
205204
}
206205

207-
// getPublicApplicationIds /view - publicToAll check
208-
// getPublicMarketplaceApplicationIds / marketplace_view - publicToAll and publicToMarketplace check & isPrivateMarketplace check
209-
// getPublicAgencyProfileApplicationIds / agency_profile_view - publicToAll and agencyProfile check
210206

211-
// marketplace_view [anonymous] publicToAll and publicToMarketplace check & isPrivateMarketplace false -> OK
207+
@NonEmptyMono
208+
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
209+
public Mono<Set<String>> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection<String> applicationIds, Boolean isAnonymous, Boolean isPrivateMarketplace) {
210+
211+
switch(requestType)
212+
{
213+
case PUBLIC_TO_ALL:
214+
return getPublicApplicationIds(applicationIds);
215+
case PUBLIC_TO_MARKETPLACE:
216+
return getPublicMarketplaceApplicationIds(applicationIds, isAnonymous, isPrivateMarketplace);
217+
case AGENCY_PROFILE:
218+
return getPublicAgencyApplicationIds(applicationIds);
219+
default:
220+
return Mono.empty();
221+
}
222+
}
212223

213-
// marketplace_view [anonymous] publicToAll and publicToMarketplace check & isPrivateMarketplace true -> NOT OK
214-
215-
// marketplace_view [LoggedIn] publicToAll and publicToMarketplace check & isPrivateMarketplace true -> OK
216-
// marketplace_view [LoggedIn] publicToAll and publicToMarketplace check & isPrivateMarketplace false -> OK
217-
218-
219-
// will be extended by EndpointType
220-
/*
221-
* if (EndpointType == view)
222-
* if (EndpointType == marketplace_view)
223-
* if (EndpointType == agency_profile_view)
224+
225+
/**
226+
* Find all public applications - doesn't matter if user is anonymous, because these apps are public
224227
*/
225-
226-
// is it needed?
227228
@NonEmptyMono
228229
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
229-
public Mono<Set<String>> getPublicApplicationIds(Collection<String> applicationIds, Boolean isAnonymous, Boolean isPrivateMarketplace) {
230+
public Mono<Set<String>> getPublicApplicationIds(Collection<String> applicationIds) {
230231

231-
return repository.findByPublicToAllIsTrue()
232+
return repository.findByPublicToAllIsTrueAndIdIn(applicationIds)
232233
.map(HasIdAndAuditing::getId)
233234
.collect(Collectors.toSet());
234235
}
235236

236-
// for Marketplaces
237+
238+
/**
239+
* Find all marketplace applications - filter based on whether user is anonymous and whether it's a private marketplace
240+
*/
237241
@NonEmptyMono
238242
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
239-
public Mono<Set<String>> getPublicMarketplaceApplicationIds(Collection<String> applicationIds, Boolean isAnonymous, Boolean isPrivateMarketplace) {
240-
241-
if(isAnonymous) {
242-
if(isPrivateMarketplace) {
243-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(false, false, applicationIds)
244-
.map(HasIdAndAuditing::getId)
245-
.collect(Collectors.toSet());
246-
} else {
247-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(true, false, applicationIds)
248-
.map(HasIdAndAuditing::getId)
249-
.collect(Collectors.toSet());
250-
}
251-
} else {
252-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(true, true, applicationIds)
253-
.map(HasIdAndAuditing::getId)
254-
.collect(Collectors.toSet());
255-
}
256-
257-
243+
public Mono<Set<String>> getPublicMarketplaceApplicationIds(Collection<String> applicationIds, boolean isAnonymous, boolean isPrivateMarketplace) {
244+
245+
if ((isAnonymous && !isPrivateMarketplace) || !isAnonymous)
246+
{
247+
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(applicationIds)
248+
.map(HasIdAndAuditing::getId)
249+
.collect(Collectors.toSet());
250+
}
251+
return Mono.empty();
258252
}
259253

260-
// for Agencies
254+
/**
255+
* Find all agency applications
256+
*/
261257
@NonEmptyMono
262258
@SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform")
263-
public Mono<Set<String>> getPublicAgencyApplicationIds(Collection<String> applicationIds, Boolean isAnonymous, Boolean isPrivateMarketplace) {
264-
265-
if(isAnonymous) {
266-
if(isPrivateMarketplace) {
267-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsAndAgencyProfileIsAndIdIn(false, false, applicationIds)
268-
.map(HasIdAndAuditing::getId)
269-
.collect(Collectors.toSet());
270-
} else {
271-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsAndAgencyProfileIsAndIdIn(true, false, applicationIds)
272-
.map(HasIdAndAuditing::getId)
273-
.collect(Collectors.toSet());
274-
}
275-
} else {
276-
return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsOrAgencyProfileIsAndIdIn(true, true, applicationIds)
277-
.map(HasIdAndAuditing::getId)
278-
.collect(Collectors.toSet());
279-
}
280-
259+
public Mono<Set<String>> getPublicAgencyApplicationIds(Collection<String> applicationIds) {
281260

261+
return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(applicationIds)
262+
.map(HasIdAndAuditing::getId)
263+
.collect(Collectors.toSet());
282264
}
283265

284266
public Flux<Application> findAll() {

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.Set;
1616

1717
import org.lowcoder.domain.application.model.Application;
18+
import org.lowcoder.domain.application.model.ApplicationRequestType;
1819
import org.lowcoder.domain.application.service.ApplicationService;
1920
import org.lowcoder.domain.permission.model.ResourceAction;
2021
import org.lowcoder.domain.permission.model.ResourcePermission;
@@ -46,7 +47,7 @@ protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserPermission
4647
}
4748

4849
Set<String> applicationIds = newHashSet(resourceIds);
49-
return Mono.zip(applicationService.getPublicApplicationIds(applicationIds, Boolean.TRUE, config.getMarketplace().isPrivateMode()),
50+
return Mono.zip(applicationService.getPublicApplicationIds(applicationIds),
5051
templateSolution.getTemplateApplicationIds(applicationIds))
5152
.map(tuple -> {
5253
Set<String> publicAppIds = tuple.getT1();
@@ -61,7 +62,7 @@ protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserPermission
6162
(Collection<String> resourceIds, ResourceAction resourceAction) {
6263

6364
Set<String> applicationIds = newHashSet(resourceIds);
64-
return Mono.zip(applicationService.getPublicApplicationIds(applicationIds, Boolean.FALSE, config.getMarketplace().isPrivateMode()),
65+
return Mono.zip(applicationService.getPublicApplicationIds(applicationIds),
6566
templateSolution.getTemplateApplicationIds(applicationIds))
6667
.map(tuple -> {
6768
Set<String> publicAppIds = tuple.getT1();
@@ -70,7 +71,39 @@ protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserPermission
7071
});
7172
}
7273

73-
private List<ResourcePermission> getAnonymousUserPermission(String applicationId) {
74+
75+
@Override
76+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserApplicationPermissions(
77+
Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType)
78+
{
79+
if (!ANONYMOUS_USER_ROLE.canDo(resourceAction)) {
80+
return Mono.just(emptyMap());
81+
}
82+
83+
Set<String> applicationIds = newHashSet(resourceIds);
84+
return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.TRUE, config.getMarketplace().isPrivateMode()),
85+
templateSolution.getTemplateApplicationIds(applicationIds))
86+
.map(tuple -> {
87+
Set<String> publicAppIds = tuple.getT1();
88+
Set<String> templateAppIds = tuple.getT2();
89+
return collectMap(union(publicAppIds, templateAppIds), identity(), this::getAnonymousUserPermission);
90+
});
91+
}
92+
93+
@Override
94+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserApplicationPublicResourcePermissions(
95+
Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) {
96+
Set<String> applicationIds = newHashSet(resourceIds);
97+
return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.FALSE, config.getMarketplace().isPrivateMode()),
98+
templateSolution.getTemplateApplicationIds(applicationIds))
99+
.map(tuple -> {
100+
Set<String> publicAppIds = tuple.getT1();
101+
Set<String> templateAppIds = tuple.getT2();
102+
return collectMap(union(publicAppIds, templateAppIds), identity(), this::getAnonymousUserPermission);
103+
});
104+
}
105+
106+
private List<ResourcePermission> getAnonymousUserPermission(String applicationId) {
74107
return Collections.singletonList(ResourcePermission.builder()
75108
.resourceId(applicationId)
76109
.resourceType(ResourceType.APPLICATION)

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.stream.Collectors;
1111

1212
import org.apache.commons.collections4.CollectionUtils;
13+
import org.lowcoder.domain.application.model.ApplicationRequestType;
1314
import org.lowcoder.domain.datasource.model.Datasource;
1415
import org.lowcoder.domain.datasource.service.DatasourceService;
1516
import org.lowcoder.domain.permission.model.ResourceAction;
@@ -44,6 +45,18 @@ protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserPublicR
4445
}
4546

4647
@Override
48+
protected Mono<Map<String, List<ResourcePermission>>> getAnonymousUserApplicationPermissions(
49+
Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) {
50+
return Mono.just(Collections.emptyMap());
51+
}
52+
53+
@Override
54+
protected Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserApplicationPublicResourcePermissions(
55+
Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) {
56+
return Mono.just(Collections.emptyMap());
57+
}
58+
59+
@Override
4760
protected Mono<String> getOrgId(String resourceId) {
4861
return datasourceService.getById(resourceId)
4962
.map(Datasource::getOrganizationId);

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.apache.commons.collections4.CollectionUtils;
2020
import org.apache.commons.collections4.ListUtils;
21+
import org.lowcoder.domain.application.model.ApplicationRequestType;
2122
import org.lowcoder.domain.group.service.GroupMemberService;
2223
import org.lowcoder.domain.organization.service.OrgMemberService;
2324
import org.lowcoder.domain.permission.model.ResourceAction;
@@ -153,6 +154,13 @@ protected abstract Mono<Map<String, List<ResourcePermission>>> getAnonymousUserP
153154
protected abstract Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserPublicResourcePermissions
154155
(Collection<String> resourceIds, ResourceAction resourceAction);
155156

157+
protected abstract Mono<Map<String, List<ResourcePermission>>> getAnonymousUserApplicationPermissions(Collection<String> resourceIds,
158+
ResourceAction resourceAction, ApplicationRequestType requestType);
159+
160+
protected abstract Mono<Map<String, List<ResourcePermission>>> getNonAnonymousUserApplicationPublicResourcePermissions
161+
(Collection<String> resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType);
162+
163+
156164
private Mono<Map<String, List<ResourcePermission>>> getAllMatchingPermissions0(String userId, String orgId, ResourceType resourceType,
157165
Collection<String> resourceIds,
158166
ResourceAction resourceAction) {
@@ -212,4 +220,63 @@ private Mono<Set<String>> getUserGroupIds(String orgId, String userId) {
212220
}
213221

214222
protected abstract Mono<String> getOrgId(String resourceId);
223+
224+
public Mono<UserPermissionOnResourceStatus> checkUserPermissionStatusOnApplication(String userId, String resourceId,
225+
ResourceAction resourceAction, ApplicationRequestType requestType)
226+
{
227+
ResourceType resourceType = resourceAction.getResourceType();
228+
229+
Mono<UserPermissionOnResourceStatus> publicResourcePermissionMono = getAnonymousUserApplicationPermissions(singletonList(resourceId), resourceAction, requestType)
230+
.map(it -> it.getOrDefault(resourceId, emptyList()))
231+
.map(it -> {
232+
if (!it.isEmpty()) {
233+
return UserPermissionOnResourceStatus.success(it.get(0));
234+
}
235+
return isAnonymousUser(userId) ? UserPermissionOnResourceStatus.anonymousUser() : UserPermissionOnResourceStatus.notInOrg();
236+
});
237+
238+
if (isAnonymousUser(userId)) {
239+
return publicResourcePermissionMono;
240+
}
241+
242+
Mono<UserPermissionOnResourceStatus> nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserApplicationPublicResourcePermissions(singletonList(resourceId), resourceAction, requestType)
243+
.map(it -> it.getOrDefault(resourceId, emptyList()))
244+
.map(it -> {
245+
if (!it.isEmpty()) {
246+
return UserPermissionOnResourceStatus.success(it.get(0));
247+
}
248+
return isAnonymousUser(userId) ? UserPermissionOnResourceStatus.anonymousUser() : UserPermissionOnResourceStatus.notInOrg();
249+
});
250+
251+
252+
Mono<UserPermissionOnResourceStatus> orgUserPermissionMono = getOrgId(resourceId)
253+
.flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId))
254+
.flatMap(orgMember -> {
255+
if (orgMember.isAdmin()) {
256+
return Mono.just(UserPermissionOnResourceStatus.success(buildAdminPermission(resourceType, resourceId, userId)));
257+
}
258+
return getAllMatchingPermissions0(userId, orgMember.getOrgId(), resourceType, Collections.singleton(resourceId), resourceAction)
259+
.map(it -> it.getOrDefault(resourceId, emptyList()))
260+
.map(permissions -> permissions.isEmpty() ? UserPermissionOnResourceStatus.notEnoughPermission()
261+
: UserPermissionOnResourceStatus.success(getMaxPermission(permissions)));
262+
})
263+
.defaultIfEmpty(UserPermissionOnResourceStatus.notInOrg());
264+
265+
return Mono.zip(publicResourcePermissionMono, nonAnonymousPublicResourcePermissionMono, orgUserPermissionMono)
266+
.map(tuple -> {
267+
UserPermissionOnResourceStatus publicResourcePermission = tuple.getT1();
268+
UserPermissionOnResourceStatus nonAnonymousPublicResourcePermission = tuple.getT2();
269+
UserPermissionOnResourceStatus orgUserPermission = tuple.getT3();
270+
if (orgUserPermission.hasPermission()) {
271+
return orgUserPermission;
272+
}
273+
if(nonAnonymousPublicResourcePermission.hasPermission()) {
274+
return nonAnonymousPublicResourcePermission;
275+
}
276+
if (publicResourcePermission.hasPermission()) {
277+
return publicResourcePermission;
278+
}
279+
return orgUserPermission;
280+
});
281+
}
215282
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import javax.validation.constraints.NotNull;
2020

2121
import org.apache.commons.collections4.CollectionUtils;
22+
import org.lowcoder.domain.application.model.ApplicationRequestType;
2223
import org.lowcoder.domain.permission.model.ResourceAction;
2324
import org.lowcoder.domain.permission.model.ResourceHolder;
2425
import org.lowcoder.domain.permission.model.ResourcePermission;
@@ -221,6 +222,14 @@ public Mono<ResourcePermission> checkAndReturnMaxPermission(String userId, Strin
221222
return resourcePermissionHandler.checkUserPermissionStatusOnResource(userId, resourceId, resourceAction);
222223
}
223224

225+
public Mono<UserPermissionOnResourceStatus> checkUserPermissionStatusOnApplication
226+
(String userId, String resourceId, ResourceAction resourceAction, ApplicationRequestType requestType) {
227+
ResourceType resourceType = resourceAction.getResourceType();
228+
var resourcePermissionHandler = getResourcePermissionHandler(resourceType);
229+
return resourcePermissionHandler.checkUserPermissionStatusOnApplication(userId, resourceId, resourceAction, requestType);
230+
}
231+
232+
224233
public Mono<Boolean> removeUserApplicationPermission(String appId, String userId) {
225234
return repository.removePermissionBy(ResourceType.APPLICATION, appId, ResourceHolder.USER, userId);
226235
}

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