From d33f51a710939a541bc96122cad86a011bd685a8 Mon Sep 17 00:00:00 2001 From: Abdul Qadir Date: Thu, 1 Feb 2024 21:06:06 +0500 Subject: [PATCH 1/3] feat: add marketplace applications handling --- .../domain/application/model/Application.java | 8 +++ .../repository/ApplicationRepository.java | 2 + .../service/ApplicationService.java | 11 ++++ .../permission/model/ResourceAction.java | 1 + .../application/ApplicationApiService.java | 10 +++- .../application/ApplicationController.java | 16 ++++++ .../api/application/ApplicationEndpoints.java | 31 +++++++++- .../application/view/ApplicationInfoView.java | 2 + .../view/ApplicationPermissionView.java | 5 ++ .../view/MarketplaceApplicationInfoView.java | 30 ++++++++++ .../lowcoder/api/home/UserHomeApiService.java | 3 + .../api/home/UserHomeApiServiceImpl.java | 57 ++++++++++++++++++- 12 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/MarketplaceApplicationInfoView.java diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java index 1c5863f9b..8144b45e2 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java @@ -39,6 +39,8 @@ public class Application extends HasIdAndAuditing { private final Map publishedApplicationDSL; private final Boolean publicToAll; + private final Boolean publicToMarketplace; + private Map editingApplicationDSL; @Transient @@ -75,6 +77,7 @@ public Application(@JsonProperty("orgId") String organizationId, @JsonProperty("applicationStatus") ApplicationStatus applicationStatus, @JsonProperty("publishedApplicationDSL") Map publishedApplicationDSL, @JsonProperty("publicToAll") Boolean publicToAll, + @JsonProperty("publicToMarketplace") Boolean publicToMarketplace, @JsonProperty("editingApplicationDSL") Map editingApplicationDSL) { this.organizationId = organizationId; this.name = name; @@ -82,6 +85,7 @@ public Application(@JsonProperty("orgId") String organizationId, this.applicationStatus = applicationStatus; this.publishedApplicationDSL = publishedApplicationDSL; this.publicToAll = publicToAll; + this.publicToMarketplace = publicToMarketplace; this.editingApplicationDSL = editingApplicationDSL; } @@ -105,6 +109,10 @@ public boolean isPublicToAll() { return BooleanUtils.toBooleanDefaultIfNull(publicToAll, false); } + public boolean isPublicToMarketplace() { + return BooleanUtils.toBooleanDefaultIfNull(publicToMarketplace, false); + } + public ApplicationQuery getQueryByViewModeAndQueryId(boolean isViewMode, String queryId) { return (isViewMode ? getLiveQueries() : getEditingQueries()) .stream() diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java index f520fe037..db842dadb 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java @@ -37,4 +37,6 @@ public interface ApplicationRepository extends ReactiveMongoRepository findByPublicToAllIsTrueAndIdIn(Collection ids); + Flux findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); + } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java index 79acb2619..c0917d2ec 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java @@ -103,6 +103,10 @@ public Flux findByOrganizationIdWithoutDsl(String organizationId) { return repository.findByOrganizationId(organizationId); } + public Flux findAllMarketplaceApps() { + return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); + } + public Mono countByOrganizationId(String orgId, ApplicationStatus applicationStatus) { return repository.countByOrganizationIdAndApplicationStatus(orgId, applicationStatus); } @@ -147,6 +151,13 @@ public Mono setApplicationPublicToAll(String applicationId, boolean pub return mongoUpsertHelper.updateById(application, applicationId); } + public Mono setApplicationPublicToMarketplace(String applicationId, boolean publicToMarketplace) { + Application application = Application.builder() + .publicToMarketplace(publicToMarketplace) + .build(); + return mongoUpsertHelper.updateById(application, applicationId); + } + @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") public Mono> getPublicApplicationIds(Collection applicationIds) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceAction.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceAction.java index b6b214990..c11257e41 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceAction.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceAction.java @@ -24,6 +24,7 @@ public enum ResourceAction { EDIT_APPLICATIONS(ResourceRole.EDITOR, ResourceType.APPLICATION), SET_APPLICATIONS_PUBLIC(ResourceRole.EDITOR, ResourceType.APPLICATION), + SET_APPLICATIONS_PUBLIC_TO_MARKETPLACE(ResourceRole.EDITOR, ResourceType.APPLICATION), // datasource action MANAGE_DATASOURCES(ResourceRole.OWNER, ResourceType.DATASOURCE), diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java index f2a538e16..cf3d68d48 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java @@ -141,7 +141,7 @@ public Mono create(CreateApplicationRequest createApplicationRe createApplicationRequest.applicationType(), NORMAL, createApplicationRequest.publishedApplicationDSL(), - false, createApplicationRequest.editingApplicationDSL()); + false, false, createApplicationRequest.editingApplicationDSL()); if (StringUtils.isBlank(application.getOrganizationId())) { return deferredError(INVALID_PARAMETER, "ORG_ID_EMPTY"); @@ -429,6 +429,7 @@ public Mono getApplicationPermissions(String applicat .creatorId(creatorId) .orgName(organization.getName()) .publicToAll(application.isPublicToAll()) + .publicToMarketplace(application.isPublicToMarketplace()) .build(); }); }); @@ -485,6 +486,7 @@ private ApplicationInfoView buildView(Application application, String role, @Nul .applicationStatus(application.getApplicationStatus()) .folderId(folderId) .publicToAll(application.isPublicToAll()) + .publicToMarketplace(application.isPublicToMarketplace()) .build(); } @@ -498,6 +500,12 @@ public Mono setApplicationPublicToAll(String applicationId, boolean pub .then(applicationService.setApplicationPublicToAll(applicationId, publicToAll)); } + public Mono setApplicationPublicToMarketplace(String applicationId, boolean publicToMarketplace) { + return checkCurrentUserApplicationPermission(applicationId, ResourceAction.SET_APPLICATIONS_PUBLIC_TO_MARKETPLACE) + .then(checkApplicationStatus(applicationId, NORMAL)) + .then(applicationService.setApplicationPublicToMarketplace(applicationId, publicToMarketplace)); + } + private Map sanitizeDsl(Map applicationDsl) { if (applicationDsl.get("queries") instanceof List queries) { List> list = queries.stream().map(this::doSanitizeQuery).toList(); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java index b080da7ba..ff37c6011 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java @@ -15,6 +15,7 @@ import org.lowcoder.api.application.view.ApplicationInfoView; import org.lowcoder.api.application.view.ApplicationPermissionView; import org.lowcoder.api.application.view.ApplicationView; +import org.lowcoder.api.application.view.MarketplaceApplicationInfoView; import org.lowcoder.api.framework.view.ResponseView; import org.lowcoder.api.home.UserHomeApiService; import org.lowcoder.api.home.UserHomepageView; @@ -127,6 +128,14 @@ public Mono>> getApplications(@RequestPar .map(ResponseView::success); } + @Override + public Mono>> getMarketplaceApplications(@RequestParam(required = false) Integer applicationType) { + ApplicationType applicationTypeEnum = applicationType == null ? null : ApplicationType.fromValue(applicationType); + return userHomeApiService.getAllMarketplaceApplications(applicationTypeEnum) + .collectList() + .map(ResponseView::success); + } + @Override public Mono> updatePermission(@PathVariable String applicationId, @PathVariable String permissionId, @@ -177,4 +186,11 @@ public Mono> setApplicationPublicToAll(@PathVariable Strin return applicationApiService.setApplicationPublicToAll(applicationId, request.publicToAll()) .map(ResponseView::success); } + + @Override + public Mono> setApplicationPublicToMarketplace(@PathVariable String applicationId, + @RequestBody ApplicationPublicToMarketplaceRequest request) { + return applicationApiService.setApplicationPublicToMarketplace(applicationId, request.publicToMarketplace()) + .map(ResponseView::success); + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java index 8417c40d0..da51dfa04 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java @@ -10,6 +10,7 @@ import org.lowcoder.api.application.view.ApplicationInfoView; import org.lowcoder.api.application.view.ApplicationPermissionView; import org.lowcoder.api.application.view.ApplicationView; +import org.lowcoder.api.application.view.MarketplaceApplicationInfoView; import org.lowcoder.api.framework.view.ResponseView; import org.lowcoder.api.home.UserHomepageView; import org.lowcoder.domain.application.model.Application; @@ -149,6 +150,15 @@ public Mono>> getApplications(@RequestPar @RequestParam(required = false) ApplicationStatus applicationStatus, @RequestParam(defaultValue = "true") boolean withContainerSize); + @Operation( + tags = TAG_APPLICATION_MANAGEMENT, + operationId = "listMarketplaceApplications", + summary = "List marketplace Applications", + description = "Retrieve a list of Lowcoder Applications that are published to the marketplace" + ) + @GetMapping("/marketplace-apps") + public Mono>> getMarketplaceApplications(@RequestParam(required = false) Integer applicationType); + @Operation( tags = TAG_APPLICATION_PERMISSIONS, operationId = "updateApplicationPermissions", @@ -202,8 +212,18 @@ public Mono> grantPermission( public Mono> setApplicationPublicToAll(@PathVariable String applicationId, @RequestBody ApplicationPublicToAllRequest request); - - public record BatchAddPermissionRequest(String role, Set userIds, Set groupIds) { + @Operation( + tags = TAG_APPLICATION_MANAGEMENT, + operationId = "setApplicationAsPublicToMarketplace", + summary = "Set Application as publicly available on marketplace but to only logged in users", + description = "Set a Lowcoder Application identified by its ID as publicly available on marketplace but to only logged in users." + ) + @PutMapping("/{applicationId}/public-to-marketplace") + public Mono> setApplicationPublicToMarketplace(@PathVariable String applicationId, + @RequestBody ApplicationPublicToMarketplaceRequest request); + + + public record BatchAddPermissionRequest(String role, Set userIds, Set groupIds) { } public record ApplicationPublicToAllRequest(Boolean publicToAll) { @@ -213,6 +233,13 @@ public Boolean publicToAll() { } } + public record ApplicationPublicToMarketplaceRequest(Boolean publicToMarketplace) { + @Override + public Boolean publicToMarketplace() { + return BooleanUtils.isTrue(publicToMarketplace); + } + } + public record UpdatePermissionRequest(String role) { } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationInfoView.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationInfoView.java index 62cc9258f..66eda1871 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationInfoView.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationInfoView.java @@ -38,6 +38,8 @@ public class ApplicationInfoView { private final boolean publicToAll; + private final boolean publicToMarketplace; + public long getLastViewTime() { return lastViewTime == null ? 0 : lastViewTime.toEpochMilli(); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationPermissionView.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationPermissionView.java index 64d8b1038..ec17670bf 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationPermissionView.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationPermissionView.java @@ -8,8 +8,13 @@ public class ApplicationPermissionView extends CommonPermissionView { private boolean publicToAll; + private boolean publicToMarketplace; public boolean isPublicToAll() { return publicToAll; } + + public boolean isPublicToMarketplace() { + return publicToMarketplace; + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/MarketplaceApplicationInfoView.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/MarketplaceApplicationInfoView.java new file mode 100644 index 000000000..b45ffd499 --- /dev/null +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/MarketplaceApplicationInfoView.java @@ -0,0 +1,30 @@ +package org.lowcoder.api.application.view; + +import lombok.Builder; +import lombok.Getter; +import org.lowcoder.domain.application.model.ApplicationStatus; + +@Builder +@Getter +public class MarketplaceApplicationInfoView { + + // org details + private final String orgId; + private final String orgName; + + // creator info + private final String creatorEmail; + + // App details + private final String applicationId; + private final String name; + private final long createAt; + private final String createBy; + /** + * @see org.lowcoder.domain.application.model.ApplicationType + */ + private final int applicationType; + private final ApplicationStatus applicationStatus; + + +} diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiService.java index ddcfff54c..5f194fcc4 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiService.java @@ -2,6 +2,7 @@ import javax.annotation.Nullable; +import org.lowcoder.api.application.view.MarketplaceApplicationInfoView; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -22,4 +23,6 @@ public interface UserHomeApiService { Flux getAllAuthorisedApplications4CurrentOrgMember(@Nullable ApplicationType applicationType, @Nullable ApplicationStatus applicationStatus, boolean withContainerSize); + + public Flux getAllMarketplaceApplications(@Nullable ApplicationType applicationType); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiServiceImpl.java index f08307647..6d7aff678 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/UserHomeApiServiceImpl.java @@ -18,6 +18,7 @@ import org.apache.commons.lang3.StringUtils; import org.lowcoder.api.application.view.ApplicationInfoView; import org.lowcoder.api.application.view.ApplicationInfoView.ApplicationInfoViewBuilder; +import org.lowcoder.api.application.view.MarketplaceApplicationInfoView; import org.lowcoder.api.usermanagement.OrgDevChecker; import org.lowcoder.api.usermanagement.view.OrgAndVisitorRoleView; import org.lowcoder.api.usermanagement.view.UserProfileView; @@ -256,6 +257,59 @@ public Flux getAllAuthorisedApplications4CurrentOrgMember(@ }); } + @Override + public Flux getAllMarketplaceApplications(@Nullable ApplicationType applicationType) { + + return sessionUserService.getVisitorOrgMemberCache() + .flatMapMany(orgMember -> { + // application flux + Flux applicationFlux = Flux.defer(() -> applicationService.findAllMarketplaceApps()) + .filter(application -> isNull(applicationType) || application.getApplicationType() == applicationType.getValue()) + .cache(); + + // user map + Mono> userMapMono = applicationFlux + .flatMap(application -> emptyIfNull(application.getCreatedBy())) + .collectList() + .flatMap(creatorIds -> userService.getByIds(creatorIds)) + .cache(); + + // org map + Mono> orgMapMono = applicationFlux + .flatMap(application -> emptyIfNull(application.getOrganizationId())) + .collectList() + .flatMap(orgIds -> organizationService.getByIds(orgIds) + .collectList() + .map(it -> it.stream().collect(Collectors.toMap(Organization::getId, Function.identity()))) + ) + .cache(); + + + return applicationFlux + .flatMap(application -> Mono.zip(Mono.just(application), userMapMono, orgMapMono)) + .map(tuple -> { + // build view + Application application = tuple.getT1(); + Map userMap = tuple.getT2(); + Map orgMap = tuple.getT3(); + return MarketplaceApplicationInfoView.builder() + .applicationId(application.getId()) + .name(application.getName()) + .applicationType(application.getApplicationType()) + .applicationStatus(application.getApplicationStatus()) + .orgId(application.getOrganizationId()) + .orgName(orgMap.get(application.getOrganizationId()).getName()) + .creatorEmail(Optional.ofNullable(userMap.get(application.getCreatedBy())) + .map(User::getName) + .orElse("")) + .createAt(application.getCreatedAt().toEpochMilli()) + .createBy(application.getCreatedBy()) + .build(); + }); + + }); + } + private ApplicationInfoView buildView(Application application, ResourceRole maxRole, Map userMap, @Nullable Instant lastViewTime, boolean withContainerSize) { ApplicationInfoViewBuilder applicationInfoViewBuilder = ApplicationInfoView.builder() @@ -271,7 +325,8 @@ private ApplicationInfoView buildView(Application application, ResourceRole maxR .applicationStatus(application.getApplicationStatus()) .lastModifyTime(application.getUpdatedAt()) .lastViewTime(lastViewTime) - .publicToAll(application.isPublicToAll()); + .publicToAll(application.isPublicToAll()) + .publicToMarketplace(application.isPublicToMarketplace()); if (withContainerSize) { return applicationInfoViewBuilder .containerSize(application.getLiveContainerSize()) From 55fbff9c8da4fd9796372cc168eb03a9888ea8d9 Mon Sep 17 00:00:00 2001 From: Abdul Qadir Date: Tue, 6 Feb 2024 21:37:58 +0500 Subject: [PATCH 2/3] Add handling for PTM apps --- .../repository/ApplicationRepository.java | 2 +- .../service/ApplicationService.java | 5 +++-- .../service/ApplicationPermissionHandler.java | 17 ++++++++++++++- .../service/DatasourcePermissionHandler.java | 6 +++++- .../service/ResourcePermissionHandler.java | 21 +++++++++++++++++-- .../service/ResourcePermissionService.java | 3 ++- .../application/ApplicationController.java | 8 +++++++ .../api/application/ApplicationEndpoints.java | 9 ++++++++ 8 files changed, 63 insertions(+), 8 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java index db842dadb..cf23dcb50 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java @@ -35,7 +35,7 @@ public interface ApplicationRepository extends ReactiveMongoRepository findByIdIn(List ids); @Query(fields = "{_id : 1}") - Flux findByPublicToAllIsTrueAndIdIn(Collection ids); + Flux findByPublicToAllIsTrueAndPublicToMarketplaceAndIdIn(Collection ids, Boolean publicToMarketplace); Flux findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java index c0917d2ec..abcfb6eab 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java @@ -160,9 +160,10 @@ public Mono setApplicationPublicToMarketplace(String applicationId, boo @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPublicApplicationIds(Collection applicationIds) { - return repository.findByPublicToAllIsTrueAndIdIn(applicationIds) + public Mono> getPublicApplicationIds(Collection applicationIds, Boolean isAnonymous) { + return repository.findByPublicToAllIsTrueAndPublicToMarketplaceAndIdIn(applicationIds, !isAnonymous) .map(HasIdAndAuditing::getId) .collect(Collectors.toSet()); + } } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java index 8ab5c7c49..d93585bb0 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ApplicationPermissionHandler.java @@ -46,7 +46,22 @@ protected Mono>> getAnonymousUserPermission } Set applicationIds = newHashSet(resourceIds); - return Mono.zip(applicationService.getPublicApplicationIds(applicationIds), + return Mono.zip(applicationService.getPublicApplicationIds(applicationIds, Boolean.TRUE), + templateSolution.getTemplateApplicationIds(applicationIds)) + .map(tuple -> { + Set publicAppIds = tuple.getT1(); + Set templateAppIds = tuple.getT2(); + return collectMap(union(publicAppIds, templateAppIds), identity(), this::getAnonymousUserPermission); + }); + } + + // This is for PTM apps that are public but only available to logged-in users + @Override + protected Mono>> getNonAnonymousUserPublicResourcePermissions + (Collection resourceIds, ResourceAction resourceAction) { + + Set applicationIds = newHashSet(resourceIds); + return Mono.zip(applicationService.getPublicApplicationIds(applicationIds, Boolean.FALSE), templateSolution.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java index 59be368c7..130ee8033 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/DatasourcePermissionHandler.java @@ -1,7 +1,6 @@ package org.lowcoder.domain.permission.service; import static org.lowcoder.domain.permission.model.ResourceHolder.USER; -import static org.lowcoder.sdk.constants.Authentication.ANONYMOUS_USER_ID; import java.util.Collection; import java.util.Collections; @@ -39,6 +38,11 @@ protected Mono>> getAnonymousUserPermission return Mono.just(Collections.emptyMap()); } + @Override + protected Mono>> getNonAnonymousUserPublicResourcePermissions(Collection resourceIds, ResourceAction resourceAction) { + return Mono.just(Collections.emptyMap()); + } + @Override protected Mono getOrgId(String resourceId) { return datasourceService.getById(resourceId) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java index 6ad1ccdcc..762e9bcb1 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java @@ -94,6 +94,16 @@ public Mono checkUserPermissionStatusOnResource( return publicResourcePermissionMono; } + Mono nonAnonymousPublicResourcePermissionMono = getNonAnonymousUserPublicResourcePermissions(singletonList(resourceId), resourceAction) + .map(it -> it.getOrDefault(resourceId, emptyList())) + .map(it -> { + if (!it.isEmpty()) { + return UserPermissionOnResourceStatus.success(it.get(0)); + } + return isAnonymousUser(userId) ? UserPermissionOnResourceStatus.anonymousUser() : UserPermissionOnResourceStatus.notInOrg(); + }); + + Mono orgUserPermissionMono = getOrgId(resourceId) .flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId)) .flatMap(orgMember -> { @@ -107,13 +117,17 @@ public Mono checkUserPermissionStatusOnResource( }) .defaultIfEmpty(UserPermissionOnResourceStatus.notInOrg()); - return Mono.zip(publicResourcePermissionMono, orgUserPermissionMono) + return Mono.zip(publicResourcePermissionMono, nonAnonymousPublicResourcePermissionMono, orgUserPermissionMono) .map(tuple -> { UserPermissionOnResourceStatus publicResourcePermission = tuple.getT1(); - UserPermissionOnResourceStatus orgUserPermission = tuple.getT2(); + UserPermissionOnResourceStatus nonAnonymousPublicResourcePermission = tuple.getT2(); + UserPermissionOnResourceStatus orgUserPermission = tuple.getT3(); if (orgUserPermission.hasPermission()) { return orgUserPermission; } + if(nonAnonymousPublicResourcePermission.hasPermission()) { + return nonAnonymousPublicResourcePermission; + } if (publicResourcePermission.hasPermission()) { return publicResourcePermission; } @@ -132,6 +146,9 @@ private ResourcePermission getMaxPermission(List permissions protected abstract Mono>> getAnonymousUserPermissions(Collection resourceIds, ResourceAction resourceAction); + protected abstract Mono>> getNonAnonymousUserPublicResourcePermissions + (Collection resourceIds, ResourceAction resourceAction); + private Mono>> getAllMatchingPermissions0(String userId, String orgId, ResourceType resourceType, Collection resourceIds, ResourceAction resourceAction) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionService.java index 856559110..9cdba0e30 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionService.java @@ -214,7 +214,8 @@ public Mono checkAndReturnMaxPermission(String userId, Strin }); } - public Mono checkUserPermissionStatusOnResource(String userId, String resourceId, ResourceAction resourceAction) { + public Mono checkUserPermissionStatusOnResource + (String userId, String resourceId, ResourceAction resourceAction) { ResourceType resourceType = resourceAction.getResourceType(); var resourcePermissionHandler = getResourcePermissionHandler(resourceType); return resourcePermissionHandler.checkUserPermissionStatusOnResource(userId, resourceId, resourceAction); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java index ff37c6011..a5c29b132 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java @@ -97,6 +97,14 @@ public Mono> getPublishedApplication(@PathVariable .map(ResponseView::success); } + @Override + public Mono> getPublishedMarketPlaceApplication(@PathVariable String applicationId) { + return applicationApiService.getPublishedApplication(applicationId) + .delayUntil(applicationView -> applicationApiService.updateUserApplicationLastViewTime(applicationId)) + .delayUntil(applicationView -> businessEventPublisher.publishApplicationCommonEvent(applicationView, VIEW)) + .map(ResponseView::success); + } + @Override public Mono> update(@PathVariable String applicationId, @RequestBody Application newApplication) { diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java index da51dfa04..0d03f608f 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java @@ -111,6 +111,15 @@ public interface ApplicationEndpoints @GetMapping("/{applicationId}/view") public Mono> getPublishedApplication(@PathVariable String applicationId); + @Operation( + tags = TAG_APPLICATION_MANAGEMENT, + operationId = "getMarketplaceApplicationDataInViewMode", + summary = "Get Marketplace Application data in view mode", + description = "Retrieve the DSL data of a Lowcoder Application in view-mode by its ID for the marketplace." + ) + @GetMapping("/{applicationId}/view_marketplace") + public Mono> getPublishedMarketPlaceApplication(@PathVariable String applicationId); + @Operation( tags = TAG_APPLICATION_MANAGEMENT, operationId = "updateApplication", From ff6b08f253e622d27e152c16f8e77bedf6c937ac Mon Sep 17 00:00:00 2001 From: Abdul Qadir Date: Wed, 7 Feb 2024 20:28:02 +0500 Subject: [PATCH 3/3] Finalize handling for ptm apps --- .../domain/application/repository/ApplicationRepository.java | 2 +- .../lowcoder/domain/application/service/ApplicationService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java index cf23dcb50..8c018d71e 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java @@ -35,7 +35,7 @@ public interface ApplicationRepository extends ReactiveMongoRepository findByIdIn(List ids); @Query(fields = "{_id : 1}") - Flux findByPublicToAllIsTrueAndPublicToMarketplaceAndIdIn(Collection ids, Boolean publicToMarketplace); + Flux findByPublicToAllIsTrueAndPublicToMarketplaceIsAndIdIn(Boolean publicToMarketplace, Collection ids); Flux findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java index abcfb6eab..ec6997e09 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java @@ -161,7 +161,7 @@ public Mono setApplicationPublicToMarketplace(String applicationId, boo @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") public Mono> getPublicApplicationIds(Collection applicationIds, Boolean isAnonymous) { - return repository.findByPublicToAllIsTrueAndPublicToMarketplaceAndIdIn(applicationIds, !isAnonymous) + return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsAndIdIn(!isAnonymous, applicationIds) .map(HasIdAndAuditing::getId) .collect(Collectors.toSet());