From 8f513810270906020ba3bfcf05d9f982d7b30a3e Mon Sep 17 00:00:00 2001 From: Thomasr Date: Thu, 5 Dec 2024 13:44:45 -0500 Subject: [PATCH 1/3] #923: Add title, description, category to the application list endpoint --- .../domain/application/model/Application.java | 33 +++++++++++++++++-- .../repository/ApplicationRepository.java | 6 ++-- .../application/view/ApplicationInfoView.java | 7 ++++ .../api/home/UserHomeApiServiceImpl.java | 3 ++ 4 files changed, 43 insertions(+), 6 deletions(-) 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 0dc3e3043..4760dbfdf 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 @@ -165,17 +165,44 @@ public Map getEditingApplicationDSL() { } public String getCategory() { - if(editingApplicationDSL == null || editingApplicationDSL.get("settings") == null) return ""; - Object settingsObject = editingApplicationDSL.get("settings"); + var liveDSL = getLiveApplicationDsl(); + if(liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); if (settingsObject instanceof Map) { @SuppressWarnings("unchecked") - Map settings = (Map) editingApplicationDSL.get("settings"); + Map settings = (Map) liveDSL.get("settings"); return (String) settings.get("category"); } else { return ""; } } + public String getTitle() { + var liveDSL = getLiveApplicationDsl(); + if(liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("title"); + } else { + return ""; + } + } + + public String getDescription() { + var liveDSL = getLiveApplicationDsl(); + if(liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("description"); + } else { + return ""; + } + } + public Map getEditingApplicationDSLOrNull() {return editingApplicationDSL; } public Mono getLiveContainerSize(ApplicationRecordService applicationRecordService) { 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 9197d6bb4..5cac07fdc 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 @@ -17,16 +17,16 @@ public interface ApplicationRepository extends ReactiveMongoRepository, CustomApplicationRepository { // publishedApplicationDSL : 0 -> excludes publishedApplicationDSL from the return - @Aggregation(pipeline = {"{ $match: { organizationId: ?0 } }", "{ $project: { 'editingApplicationDSL.settings.category': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) + @Aggregation(pipeline = {"{ $match: { organizationId: ?0 } }", "{ $project: { 'editingApplicationDSL.settings': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) Flux findByOrganizationId(String organizationId); @Override @Nonnull - @Aggregation(pipeline = {"{ $match: { _id: ?0 } }", "{ $project: { 'editingApplicationDSL.settings.category': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) + @Aggregation(pipeline = {"{ $match: { _id: ?0 } }", "{ $project: { 'editingApplicationDSL.settings': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) Mono findById(@Nonnull String id); - @Aggregation(pipeline = {"{ $match: { gid: ?0 } }", "{ $project: { 'editingApplicationDSL.settings.category': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) + @Aggregation(pipeline = {"{ $match: { gid: ?0 } }", "{ $project: { 'editingApplicationDSL.settings': 1, _id: 1, gid: 1, organizationId: 1, name: 1, applicationType: 1, applicationStatus: 1, publicToAll: 1, publicToMarketplace: 1, agencyProfile: 1, editingUserId: 1, lastEditedAt: 1, createdAt: 1, updatedAt: 1, createdBy: 1, modifiedBy: 1, _class: 1}}"}) Flux findByGid(@Nonnull String gid); Mono countByOrganizationIdAndApplicationStatus(String organizationId, ApplicationStatus applicationStatus); 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 82fec6a07..5270625ab 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 @@ -41,6 +41,13 @@ public class ApplicationInfoView { private final String editingUserId; + @JsonInclude(Include.NON_NULL) + private final String title; + @JsonInclude(Include.NON_NULL) + private final String description; + @JsonInclude(Include.NON_NULL) + private final String category; + public long getLastViewTime() { return lastViewTime == null ? 0 : lastViewTime.toEpochMilli(); } 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 afa08b036..5e019199b 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 @@ -568,6 +568,9 @@ private Mono buildView(Application application, ResourceRol .applicationGid(application.getGid()) .orgId(application.getOrganizationId()) .name(application.getName()) + .title(application.getTitle()) + .description(application.getDescription()) + .category(application.getCategory()) .createBy(Optional.ofNullable(userMap.get(application.getCreatedBy())) .map(User::getName) .orElse("")) From c00d60cd9bae698782eb75bc7d343c590e2aba8a Mon Sep 17 00:00:00 2001 From: Thomasr Date: Mon, 16 Dec 2024 14:18:24 -0500 Subject: [PATCH 2/3] Add icon, published, publishedVersion, lastPublishedTime field to the application list api --- .../domain/application/model/Application.java | 93 +++++++++++-------- .../application/view/ApplicationInfoView.java | 7 ++ .../api/home/UserHomeApiServiceImpl.java | 87 ++++++++++------- 3 files changed, 115 insertions(+), 72 deletions(-) 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 4760dbfdf..883e4b9d3 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 @@ -164,43 +164,62 @@ public Map getEditingApplicationDSL() { return dsl; } - public String getCategory() { - var liveDSL = getLiveApplicationDsl(); - if(liveDSL == null || liveDSL.get("settings") == null) return ""; - Object settingsObject = liveDSL.get("settings"); - if (settingsObject instanceof Map) { - @SuppressWarnings("unchecked") - Map settings = (Map) liveDSL.get("settings"); - return (String) settings.get("category"); - } else { - return ""; - } - } - - public String getTitle() { - var liveDSL = getLiveApplicationDsl(); - if(liveDSL == null || liveDSL.get("settings") == null) return ""; - Object settingsObject = liveDSL.get("settings"); - if (settingsObject instanceof Map) { - @SuppressWarnings("unchecked") - Map settings = (Map) liveDSL.get("settings"); - return (String) settings.get("title"); - } else { - return ""; - } - } - - public String getDescription() { - var liveDSL = getLiveApplicationDsl(); - if(liveDSL == null || liveDSL.get("settings") == null) return ""; - Object settingsObject = liveDSL.get("settings"); - if (settingsObject instanceof Map) { - @SuppressWarnings("unchecked") - Map settings = (Map) liveDSL.get("settings"); - return (String) settings.get("description"); - } else { - return ""; - } + public Mono getCategory(ApplicationRecordService applicationRecordService) { + return getLiveApplicationDsl(applicationRecordService).map(liveDSL -> { + if (liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("category"); + } else { + return ""; + } + }); + } + + public Mono getTitle(ApplicationRecordService applicationRecordService) { + return getLiveApplicationDsl(applicationRecordService).map(liveDSL -> { + if (liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("title"); + } else { + return ""; + } + }); + } + + public Mono getDescription(ApplicationRecordService applicationRecordService) { + return getLiveApplicationDsl(applicationRecordService).map(liveDSL -> { + if (liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("description"); + } else { + return ""; + } + } + ); + } + + public Mono getIcon(ApplicationRecordService applicationRecordService) { + return getLiveApplicationDsl(applicationRecordService).map(liveDSL -> { + if (liveDSL == null || liveDSL.get("settings") == null) return ""; + Object settingsObject = liveDSL.get("settings"); + if (settingsObject instanceof Map) { + @SuppressWarnings("unchecked") + Map settings = (Map) liveDSL.get("settings"); + return (String) settings.get("icon"); + } else { + return ""; + } + } + ); } public Map getEditingApplicationDSLOrNull() {return editingApplicationDSL; } 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 5270625ab..c8d8bfd1b 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 @@ -47,6 +47,13 @@ public class ApplicationInfoView { private final String description; @JsonInclude(Include.NON_NULL) private final String category; + @JsonInclude(Include.NON_NULL) + private final String icon; + private final boolean published; + @JsonInclude(Include.NON_NULL) + private final String publishedVersion; + @JsonInclude(Include.NON_NULL) + private final Instant lastPublishedTime; public long getLastViewTime() { return lastViewTime == null ? 0 : lastViewTime.toEpochMilli(); 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 5e019199b..ce20a0c17 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 @@ -12,6 +12,7 @@ import org.lowcoder.api.usermanagement.view.OrgAndVisitorRoleView; import org.lowcoder.api.usermanagement.view.UserProfileView; import org.lowcoder.domain.application.model.Application; +import org.lowcoder.domain.application.model.ApplicationRecord; import org.lowcoder.domain.application.model.ApplicationStatus; import org.lowcoder.domain.application.model.ApplicationType; import org.lowcoder.domain.application.service.ApplicationRecordService; @@ -35,7 +36,9 @@ import org.lowcoder.domain.user.service.UserService; import org.lowcoder.domain.user.service.UserStatusService; import org.lowcoder.infra.util.NetworkUtils; +import org.lowcoder.infra.util.TupleUtils; import org.lowcoder.sdk.config.CommonConfig; +import org.lowcoder.sdk.models.VersionedModel; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; @@ -203,11 +206,13 @@ public Flux getAllAuthorisedApplications4CurrentOrgMember(@ return applicationService.findByOrganizationIdWithDsl(currentOrgId); } return applicationService.findByOrganizationIdWithoutDsl(currentOrgId); - }) - .filter(application -> (isNull(applicationType) || applicationType == ApplicationType.ALL || application.getApplicationType() == applicationType.getValue()) - && (isNull(applicationStatus) || application.getApplicationStatus() == applicationStatus) - && (isNull(name) || StringUtils.containsIgnoreCase(application.getName(), name)) - && (isNull(category) || StringUtils.containsIgnoreCase(application.getCategory(), category))) + }).flatMap(application -> application.getCategory(applicationRecordService) + .map(categoryValue -> Map.entry(application, categoryValue))) + .filter(entry -> (isNull(applicationType) || applicationType == ApplicationType.ALL || entry.getKey().getApplicationType() == applicationType.getValue()) + && (isNull(applicationStatus) || entry.getKey().getApplicationStatus() == applicationStatus) + && (isNull(name) || StringUtils.containsIgnoreCase(entry.getKey().getName(), name)) + && (isNull(category) || StringUtils.containsIgnoreCase(entry.getValue(), category))) + .map(Map.Entry::getKey) .cache() .collectList() .flatMapIterable(Function.identity()); @@ -563,36 +568,48 @@ public Flux getAllAgencyProfileBundles() { private Mono buildView(Application application, ResourceRole maxRole, Map userMap, @Nullable Instant lastViewTime, Long bundlePosition, boolean withContainerSize) { - ApplicationInfoViewBuilder applicationInfoViewBuilder = ApplicationInfoView.builder() - .applicationId(application.getId()) - .applicationGid(application.getGid()) - .orgId(application.getOrganizationId()) - .name(application.getName()) - .title(application.getTitle()) - .description(application.getDescription()) - .category(application.getCategory()) - .createBy(Optional.ofNullable(userMap.get(application.getCreatedBy())) - .map(User::getName) - .orElse("")) - .createAt(application.getCreatedAt().toEpochMilli()) - .role(maxRole.getValue()) - .applicationType(application.getApplicationType()) - .applicationStatus(application.getApplicationStatus()) - .lastModifyTime(application.getUpdatedAt()) - .lastViewTime(lastViewTime) - .lastEditedAt(application.getLastEditedAt()) - .publicToAll(application.isPublicToAll()) - .publicToMarketplace(application.isPublicToMarketplace()) - .agencyProfile(application.agencyProfile()); - if (withContainerSize) { - return application.getLiveContainerSize(applicationRecordService).map(size -> applicationInfoViewBuilder - .containerSize(size) - .build()) - .switchIfEmpty(Mono.just(applicationInfoViewBuilder - .containerSize(null) - .build())); - } - return Mono.just(applicationInfoViewBuilder.build()); + return application.getTitle(applicationRecordService) + .zipWith(application.getDescription(applicationRecordService)) + .zipWith(application.getCategory(applicationRecordService), TupleUtils::merge) + .zipWith(application.getIcon(applicationRecordService), TupleUtils::merge) + .zipWith(applicationRecordService.getLatestRecordByApplicationId(application.getId()).map(Optional::of).switchIfEmpty(Mono.just(Optional.empty())), TupleUtils::merge) + .flatMap(tuple -> { + Optional lastAppRecord = tuple.getT5(); + ApplicationInfoView.ApplicationInfoViewBuilder applicationInfoViewBuilder = ApplicationInfoView.builder() + .applicationId(application.getId()) + .applicationGid(application.getGid()) + .orgId(application.getOrganizationId()) + .name(application.getName()) + .title(tuple.getT1()) + .description(tuple.getT2()) + .category(tuple.getT3()) + .icon(tuple.getT4()) + .published(lastAppRecord.isPresent()) + .publishedVersion(lastAppRecord.map(ApplicationRecord::version).orElse(null)) + .lastPublishedTime(lastAppRecord.map(ApplicationRecord::getCreatedAt).orElse(null)) + .createBy(Optional.ofNullable(userMap.get(application.getCreatedBy())) + .map(User::getName) + .orElse("")) + .createAt(application.getCreatedAt().toEpochMilli()) + .role(maxRole.getValue()) + .applicationType(application.getApplicationType()) + .applicationStatus(application.getApplicationStatus()) + .lastModifyTime(application.getUpdatedAt()) + .lastViewTime(lastViewTime) + .lastEditedAt(application.getLastEditedAt()) + .publicToAll(application.isPublicToAll()) + .publicToMarketplace(application.isPublicToMarketplace()) + .agencyProfile(application.agencyProfile()); + if (withContainerSize) { + return application.getLiveContainerSize(applicationRecordService).map(size -> applicationInfoViewBuilder + .containerSize(size) + .build()) + .switchIfEmpty(Mono.just(applicationInfoViewBuilder + .containerSize(null) + .build())); + } + return Mono.just(applicationInfoViewBuilder.build()); + }); } } From a97deef5bda4aab964a71b92409858033862ccb7 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Mon, 16 Dec 2024 14:29:04 -0500 Subject: [PATCH 3/3] null error on map --- .../java/org/lowcoder/domain/application/model/Application.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 883e4b9d3..0c7d9aae0 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 @@ -219,7 +219,7 @@ public Mono getIcon(ApplicationRecordService applicationRecordService) { return ""; } } - ); + ).onErrorReturn(""); } public Map getEditingApplicationDSLOrNull() {return editingApplicationDSL; }