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..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 @@ -164,16 +164,62 @@ public Map getEditingApplicationDSL() { return dsl; } - public String getCategory() { - if(editingApplicationDSL == null || editingApplicationDSL.get("settings") == null) return ""; - Object settingsObject = editingApplicationDSL.get("settings"); - if (settingsObject instanceof Map) { - @SuppressWarnings("unchecked") - Map settings = (Map) editingApplicationDSL.get("settings"); - return (String) settings.get("category"); - } 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 ""; + } + } + ).onErrorReturn(""); } public Map getEditingApplicationDSLOrNull() {return editingApplicationDSL; } 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..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 @@ -41,6 +41,20 @@ 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; + @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 afa08b036..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,33 +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()) - .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()); + }); } }