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 3adb8d7d1..a53879bfe 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 @@ -5,6 +5,8 @@ import lombok.Getter; import lombok.experimental.SuperBuilder; +import java.util.Set; + @Getter @SuperBuilder public class ApplicationCommonEvent extends AbstractEvent { @@ -23,6 +25,13 @@ public class ApplicationCommonEvent extends AbstractEvent { private final String oldFolderId; @Nullable private final String oldFolderName; + private final String permissionId; + private final String role; + private final Set userIds; + private final Set groupIds; + private final String shareType; + private final String tag; + private final String commitMessage; @Override public EventType getEventType() { 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 582cb2803..9962783cf 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 @@ -4,7 +4,6 @@ import org.lowcoder.api.application.view.*; import org.lowcoder.api.framework.view.PageResponseView; import org.lowcoder.api.framework.view.ResponseView; -import org.lowcoder.api.home.SessionUserService; import org.lowcoder.api.home.UserHomeApiService; import org.lowcoder.api.home.UserHomepageView; import org.lowcoder.api.util.BusinessEventPublisher; @@ -14,7 +13,6 @@ import org.lowcoder.domain.application.model.ApplicationStatus; import org.lowcoder.domain.application.model.ApplicationType; import org.lowcoder.domain.application.service.ApplicationRecordService; -import org.lowcoder.domain.folder.service.FolderElementRelationService; import org.lowcoder.domain.permission.model.ResourceRole; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -37,7 +35,6 @@ public class ApplicationController implements ApplicationEndpoints { private final UserHomeApiService userHomeApiService; private final ApplicationApiService applicationApiService; private final BusinessEventPublisher businessEventPublisher; - private final SessionUserService sessionUserService; private final GidService gidService; private final ApplicationRecordService applicationRecordService; @@ -152,6 +149,14 @@ public Mono> publish(@PathVariable String applicat return newtag; }) .switchIfEmpty(Mono.just("1.0.0")) + .delayUntil(newtag -> { + ApplicationPublishRequest req = Objects.requireNonNullElse(applicationPublishRequest, new ApplicationPublishRequest("", newtag)); + return businessEventPublisher.publishApplicationPublishEvent(appId, req).then(Mono.defer(() -> { + if(newtag.equals(req.tag())) { + return businessEventPublisher.publishApplicationVersionChangeEvent(appId, newtag); + } else return Mono.empty(); + })); + }) .flatMap(newtag -> applicationApiService.publish(appId, Objects.requireNonNullElse(applicationPublishRequest, new ApplicationPublishRequest("", newtag)))) .map(ResponseView::success)); } @@ -221,6 +226,7 @@ public Mono> updatePermission(@PathVariable String applica } return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.updatePermission(appId, permissionId, role) + .delayUntil(__ -> businessEventPublisher.publishApplicationPermissionEvent(applicationId, null, null, permissionId, role.getValue())) .map(ResponseView::success)); } @@ -230,6 +236,7 @@ public Mono> removePermission( @PathVariable String permissionId) { return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.removePermission(appId, permissionId) + .delayUntil(__ -> businessEventPublisher.publishApplicationPermissionEvent(applicationId, null, null, permissionId, null)) .map(ResponseView::success)); } @@ -246,6 +253,7 @@ public Mono> grantPermission( emptyIfNull(request.userIds()), emptyIfNull(request.groupIds()), role) + .delayUntil(__ -> businessEventPublisher.publishApplicationPermissionEvent(applicationId, emptyIfNull(request.userIds()), emptyIfNull(request.groupIds()), null, role.getValue())) .map(ResponseView::success)); } @@ -262,6 +270,7 @@ public Mono> setApplicationPublicToAll(@PathVariable Strin @RequestBody ApplicationPublicToAllRequest request) { return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.setApplicationPublicToAll(appId, request.publicToAll()) + .delayUntil(__ -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToAll")) .map(ResponseView::success)); } @@ -270,6 +279,7 @@ public Mono> setApplicationPublicToMarketplace(@PathVariab @RequestBody ApplicationPublicToMarketplaceRequest request) { return gidService.convertApplicationIdToObjectId(applicationId).flatMap(appId -> applicationApiService.setApplicationPublicToMarketplace(appId, request) + .delayUntil(__ -> businessEventPublisher.publishApplicationSharingEvent(applicationId, "PublicToMarketplace")) .map(ResponseView::success)); } 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 fe3119d32..e6902a460 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,10 +7,12 @@ 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.ApplicationPublishRequest; import org.lowcoder.api.application.view.ApplicationView; import org.lowcoder.api.home.SessionUserService; import org.lowcoder.api.usermanagement.view.AddMemberRequest; import org.lowcoder.api.usermanagement.view.UpdateRoleRequest; +import org.lowcoder.domain.application.model.Application; import org.lowcoder.domain.application.service.ApplicationRecordServiceImpl; import org.lowcoder.domain.application.service.ApplicationService; import org.lowcoder.domain.datasource.model.Datasource; @@ -186,6 +188,174 @@ public Mono publishApplicationCommonEvent(ApplicationView applicationView, }); } + public Mono publishApplicationPermissionEvent(String applicationId, Set userIds, Set groupIds, String permissionId, String role) { + return sessionUserService.isAnonymousUser() + .flatMap(anonymous -> { + if (anonymous) { + return Mono.empty(); + } + return sessionUserService.getVisitorOrgMemberCache() + .zipWith(sessionUserService.getVisitorToken()) + .zipWith(Mono.defer(() -> applicationService.findById(applicationId) + .zipWhen(application -> application.getCategory(applicationRecordServiceImpl)) + .zipWhen(application -> application.getT1().getDescription(applicationRecordServiceImpl)))) + .doOnNext(tuple -> { + OrgMember orgMember = tuple.getT1().getT1(); + String token = tuple.getT1().getT2(); + String category = tuple.getT2().getT1().getT2(); + String description = tuple.getT2().getT2(); + Application application = tuple.getT2().getT1().getT1(); + ApplicationCommonEvent event = ApplicationCommonEvent.builder() + .orgId(orgMember.getOrgId()) + .userId(orgMember.getUserId()) + .applicationId(application.getId()) + .applicationGid(application.getGid()) + .applicationName(application.getName()) + .applicationCategory(category) + .applicationDescription(description) + .type(EventType.APPLICATION_PERMISSION_CHANGE) + .permissionId(permissionId) + .role(role) + .userIds(userIds) + .groupIds(groupIds) + .isAnonymous(anonymous) + .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) + .build(); + event.populateDetails(); + applicationEventPublisher.publishEvent(event); + }) + .then() + .onErrorResume(throwable -> { + log.error("publishApplicationPermissionEvent error. {}, {}, {}", applicationId, permissionId, role, throwable); + return Mono.empty(); + }); + }); + } + + public Mono publishApplicationSharingEvent(String applicationId, String shareType) { + return sessionUserService.isAnonymousUser() + .flatMap(anonymous -> { + if (anonymous) { + return Mono.empty(); + } + return sessionUserService.getVisitorOrgMemberCache() + .zipWith(sessionUserService.getVisitorToken()) + .zipWith(Mono.defer(() -> applicationService.findById(applicationId) + .zipWhen(application -> application.getCategory(applicationRecordServiceImpl)) + .zipWhen(application -> application.getT1().getDescription(applicationRecordServiceImpl)))) + .doOnNext(tuple -> { + OrgMember orgMember = tuple.getT1().getT1(); + String token = tuple.getT1().getT2(); + String category = tuple.getT2().getT1().getT2(); + String description = tuple.getT2().getT2(); + Application application = tuple.getT2().getT1().getT1(); + ApplicationCommonEvent event = ApplicationCommonEvent.builder() + .orgId(orgMember.getOrgId()) + .userId(orgMember.getUserId()) + .applicationId(application.getId()) + .applicationGid(application.getGid()) + .applicationName(application.getName()) + .applicationCategory(category) + .applicationDescription(description) + .type(EventType.APPLICATION_SHARING_CHANGE) + .shareType(shareType) + .isAnonymous(anonymous) + .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) + .build(); + event.populateDetails(); + applicationEventPublisher.publishEvent(event); + }) + .then() + .onErrorResume(throwable -> { + log.error("publishApplicationSharingEvent error. {}, {}", applicationId, shareType, throwable); + return Mono.empty(); + }); + }); + } + + public Mono publishApplicationPublishEvent(String applicationId, ApplicationPublishRequest request) { + return sessionUserService.isAnonymousUser() + .flatMap(anonymous -> { + if (anonymous) { + return Mono.empty(); + } + return sessionUserService.getVisitorOrgMemberCache() + .zipWith(sessionUserService.getVisitorToken()) + .zipWith(Mono.defer(() -> applicationService.findById(applicationId) + .zipWhen(application -> application.getCategory(applicationRecordServiceImpl)) + .zipWhen(application -> application.getT1().getDescription(applicationRecordServiceImpl)))) + .doOnNext(tuple -> { + OrgMember orgMember = tuple.getT1().getT1(); + String token = tuple.getT1().getT2(); + String category = tuple.getT2().getT1().getT2(); + String description = tuple.getT2().getT2(); + Application application = tuple.getT2().getT1().getT1(); + ApplicationCommonEvent event = ApplicationCommonEvent.builder() + .orgId(orgMember.getOrgId()) + .userId(orgMember.getUserId()) + .applicationId(application.getId()) + .applicationGid(application.getGid()) + .applicationName(application.getName()) + .applicationCategory(category) + .applicationDescription(description) + .type(EventType.APPLICATION_SHARING_CHANGE) + .commitMessage(request.commitMessage()) + .tag(request.tag()) + .isAnonymous(anonymous) + .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) + .build(); + event.populateDetails(); + applicationEventPublisher.publishEvent(event); + }) + .then() + .onErrorResume(throwable -> { + log.error("publishApplicationPublishEvent error. {}, {}, {}", applicationId, request.tag(), request.commitMessage(), throwable); + return Mono.empty(); + }); + }); + } + + public Mono publishApplicationVersionChangeEvent(String applicationId, String newtag) { + return sessionUserService.isAnonymousUser() + .flatMap(anonymous -> { + if (anonymous) { + return Mono.empty(); + } + return sessionUserService.getVisitorOrgMemberCache() + .zipWith(sessionUserService.getVisitorToken()) + .zipWith(Mono.defer(() -> applicationService.findById(applicationId) + .zipWhen(application -> application.getCategory(applicationRecordServiceImpl)) + .zipWhen(application -> application.getT1().getDescription(applicationRecordServiceImpl)))) + .doOnNext(tuple -> { + OrgMember orgMember = tuple.getT1().getT1(); + String token = tuple.getT1().getT2(); + String category = tuple.getT2().getT1().getT2(); + String description = tuple.getT2().getT2(); + Application application = tuple.getT2().getT1().getT1(); + ApplicationCommonEvent event = ApplicationCommonEvent.builder() + .orgId(orgMember.getOrgId()) + .userId(orgMember.getUserId()) + .applicationId(application.getId()) + .applicationGid(application.getGid()) + .applicationName(application.getName()) + .applicationCategory(category) + .applicationDescription(description) + .type(EventType.APPLICATION_SHARING_CHANGE) + .tag(newtag) + .isAnonymous(anonymous) + .sessionHash(Hashing.sha512().hashString(token, StandardCharsets.UTF_8).toString()) + .build(); + event.populateDetails(); + applicationEventPublisher.publishEvent(event); + }) + .then() + .onErrorResume(throwable -> { + log.error("publishApplicationPublishEvent error. {}, {}", applicationId, newtag, throwable); + return Mono.empty(); + }); + }); + } + public Mono publishUserLoginEvent(String source) { return sessionUserService.getVisitorOrgMember().zipWith(sessionUserService.getVisitorToken()) .doOnNext(tuple -> {