diff --git a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/AbstractEvent.java b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/AbstractEvent.java index 7f96689f5..532ad47fc 100644 --- a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/AbstractEvent.java +++ b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/AbstractEvent.java @@ -1,5 +1,6 @@ package org.lowcoder.infra.event; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Getter; import lombok.Setter; import lombok.experimental.SuperBuilder; @@ -57,7 +58,16 @@ public void populateDetails(ContextView contextView) { try { f.setAccessible(Boolean.TRUE); value = f.get(this); - details.put(f.getName(), value); + JsonInclude jsonInclude = f.getAnnotation(JsonInclude.class); + if (jsonInclude != null && jsonInclude.value() == JsonInclude.Include.NON_NULL) { + // Include only if value is not null + if (value != null) { + details.put(f.getName(), value); + } + } else { + // Include regardless of value + details.put(f.getName(), value); + } } catch (Exception e) { } diff --git a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/ApplicationCommonEvent.java b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/ApplicationCommonEvent.java index a53879bfe..c9a652e25 100644 --- a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/ApplicationCommonEvent.java +++ b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/ApplicationCommonEvent.java @@ -1,6 +1,7 @@ package org.lowcoder.infra.event; +import com.fasterxml.jackson.annotation.JsonInclude; import jakarta.annotation.Nullable; import lombok.Getter; import lombok.experimental.SuperBuilder; @@ -18,20 +19,33 @@ public class ApplicationCommonEvent extends AbstractEvent { private final String applicationDescription; private final EventType type; @Nullable + @JsonInclude(JsonInclude.Include.NON_NULL) private final String folderId; @Nullable + @JsonInclude(JsonInclude.Include.NON_NULL) private final String folderName; @Nullable + @JsonInclude(JsonInclude.Include.NON_NULL) private final String oldFolderId; @Nullable + @JsonInclude(JsonInclude.Include.NON_NULL) private final String oldFolderName; + @JsonInclude(JsonInclude.Include.NON_NULL) private final String permissionId; + @JsonInclude(JsonInclude.Include.NON_NULL) private final String role; + @JsonInclude(JsonInclude.Include.NON_NULL) private final Set userIds; + @JsonInclude(JsonInclude.Include.NON_NULL) private final Set groupIds; + @JsonInclude(JsonInclude.Include.NON_NULL) private final String shareType; + @JsonInclude(JsonInclude.Include.NON_NULL) private final String tag; + @JsonInclude(JsonInclude.Include.NON_NULL) private final String commitMessage; + @JsonInclude(JsonInclude.Include.NON_NULL) + private final Object sharingDetails; @Override public EventType getEventType() { diff --git a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/BundleCommonEvent.java b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/BundleCommonEvent.java new file mode 100644 index 000000000..312f9cc54 --- /dev/null +++ b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/BundleCommonEvent.java @@ -0,0 +1,31 @@ +package org.lowcoder.infra.event; + + +import jakarta.annotation.Nullable; +import lombok.Getter; +import lombok.experimental.SuperBuilder; + +@Getter +@SuperBuilder +public class BundleCommonEvent extends AbstractEvent { + + private final String bundleId; + private final String bundleGid; + private final String bundleName; + private final String bundleCategory; + private final String bundleDescription; + private final EventType type; + @Nullable + private final String folderId; + @Nullable + private final String folderName; + @Nullable + private final String oldFolderId; + @Nullable + private final String oldFolderName; + + @Override + public EventType getEventType() { + return type; + } +} 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 9962783cf..a32c1dd0f 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 @@ -270,7 +270,8 @@ public Mono> setApplicationPublicToAll(@PathVariable Strin @RequestBody ApplicationPublicToAllRequest request) { return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.setApplicationPublicToAll(appId, request.publicToAll()) - .delayUntil(__ -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToAll")) + .delayUntil(__ -> applicationApiService.getApplicationPermissions(appId) + .flatMap(applicationPermissionView -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToAll", applicationPermissionView))) .map(ResponseView::success)); } @@ -279,7 +280,8 @@ public Mono> setApplicationPublicToMarketplace(@PathVariab @RequestBody ApplicationPublicToMarketplaceRequest request) { return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.setApplicationPublicToMarketplace(appId, request) - .delayUntil(__ -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToMarketplace")) + .delayUntil(__ -> applicationApiService.getApplicationPermissions(appId) + .flatMap(applicationPermissionView -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToMarketplace", applicationPermissionView))) .map(ResponseView::success)); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java index bc156b4d3..5e6d3ff68 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java @@ -1,7 +1,6 @@ package org.lowcoder.api.bundle; import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.NotNull; import org.lowcoder.api.bundle.view.BundleInfoView; import org.lowcoder.api.bundle.view.BundlePermissionView; import org.lowcoder.api.bundle.view.MarketplaceBundleInfoView; @@ -20,12 +19,12 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; import static org.lowcoder.api.util.Pagination.fluxToPageResponseView; +import static org.lowcoder.plugin.api.event.LowcoderEvent.EventType.*; import static org.lowcoder.sdk.exception.BizError.INVALID_PARAMETER; import static org.lowcoder.sdk.util.ExceptionUtils.ofError; @@ -43,8 +42,7 @@ public class BundleController implements BundleEndpoints @Override public Mono> create(@RequestBody CreateBundleRequest bundle) { return bundleApiService.create(bundle) - //TODO [thomasr]: add new method to BusinessEventPublisher(jar file) -// .delayUntil(f -> businessEventPublisher.publishBundleCommonEvent(f.getBundleId(), f.getName(), EventType.BUNDLE_CREATE)) + .delayUntil(f -> businessEventPublisher.publishBundleCommonEvent(f, BUNDLE_CREATE)) .map(ResponseView::success); } @@ -52,7 +50,23 @@ public Mono> create(@RequestBody CreateBundleReques public Mono> delete(@PathVariable("id") String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.delete(objectId) -// .delayUntil(f -> businessEventPublisher.publishBundleCommonEvent(f.getId(), f.getName(), EventType.BUNDLE_DELETE)) + .delayUntil(f -> businessEventPublisher.publishBundleCommonEvent( + BundleInfoView.builder() + .bundleGid(f.getGid()) + .editingBundleDSL(f.getEditingBundleDSL()) + .image(f.getImage()) + .title(f.getTitle()) + .description(f.getDescription()) + .name(f.getName()) + .publicToMarketplace(f.isPublicToMarketplace()) + .publicToAll(f.isPublicToAll()) + .agencyProfile(f.agencyProfile()) + .createTime(f.getCreatedAt()) + .createBy(f.getCreatedBy()) + .createAt(f.getCreatedAt().toEpochMilli()) + .publishedBundleDSL(f.getPublishedBundleDSL()) + .category(f.getCategory()) + .build(), BUNDLE_DELETE)) .then(Mono.fromSupplier(() -> ResponseView.success(null)))); } @@ -63,11 +77,10 @@ public Mono> delete(@PathVariable("id") String bundleId) { public Mono> update(@RequestBody Bundle bundle) { return bundleService.findById(bundle.getId()) .zipWhen(__ -> bundleApiService.update(bundle)) -// .delayUntil(tuple2 -> { -// Bundle old = tuple2.getT1(); -// return businessEventPublisher.publishBundleCommonEvent(bundle.getId(), old.getName() + " => " + bundle.getName(), -// EventType.BUNDLE_UPDATE); -// }) + .delayUntil(tuple2 -> { + Bundle old = tuple2.getT1(); + return businessEventPublisher.publishBundleCommonEvent(tuple2.getT2(), BUNDLE_UPDATE); + }) .map(tuple2 -> ResponseView.success(tuple2.getT2())); } @@ -81,7 +94,7 @@ public Mono> publish(@PathVariable String bundleId) public Mono> recycle(@PathVariable String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.recycle(objectId) -// .delayUntil(__ -> businessEventPublisher.publishBundleCommonEvent(bundleId, null, BUNDLE_RECYCLED)) + .delayUntil(__ -> businessEventPublisher.publishBundleCommonEvent(bundleId, null, null, BUNDLE_RECYCLED)) .map(ResponseView::success)); } @@ -89,7 +102,7 @@ public Mono> recycle(@PathVariable String bundleId) { public Mono> restore(@PathVariable String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.restore(objectId) -// .delayUntil(__ -> businessEventPublisher.publishBundleCommonEvent(bundleId, null, BUNDLE_RESTORE)) + .delayUntil(__ -> businessEventPublisher.publishBundleCommonEvent(bundleId, null, null, BUNDLE_RESTORE)) .map(ResponseView::success)); } @@ -120,8 +133,7 @@ public Mono> moveApp(@PathVariable("id") String applicationId gidService.convertBundleIdToObjectId(toBundleId).flatMap(objectIdTo -> gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> bundleApiService.moveApp(appId, objectIdFrom, objectIdTo) - //TODO: Event Type not defined yet - // .then(businessEventPublisher.publishBundleCommonEvent(applicationLikeId, targetBundleId, BUNDLE_MOVE)) + .then(businessEventPublisher.publishBundleCommonEvent(applicationId, fromBundleId, toBundleId, APPLICATION_MOVE)) .then(Mono.fromSupplier(() -> ResponseView.success(null)))))); } @@ -188,7 +200,7 @@ public Mono> getBundlePermissions(@PathVariab public Mono> getPublishedBundle(@PathVariable String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.getPublishedBundle(objectId, BundleRequestType.PUBLIC_TO_ALL) -// .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) + .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) .map(ResponseView::success)); } @@ -196,7 +208,7 @@ public Mono> getPublishedBundle(@PathVariable Strin public Mono> getPublishedMarketPlaceBundle(@PathVariable String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.getPublishedBundle(objectId, BundleRequestType.PUBLIC_TO_MARKETPLACE) -// .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) + .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) .map(ResponseView::success)); } @@ -204,7 +216,7 @@ public Mono> getPublishedMarketPlaceBundle(@PathVar public Mono> getAgencyProfileBundle(@PathVariable String bundleId) { return gidService.convertBundleIdToObjectId(bundleId).flatMap(objectId -> bundleApiService.getPublishedBundle(objectId, BundleRequestType.AGENCY_PROFILE) -// .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) + .delayUntil(bundleView -> businessEventPublisher.publishBundleCommonEvent(bundleView, BUNDLE_VIEW)) .map(ResponseView::success)); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/view/BundleInfoView.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/view/BundleInfoView.java index 343c2e7f1..68d2c0976 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/view/BundleInfoView.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/view/BundleInfoView.java @@ -27,6 +27,7 @@ public class BundleInfoView { private final Long createAt; private final String createBy; private final String folderId; + private final String folderIdFrom; private final Boolean publicToAll; private final Boolean publicToMarketplace; private final Boolean agencyProfile; diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/BusinessEventPublisher.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/BusinessEventPublisher.java index 69af10325..a5a3ff73a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/BusinessEventPublisher.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/BusinessEventPublisher.java @@ -7,8 +7,10 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.lowcoder.api.application.view.ApplicationInfoView; +import org.lowcoder.api.application.view.ApplicationPermissionView; import org.lowcoder.api.application.view.ApplicationPublishRequest; import org.lowcoder.api.application.view.ApplicationView; +import org.lowcoder.api.bundle.view.BundleInfoView; import org.lowcoder.api.home.SessionUserService; import org.lowcoder.api.usermanagement.view.AddMemberRequest; import org.lowcoder.api.usermanagement.view.UpdateRoleRequest; @@ -243,7 +245,7 @@ public Mono publishApplicationPermissionEvent(String applicationId, Set publishApplicationSharingEvent(String applicationId, String shareType) { + public Mono publishApplicationSharingEvent(String applicationId, String shareType, ApplicationPermissionView applicationPermissionView) { return sessionUserService.isAnonymousUser() .flatMap(anonymous -> { if (anonymous) { @@ -270,6 +272,7 @@ public Mono publishApplicationSharingEvent(String applicationId, String sh .applicationCategory(category) .applicationDescription(description) .type(EventType.APPLICATION_SHARING_CHANGE) + .sharingDetails(applicationPermissionView) .shareType(shareType) .isAnonymous(anonymous) .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) @@ -382,6 +385,76 @@ public Mono publishApplicationVersionChangeEvent(String applicationId, Str } + public Mono publishBundleCommonEvent(BundleInfoView bundleInfoView, EventType eventType) { + return sessionUserService.isAnonymousUser() + .flatMap(anonymous -> { + if (anonymous) { + return Mono.empty(); + } + return sessionUserService.getVisitorOrgMemberCache() + .zipWith(Mono.defer(() -> { + String folderId = bundleInfoView.getFolderId(); + if (StringUtils.isBlank(folderId)) { + return Mono.just(Optional. empty()); + } + return folderService.findById(folderId) + .map(Optional::of) + .onErrorReturn(Optional.empty()); + })) + .zipWith(Mono.defer(() -> { + String folderId = bundleInfoView.getFolderIdFrom(); + if (StringUtils.isBlank(folderId)) { + return Mono.just(Optional. empty()); + } + return folderService.findById(folderId) + .map(Optional::of) + .onErrorReturn(Optional.empty()); + }), TupleUtils::merge) + .zipWith(sessionUserService.getVisitorToken()) + .flatMap(tuple -> { + OrgMember orgMember = tuple.getT1().getT1(); + Optional optional = tuple.getT1().getT2(); + Optional optionalFrom = tuple.getT1().getT3(); + String token = tuple.getT2(); + ApplicationCommonEvent event = ApplicationCommonEvent.builder() + .orgId(orgMember.getOrgId()) + .userId(orgMember.getUserId()) + .applicationId(bundleInfoView.getBundleId()) + .applicationGid(bundleInfoView.getBundleGid()) + .applicationName(bundleInfoView.getName()) + .type(eventType) + .folderId(optional.map(Folder::getId).orElse(null)) + .folderName(optional.map(Folder::getName).orElse(null)) + .oldFolderId(optionalFrom.map(Folder::getId).orElse(null)) + .oldFolderName(optionalFrom.map(Folder::getName).orElse(null)) + .isAnonymous(anonymous) + .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) + .build(); + return Mono.deferContextual(contextView -> { + event.populateDetails(contextView); + applicationEventPublisher.publishEvent(event); + return Mono.empty(); + }).then(); + }) + .then() + .onErrorResume(throwable -> { + log.error("publishBundleCommonEvent error. {}, {}", bundleInfoView, eventType, throwable); + return Mono.empty(); + }); + }); + } + + public Mono publishBundleCommonEvent(String bundleId, @Nullable String folderIdFrom, @Nullable String folderIdTo, EventType eventType) { + return applicationService.findByIdWithoutDsl(bundleId) + .map(application -> BundleInfoView.builder() + .bundleId(bundleId) + .name(application.getName()) + .folderId(folderIdTo) + .folderIdFrom(folderIdFrom) + .build()) + .flatMap(bundleInfoView -> publishBundleCommonEvent(bundleInfoView, eventType)); + } + public Mono publishUserLoginEvent(String source) { return sessionUserService.getVisitorOrgMember().zipWith(sessionUserService.getVisitorToken()) .delayUntil(tuple -> {