diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index a28912ccb..7a6e047ca 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -37,11 +37,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends gosu \ COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder/api-service /lowcoder/api-service # Copy lowcoder api service app, dependencies and libs -COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/distribution/target/lowcoder-api-service-bin/app /lowcoder/api-service/app -COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/distribution/target/lowcoder-api-service-bin/dependencies /lowcoder/api-service/dependencies -COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/distribution/target/lowcoder-api-service-bin/libs /lowcoder/api-service/libs -COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/distribution/target/lowcoder-api-service-bin/plugins /lowcoder/api-service/plugins -COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/distribution/target/lowcoder-api-service-bin/set-classpath.sh /lowcoder/api-service/set-classpath.sh +COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/lowcoder-server/target/lowcoder-api-service-bin/lowcoder-api-service.jar /lowcoder/api-service/lowcoder-api-service.jar +COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/lowcoder-server/target/lowcoder-api-service-bin/libs /lowcoder/api-service/libs +COPY --chown=lowcoder:lowcoder --from=build-api-service /lowcoder-server/lowcoder-server/target/lowcoder-api-service-bin/plugins /lowcoder/api-service/plugins EXPOSE 8080 CMD [ "/bin/bash" , "/lowcoder/api-service/entrypoint.sh" ] diff --git a/deploy/docker/api-service/entrypoint.sh b/deploy/docker/api-service/entrypoint.sh index 59c0f614d..92ad13738 100644 --- a/deploy/docker/api-service/entrypoint.sh +++ b/deploy/docker/api-service/entrypoint.sh @@ -12,7 +12,7 @@ echo "Initializing api-service..." if [ -z $JAVA_HOME ]; then JAVA_HOME=`dirname $(dirname $(readlink -f $(which javac)))` fi; -APP_JAR="${APP_JAR:=/lowcoder/api-service/server.jar}" +APP_JAR="${APP_JAR:=/lowcoder/api-service/lowcoder-api-service.jar}" JAVA_OPTS="${JAVA_OPTS:=}" CUSTOM_APP_PROPERTIES="${APP_PROPERTIES}" CONTEXT_PATH=${CONTEXT_PATH:=/} @@ -27,7 +27,6 @@ ${JAVA_HOME}/bin/java -version echo cd /lowcoder/api-service -source set-classpath.sh exec gosu ${USER_ID}:${GROUP_ID} ${JAVA_HOME}/bin/java \ -Djava.util.prefs.userRoot=/tmp \ @@ -36,7 +35,7 @@ exec gosu ${USER_ID}:${GROUP_ID} ${JAVA_HOME}/bin/java \ -Dlog4j2.formatMsgNoLookups=true \ -Dspring.config.location="file:///lowcoder/api-service/config/application.yaml" \ --add-opens java.base/java.nio=ALL-UNNAMED \ - -cp "${LOWCODER_CLASSPATH:=.}" \ ${JAVA_OPTS} \ - org.lowcoder.api.ServerApplication --spring.webflux.base-path=${CONTEXT_PATH} ${CUSTOM_APP_PROPERTIES} + -Dpf4j.pluginsDir=/lowcoder/api-service/plugins \ + -jar ${APP_JAR} --spring.webflux.base-path=${CONTEXT_PATH} ${CUSTOM_APP_PROPERTIES} diff --git a/server/api-service/distribution/pom.xml b/server/api-service/distribution/pom.xml deleted file mode 100644 index d68b3fab4..000000000 --- a/server/api-service/distribution/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - 4.0.0 - - org.lowcoder - lowcoder-root - ${revision} - - - distribution - pom - - - ${project.build.directory}/dependencies - - - - - - - org.lowcoder - lowcoder-sdk - - - org.lowcoder - lowcoder-infra - - - org.lowcoder - lowcoder-domain - - - org.lowcoder - lowcoder-server - - - - - lowcoder-api-service - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - prepare-package - - copy-dependencies - - - ${assembly.lib.directory} - false - false - true - true - - - - - - maven-assembly-plugin - - - distro-assembly - package - - single - - - false - - src/assembly/bin.xml - - - - - - - - - \ No newline at end of file diff --git a/server/api-service/distribution/src/assembly/bin.xml b/server/api-service/distribution/src/assembly/bin.xml deleted file mode 100644 index b6422619e..000000000 --- a/server/api-service/distribution/src/assembly/bin.xml +++ /dev/null @@ -1,72 +0,0 @@ - - bin - - dir - - false - - - - src/assembly/set-classpath.sh - - - - - - ${assembly.lib.directory} - dependencies - - ${project.groupId}:* - - - - - - - - true - - org.lowcoder:lowcoder-server - - - app - false - false - - - - - - true - - org.lowcoder:lowcoder-domain - org.lowcoder:lowcoder-infra - org.lowcoder:lowcoder-sdk - - - libs - false - false - - - - - - true - true - - org.lowcoder:*Plugin - - - org.lowcoder:sqlBasedPlugin - - - plugins - false - false - - - - \ No newline at end of file diff --git a/server/api-service/distribution/src/assembly/set-classpath.sh b/server/api-service/distribution/src/assembly/set-classpath.sh deleted file mode 100755 index de82ddf7f..000000000 --- a/server/api-service/distribution/src/assembly/set-classpath.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Set lowcoder api service classpath for use in startup script -# -export LOWCODER_CLASSPATH="`find libs/ dependencies/ app/ -type f -name "*.jar" | tr '\n' ':' | sed -e 's/:$//'`" - -# -# Example usage: -# -# java -cp "${LOWCODER_CLASSPATH}" org.lowcoder.api.ServerApplication diff --git a/server/api-service/lombok.config b/server/api-service/lombok.config new file mode 100644 index 000000000..7eb5eb12e --- /dev/null +++ b/server/api-service/lombok.config @@ -0,0 +1,6 @@ +# Copy the Qualifier annotation from the instance variables to the constructor +# see https://github.com/rzwitserloot/lombok/issues/745 +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value +lombok.copyableAnnotations += org.springframework.context.annotation.Lazy + diff --git a/server/api-service/lowcoder-dependencies/pom.xml b/server/api-service/lowcoder-dependencies/pom.xml index db8e5c167..3f8b6b703 100644 --- a/server/api-service/lowcoder-dependencies/pom.xml +++ b/server/api-service/lowcoder-dependencies/pom.xml @@ -18,7 +18,7 @@ org.springframework.boot spring-boot-dependencies - 3.1.2 + 3.2.4 pom import @@ -32,13 +32,13 @@ org.pf4j pf4j - 3.5.0 + 3.11.0 org.json json - 20230227 + 20240303 @@ -50,12 +50,12 @@ org.apache.commons commons-text - 1.10.0 + 1.11.0 commons-io commons-io - 2.13.0 + 2.16.0 org.glassfish @@ -70,7 +70,13 @@ org.eclipse.jgit org.eclipse.jgit - 6.5.0.202303070854-r + 6.9.0.202403050737-r + + + + jakarta.persistence + jakarta.persistence-api + 3.1.0 @@ -81,7 +87,7 @@ com.google.guava guava - 30.0-jre + 33.1.0-jre @@ -92,18 +98,18 @@ org.jetbrains.kotlin kotlin-stdlib-jdk7 - 1.6.21 + 1.9.23 com.jayway.jsonpath json-path - 2.7.0 + 2.9.0 com.github.ben-manes.caffeine caffeine - 3.0.5 + 3.1.8 es.moki.ratelimitj @@ -113,7 +119,7 @@ com.github.spullara.mustache.java compiler - 0.9.6 + 0.9.11 @@ -125,7 +131,7 @@ io.projectreactor reactor-core - 3.4.29 + 3.6.4 @@ -137,19 +143,34 @@ com.querydsl querydsl-apt + 5.1.0 + jakarta + + + + com.querydsl + querydsl-jpa + 5.1.0 + jakarta + + + + com.querydsl + querydsl-mongodb 5.0.0 + jakarta io.sentry - sentry-spring-boot-starter - 3.1.2 + sentry-spring-boot-starter-jakarta + 7.6.0 org.jgrapht jgrapht-core - 1.5.0 + 1.5.2 @@ -172,17 +193,22 @@ - com.github.cloudyrock.mongock + io.mongock mongock-bom - 4.3.8 + 5.4.0 pom import + + io.mongock + mongock-springboot + 5.4.0 + io.projectreactor.tools blockhound - 1.0.6.RELEASE + 1.0.8.RELEASE @@ -194,7 +220,7 @@ io.projectreactor reactor-test - 3.3.5.RELEASE + 3.6.4 org.apache.httpcomponents @@ -204,7 +230,7 @@ de.flapdoodle.embed de.flapdoodle.embed.mongo.spring30x - 4.7.0 + 4.11.0 org.mockito @@ -217,6 +243,12 @@ jakarta.validation-api 3.0.2 + + org.springdoc + springdoc-openapi-starter-webflux-ui + 2.5.0 + + diff --git a/server/api-service/lowcoder-domain/pom.xml b/server/api-service/lowcoder-domain/pom.xml index 3883d1f57..84a6a116e 100644 --- a/server/api-service/lowcoder-domain/pom.xml +++ b/server/api-service/lowcoder-domain/pom.xml @@ -5,7 +5,7 @@ lowcoder-root org.lowcoder - ${revision} + ${revision} 4.0.0 @@ -56,18 +56,26 @@ - com.github.cloudyrock.mongock - mongock-spring-v5 + io.mongock + mongock-springboot com.google.guava guava + + javax.inject + javax.inject + + + org.springframework.boot + spring-boot-autoconfigure + - com.github.cloudyrock.mongock - mongodb-springdata-v3-driver + io.mongock + mongodb-springdata-v4-driver org.projectlombok @@ -140,6 +148,7 @@ com.querydsl querydsl-apt + jakarta com.google.guava @@ -150,11 +159,16 @@ com.querydsl querydsl-jpa + jakarta + + + jakarta.persistence + jakarta.persistence-api io.sentry - sentry-spring-boot-starter + sentry-spring-boot-starter-jakarta @@ -191,11 +205,11 @@ es.moki.ratelimitj ratelimitj-redis - - io.lettuce - lettuce-core - - + + io.lettuce + lettuce-core + + @@ -234,13 +248,13 @@ test - - jakarta.xml.bind - jakarta.xml.bind-api + + jakarta.xml.bind + jakarta.xml.bind-api - - jakarta.activation - jakarta.activation-api + + jakarta.activation + jakarta.activation-api @@ -262,17 +276,34 @@ process - target/generated-sources/java - - org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor - - - true - + target/generated-sources + org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + generate-sources + + + + + + + + + run + + + + + @@ -282,15 +313,15 @@ - - - org.lowcoder - lowcoder-dependencies - ${revision} - pom - import - - - + + + org.lowcoder + lowcoder-dependencies + ${revision} + pom + import + + + 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 de6b069ef..66a0f41e0 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 @@ -1,19 +1,17 @@ package org.lowcoder.domain.application.repository; -import java.util.Collection; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; import org.lowcoder.domain.application.model.Application; import org.lowcoder.domain.application.model.ApplicationStatus; import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import org.springframework.stereotype.Repository; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Collection; + @Repository public interface ApplicationRepository extends ReactiveMongoRepository, CustomApplicationRepository { 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 a5f83cdaf..3bdcbac9f 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 @@ -1,289 +1,74 @@ package org.lowcoder.domain.application.service; - -import static org.lowcoder.domain.application.ApplicationUtil.getDependentModulesFromDsl; - -import java.util.*; -import java.util.stream.Collectors; - import org.lowcoder.domain.application.model.Application; import org.lowcoder.domain.application.model.ApplicationRequestType; import org.lowcoder.domain.application.model.ApplicationStatus; -import org.lowcoder.domain.application.repository.ApplicationRepository; -import org.lowcoder.domain.permission.model.ResourceRole; -import org.lowcoder.domain.permission.service.ResourcePermissionService; import org.lowcoder.infra.annotation.NonEmptyMono; -import org.lowcoder.infra.mongo.MongoUpsertHelper; -import org.lowcoder.sdk.constants.FieldName; -import org.lowcoder.sdk.exception.BizError; -import org.lowcoder.sdk.exception.BizException; -import org.lowcoder.sdk.models.HasIdAndAuditing; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Lazy -@Service -@Slf4j -public class ApplicationService { - - - @Autowired - private MongoUpsertHelper mongoUpsertHelper; - - @Autowired - private ResourcePermissionService resourcePermissionService; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; - @Autowired - private ApplicationRepository repository; +public interface ApplicationService { + Mono findById(String id); - public Mono findById(String id) { - if (id == null) { - return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); - } + Mono findByIdWithoutDsl(String id); - return repository.findByIdWithDsl(id) - .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "CANT_FIND_APPLICATION", id))); - } + Mono updateById(String applicationId, Application application); - public Mono findByIdWithoutDsl(String id) { - if (id == null) { - return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); - } + Mono updatePublishedApplicationDSL(String applicationId, Map applicationDSL); - return repository.findById(id) - .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "CANT_FIND_APPLICATION", id))); - } + Mono publish(String applicationId); - public Mono updateById(String applicationId, Application application) { - if (applicationId == null) { - return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); - } + Mono create(Application newApplication, String visitorId); - return mongoUpsertHelper.updateById(application, applicationId); - } + Flux findByOrganizationIdWithDsl(String organizationId); + Flux findByOrganizationIdWithoutDsl(String organizationId); - public Mono updatePublishedApplicationDSL(String applicationId, Map applicationDSL) { - Application application = Application.builder().publishedApplicationDSL(applicationDSL).build(); - return mongoUpsertHelper.updateById(application, applicationId); - } + Flux findAllMarketplaceApps(); - public Mono publish(String applicationId) { - return findById(applicationId) - .flatMap(newApplication -> { // copy editingApplicationDSL to publishedApplicationDSL - Map editingApplicationDSL = newApplication.getEditingApplicationDSL(); - return updatePublishedApplicationDSL(applicationId, editingApplicationDSL) - .thenReturn(newApplication); - }); - } + Flux findAllAgencyProfileApps(); - public Mono create(Application newApplication, String visitorId) { - return repository.save(newApplication) - .delayUntil(app -> resourcePermissionService.addApplicationPermissionToUser(app.getId(), visitorId, ResourceRole.OWNER)); - } + Mono countByOrganizationId(String orgId, ApplicationStatus applicationStatus); - /** - * If you don't need dsl, please use {@link #findByOrganizationIdWithoutDsl(String)} - */ - public Flux findByOrganizationIdWithDsl(String organizationId) { - return repository.findByOrganizationIdWithDsl(organizationId); - } + Flux findByIdIn(List applicationIds); - public Flux findByOrganizationIdWithoutDsl(String organizationId) { - return repository.findByOrganizationId(organizationId); - } + Mono> getAllDependentModulesFromApplicationId(String applicationId, boolean viewMode); - public Flux findAllMarketplaceApps() { - return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); - } + Mono> getAllDependentModulesFromApplication(Application application, boolean viewMode); - public Flux findAllAgencyProfileApps() { - return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrue(); - } + Mono> getAllDependentModulesFromDsl(Map dsl); - public Mono countByOrganizationId(String orgId, ApplicationStatus applicationStatus) { - return repository.countByOrganizationIdAndApplicationStatus(orgId, applicationStatus); - } - - public Flux findByIdIn(List applicationIds) { - return repository.findByIdIn(applicationIds); - } - - public Mono> getAllDependentModulesFromApplicationId(String applicationId, boolean viewMode) { - return findById(applicationId) - .flatMap(app -> getAllDependentModulesFromApplication(app, viewMode)); - } - - public Mono> getAllDependentModulesFromApplication(Application application, boolean viewMode) { - Map dsl = viewMode ? application.getLiveApplicationDsl() : application.getEditingApplicationDSL(); - return getAllDependentModulesFromDsl(dsl); - } - - public Mono> getAllDependentModulesFromDsl(Map dsl) { - Set circularDependencyCheckSet = Sets.newHashSet(); - return Mono.just(getDependentModulesFromDsl(dsl)) - .doOnNext(circularDependencyCheckSet::addAll) - .flatMapMany(moduleSet -> findByIdIn(Lists.newArrayList(moduleSet))) - .onErrorContinue((e, i) -> log.warn("get dependent modules on error continue , {}", e.getMessage())) - .expandDeep(module -> getDependentModules(module, circularDependencyCheckSet)) - .collectList(); - } - - private Flux getDependentModules(Application module, Set circularDependencyCheckSet) { - return Flux.fromIterable(module.getLiveModules()) - .filter(moduleId -> !circularDependencyCheckSet.contains(moduleId)) - .doOnNext(circularDependencyCheckSet::add) - .collectList() - .flatMapMany(this::findByIdIn) - .onErrorContinue((e, i) -> log.warn("get dependent modules on error continue , {}", e.getMessage())); - } - - public Mono setApplicationPublicToAll(String applicationId, boolean publicToAll) { - Application application = Application.builder() - .publicToAll(publicToAll) - .build(); - return mongoUpsertHelper.updateById(application, applicationId); - } + Mono setApplicationPublicToAll(String applicationId, boolean publicToAll); // Falk: String title, String category, String description, String image will be set in Application Settings inside DSL by Frontend - public Mono setApplicationPublicToMarketplace(String applicationId, Boolean publicToMarketplace) { - - return findById(applicationId) - - .map(application -> { - - Map applicationDsl = application.getEditingApplicationDSL(); - - // Falk: this logic is not needed anymore, because we set Meta Data in Settings in the UI already - /* if (applicationDsl.containsKey("ui")) { - Map dataObject = (Map) applicationDsl.get("ui"); - - if(publicToMarketplace) { - Map marketplaceMeta = new HashMap<>(); - marketplaceMeta.put("title", title); - marketplaceMeta.put("description", description); - marketplaceMeta.put("category", category); - marketplaceMeta.put("image", image); - if (dataObject.containsKey("marketplaceMeta")) { - dataObject.replace("marketplaceMeta", marketplaceMeta); - } else { - dataObject.put("marketplaceMeta", marketplaceMeta); - } - } else { - dataObject.remove("marketplaceMeta"); - } - - applicationDsl.replace("ui", dataObject); - - } */ - - return Application.builder() - .publicToMarketplace(publicToMarketplace) - .editingApplicationDSL(applicationDsl) - .build(); - - }) - .flatMap(application -> mongoUpsertHelper.updateById(application, applicationId)); - - - } - - public Mono setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile) { - Application application = Application.builder() - .agencyProfile(agencyProfile) - .build(); - return mongoUpsertHelper.updateById(application, applicationId); - } + Mono setApplicationPublicToMarketplace(String applicationId, Boolean publicToMarketplace); + Mono setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile); @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, boolean isAnonymous, Boolean isPrivateMarketplace) { + Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, boolean isAnonymous, Boolean isPrivateMarketplace); - switch(requestType) - { - case PUBLIC_TO_ALL: - if (isAnonymous) - { - return getPublicApplicationIds(applicationIds); - } - else - { - return getPrivateApplicationIds(applicationIds); - } - case PUBLIC_TO_MARKETPLACE: - return getPublicMarketplaceApplicationIds(applicationIds, isAnonymous, isPrivateMarketplace); - case AGENCY_PROFILE: - return getPublicAgencyApplicationIds(applicationIds); - default: - return Mono.empty(); - } - } - - - /** - * Find all public applications - doesn't matter if user is anonymous, because these apps are public - */ @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPublicApplicationIds(Collection applicationIds) { - - return repository.findByPublicToAllIsTrueAndIdIn(applicationIds) - .map(HasIdAndAuditing::getId) - .collect(Collectors.toSet()); - } - + Mono> getPublicApplicationIds(Collection applicationIds); - /** - * Find all private applications for viewing. - */ @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPrivateApplicationIds(Collection applicationIds) { - // TODO: in 2.4.0 we need to check whether the app was published or not - return repository.findByIdIn(applicationIds) - .map(HasIdAndAuditing::getId) - .collect(Collectors.toSet()); - } - - - /** - * Find all marketplace applications - filter based on whether user is anonymous and whether it's a private marketplace - */ + Mono> getPrivateApplicationIds(Collection applicationIds); + @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPublicMarketplaceApplicationIds(Collection applicationIds, boolean isAnonymous, boolean isPrivateMarketplace) { - - if ((isAnonymous && !isPrivateMarketplace) || !isAnonymous) - { - return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(applicationIds) - .map(HasIdAndAuditing::getId) - .collect(Collectors.toSet()); - } - return Mono.empty(); - } + Mono> getPublicMarketplaceApplicationIds(Collection applicationIds, boolean isAnonymous, boolean isPrivateMarketplace); - /** - * Find all agency applications - */ @NonEmptyMono @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") - public Mono> getPublicAgencyApplicationIds(Collection applicationIds) { - - return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(applicationIds) - .map(HasIdAndAuditing::getId) - .collect(Collectors.toSet()); - } + Mono> getPublicAgencyApplicationIds(Collection applicationIds); - public Flux findAll() { - return repository.findAll(); - } + Flux findAll(); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java new file mode 100644 index 000000000..a7224e946 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java @@ -0,0 +1,307 @@ +package org.lowcoder.domain.application.service; + + +import static org.lowcoder.domain.application.ApplicationUtil.getDependentModulesFromDsl; + +import java.util.*; +import java.util.stream.Collectors; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.application.model.Application; +import org.lowcoder.domain.application.model.ApplicationRequestType; +import org.lowcoder.domain.application.model.ApplicationStatus; +import org.lowcoder.domain.application.repository.ApplicationRepository; +import org.lowcoder.domain.permission.model.ResourceRole; +import org.lowcoder.domain.permission.service.ResourcePermissionService; +import org.lowcoder.infra.annotation.NonEmptyMono; +import org.lowcoder.infra.mongo.MongoUpsertHelper; +import org.lowcoder.sdk.constants.FieldName; +import org.lowcoder.sdk.exception.BizError; +import org.lowcoder.sdk.exception.BizException; +import org.lowcoder.sdk.models.HasIdAndAuditing; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +@Slf4j +public class ApplicationServiceImpl implements ApplicationService { + + private final MongoUpsertHelper mongoUpsertHelper; + private final ResourcePermissionService resourcePermissionService; + private final ApplicationRepository repository; + + @Override + public Mono findById(String id) { + if (id == null) { + return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); + } + + return repository.findByIdWithDsl(id) + .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "CANT_FIND_APPLICATION", id))); + } + + @Override + public Mono findByIdWithoutDsl(String id) { + if (id == null) { + return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); + } + + return repository.findById(id) + .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "CANT_FIND_APPLICATION", id))); + } + + @Override + public Mono updateById(String applicationId, Application application) { + if (applicationId == null) { + return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); + } + + return mongoUpsertHelper.updateById(application, applicationId); + } + + + @Override + public Mono updatePublishedApplicationDSL(String applicationId, Map applicationDSL) { + Application application = Application.builder().publishedApplicationDSL(applicationDSL).build(); + return mongoUpsertHelper.updateById(application, applicationId); + } + + @Override + public Mono publish(String applicationId) { + return findById(applicationId) + .flatMap(newApplication -> { // copy editingApplicationDSL to publishedApplicationDSL + Map editingApplicationDSL = newApplication.getEditingApplicationDSL(); + return updatePublishedApplicationDSL(applicationId, editingApplicationDSL) + .thenReturn(newApplication); + }); + } + + @Override + public Mono create(Application newApplication, String visitorId) { + return repository.save(newApplication) + .delayUntil(app -> resourcePermissionService.addApplicationPermissionToUser(app.getId(), visitorId, ResourceRole.OWNER)); + } + + /** + * If you don't need dsl, please use {@link #findByOrganizationIdWithoutDsl(String)} + */ + @Override + public Flux findByOrganizationIdWithDsl(String organizationId) { + return repository.findByOrganizationIdWithDsl(organizationId); + } + + @Override + public Flux findByOrganizationIdWithoutDsl(String organizationId) { + return repository.findByOrganizationId(organizationId); + } + + @Override + public Flux findAllMarketplaceApps() { + return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrue(); + } + + @Override + public Flux findAllAgencyProfileApps() { + return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrue(); + } + + @Override + public Mono countByOrganizationId(String orgId, ApplicationStatus applicationStatus) { + return repository.countByOrganizationIdAndApplicationStatus(orgId, applicationStatus); + } + + @Override + public Flux findByIdIn(List applicationIds) { + return repository.findByIdIn(applicationIds); + } + + @Override + public Mono> getAllDependentModulesFromApplicationId(String applicationId, boolean viewMode) { + return findById(applicationId) + .flatMap(app -> getAllDependentModulesFromApplication(app, viewMode)); + } + + @Override + public Mono> getAllDependentModulesFromApplication(Application application, boolean viewMode) { + Map dsl = viewMode ? application.getLiveApplicationDsl() : application.getEditingApplicationDSL(); + return getAllDependentModulesFromDsl(dsl); + } + + @Override + public Mono> getAllDependentModulesFromDsl(Map dsl) { + Set circularDependencyCheckSet = Sets.newHashSet(); + return Mono.just(getDependentModulesFromDsl(dsl)) + .doOnNext(circularDependencyCheckSet::addAll) + .flatMapMany(moduleSet -> findByIdIn(Lists.newArrayList(moduleSet))) + .onErrorContinue((e, i) -> log.warn("get dependent modules on error continue , {}", e.getMessage())) + .expandDeep(module -> getDependentModules(module, circularDependencyCheckSet)) + .collectList(); + } + + private Flux getDependentModules(Application module, Set circularDependencyCheckSet) { + return Flux.fromIterable(module.getLiveModules()) + .filter(moduleId -> !circularDependencyCheckSet.contains(moduleId)) + .doOnNext(circularDependencyCheckSet::add) + .collectList() + .flatMapMany(this::findByIdIn) + .onErrorContinue((e, i) -> log.warn("get dependent modules on error continue , {}", e.getMessage())); + } + + @Override + public Mono setApplicationPublicToAll(String applicationId, boolean publicToAll) { + Application application = Application.builder() + .publicToAll(publicToAll) + .build(); + return mongoUpsertHelper.updateById(application, applicationId); + } + + // Falk: String title, String category, String description, String image will be set in Application Settings inside DSL by Frontend + @Override + public Mono setApplicationPublicToMarketplace(String applicationId, Boolean publicToMarketplace) { + + return findById(applicationId) + + .map(application -> { + + Map applicationDsl = application.getEditingApplicationDSL(); + + // Falk: this logic is not needed anymore, because we set Meta Data in Settings in the UI already + /* if (applicationDsl.containsKey("ui")) { + Map dataObject = (Map) applicationDsl.get("ui"); + + if(publicToMarketplace) { + Map marketplaceMeta = new HashMap<>(); + marketplaceMeta.put("title", title); + marketplaceMeta.put("description", description); + marketplaceMeta.put("category", category); + marketplaceMeta.put("image", image); + if (dataObject.containsKey("marketplaceMeta")) { + dataObject.replace("marketplaceMeta", marketplaceMeta); + } else { + dataObject.put("marketplaceMeta", marketplaceMeta); + } + } else { + dataObject.remove("marketplaceMeta"); + } + + applicationDsl.replace("ui", dataObject); + + } */ + + return Application.builder() + .publicToMarketplace(publicToMarketplace) + .editingApplicationDSL(applicationDsl) + .build(); + + }) + .flatMap(application -> mongoUpsertHelper.updateById(application, applicationId)); + + + } + + @Override + public Mono setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile) { + Application application = Application.builder() + .agencyProfile(agencyProfile) + .build(); + return mongoUpsertHelper.updateById(application, applicationId); + } + + + @Override + @NonEmptyMono + @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") + public Mono> getFilteredPublicApplicationIds(ApplicationRequestType requestType, Collection applicationIds, boolean isAnonymous, Boolean isPrivateMarketplace) { + + switch(requestType) + { + case PUBLIC_TO_ALL: + if (isAnonymous) + { + return getPublicApplicationIds(applicationIds); + } + else + { + return getPrivateApplicationIds(applicationIds); + } + case PUBLIC_TO_MARKETPLACE: + return getPublicMarketplaceApplicationIds(applicationIds, isAnonymous, isPrivateMarketplace); + case AGENCY_PROFILE: + return getPublicAgencyApplicationIds(applicationIds); + default: + return Mono.empty(); + } + } + + + /** + * Find all public applications - doesn't matter if user is anonymous, because these apps are public + */ + @Override + @NonEmptyMono + @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") + public Mono> getPublicApplicationIds(Collection applicationIds) { + + return repository.findByPublicToAllIsTrueAndIdIn(applicationIds) + .map(HasIdAndAuditing::getId) + .collect(Collectors.toSet()); + } + + + /** + * Find all private applications for viewing. + */ + @Override + @NonEmptyMono + @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") + public Mono> getPrivateApplicationIds(Collection applicationIds) { + // TODO: in 2.4.0 we need to check whether the app was published or not + return repository.findByIdIn(applicationIds) + .map(HasIdAndAuditing::getId) + .collect(Collectors.toSet()); + } + + + /** + * Find all marketplace applications - filter based on whether user is anonymous and whether it's a private marketplace + */ + @Override + @NonEmptyMono + @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") + public Mono> getPublicMarketplaceApplicationIds(Collection applicationIds, boolean isAnonymous, boolean isPrivateMarketplace) { + + if ((isAnonymous && !isPrivateMarketplace) || !isAnonymous) + { + return repository.findByPublicToAllIsTrueAndPublicToMarketplaceIsTrueAndIdIn(applicationIds) + .map(HasIdAndAuditing::getId) + .collect(Collectors.toSet()); + } + return Mono.empty(); + } + + /** + * Find all agency applications + */ + @Override + @NonEmptyMono + @SuppressWarnings("ReactiveStreamsNullableInLambdaInTransform") + public Mono> getPublicAgencyApplicationIds(Collection applicationIds) { + + return repository.findByPublicToAllIsTrueAndAgencyProfileIsTrueAndIdIn(applicationIds) + .map(HasIdAndAuditing::getId) + .collect(Collectors.toSet()); + } + + @Override + public Flux findAll() { + return repository.findAll(); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java index 81e56adc1..647dfe908 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; import org.lowcoder.domain.application.repository.ApplicationHistorySnapshotRepository; import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService; @@ -19,12 +20,11 @@ import reactor.core.publisher.Mono; -@Lazy +@RequiredArgsConstructor @Service public class ApplicationHistorySnapshotServiceImpl implements ApplicationHistorySnapshotService { - @Autowired - private ApplicationHistorySnapshotRepository repository; + private final ApplicationHistorySnapshotRepository repository; @Override public Mono createHistorySnapshot(String applicationId, Map dsl, Map context, String userId) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/asset/service/AssetServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/asset/service/AssetServiceImpl.java index ff802c5d7..2708f661a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/asset/service/AssetServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/asset/service/AssetServiceImpl.java @@ -1,14 +1,6 @@ package org.lowcoder.domain.asset.service; -import java.awt.Color; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Set; - -import javax.imageio.ImageIO; - +import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.asset.model.Asset; import org.lowcoder.sdk.config.dynamic.Conf; import org.lowcoder.sdk.config.dynamic.ConfigCenter; @@ -25,11 +17,16 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Service; import org.springframework.web.server.ServerWebExchange; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Set; + @Slf4j @Service public class AssetServiceImpl implements AssetService { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java index 703253a4b..79be4a4d5 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java @@ -1,5 +1,6 @@ package org.lowcoder.domain.authentication; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.organization.service.OrgMemberService; import org.lowcoder.domain.organization.service.OrganizationService; @@ -22,19 +23,14 @@ import static org.lowcoder.sdk.util.ExceptionUtils.ofError; @Slf4j +@RequiredArgsConstructor @Service public class AuthenticationServiceImpl implements AuthenticationService { - @Autowired - private OrganizationService organizationService; - - @Autowired - private OrgMemberService orgMemberService; - - @Autowired - private CommonConfig commonConfig; - @Autowired - private AuthProperties authProperties; + private final OrganizationService organizationService; + private final OrgMemberService orgMemberService; + private final CommonConfig commonConfig; + private final AuthProperties authProperties; @Override public Mono findAuthConfigByAuthId(String orgId, String authId) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/FindAuthConfig.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/FindAuthConfig.java index fa569922f..2d9e2ef29 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/FindAuthConfig.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/FindAuthConfig.java @@ -1,7 +1,7 @@ package org.lowcoder.domain.authentication; -import javax.annotation.Nullable; +import jakarta.annotation.Nullable; import org.lowcoder.domain.organization.model.Organization; import org.lowcoder.sdk.auth.AbstractAuthConfig; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/context/AuthRequestContext.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/context/AuthRequestContext.java index c10e218f4..12d5bef2e 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/context/AuthRequestContext.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/context/AuthRequestContext.java @@ -1,11 +1,10 @@ package org.lowcoder.domain.authentication.context; -import javax.annotation.Nullable; - -import org.lowcoder.sdk.auth.AbstractAuthConfig; +import jakarta.annotation.Nullable; import lombok.Getter; import lombok.Setter; +import org.lowcoder.sdk.auth.AbstractAuthConfig; @Setter @Getter diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/configurations/MongoConfig.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/configurations/MongoConfig.java index 235112a9e..263e3a9bb 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/configurations/MongoConfig.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/configurations/MongoConfig.java @@ -1,11 +1,13 @@ package org.lowcoder.domain.configurations; -import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.SpringDataMongoV3Driver; -import com.github.cloudyrock.spring.v5.MongockSpring5; import com.mongodb.ReadConcern; import com.mongodb.ReadPreference; import com.mongodb.WriteConcern; +import io.mongock.driver.mongodb.springdata.v4.SpringDataMongoV4Driver; +import io.mongock.runner.springboot.MongockSpringboot; +import io.mongock.runner.springboot.base.MongockApplicationRunner; import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.user.model.User; import org.lowcoder.sdk.config.MaterialProperties; @@ -30,15 +32,13 @@ @Slf4j @Configuration +@RequiredArgsConstructor @EnableReactiveMongoAuditing @EnableReactiveMongoRepositories(basePackages = {"org.lowcoder.infra", "org.lowcoder.domain"}) public class MongoConfig { - @Autowired - private MaterialProperties materialProperties; - - @Autowired - private MappingMongoConverter mappingMongoConverter; + private final MaterialProperties materialProperties; + private final MappingMongoConverter mappingMongoConverter; @PostConstruct public void init() { @@ -46,14 +46,14 @@ public void init() { } @Bean - public MongockSpring5.MongockApplicationRunner mongockApplicationRunner(ApplicationContext springContext, MongoTemplate mongoTemplate) { - SpringDataMongoV3Driver springDataMongoV3Driver = SpringDataMongoV3Driver.withDefaultLock(mongoTemplate); - springDataMongoV3Driver.setWriteConcern(WriteConcern.JOURNALED.withJournal(false)); - springDataMongoV3Driver.setReadConcern(ReadConcern.LOCAL); + public MongockApplicationRunner mongockApplicationRunner(ApplicationContext springContext, MongoTemplate mongoTemplate) { + SpringDataMongoV4Driver driver = SpringDataMongoV4Driver.withDefaultLock(mongoTemplate); + driver.setWriteConcern(WriteConcern.JOURNALED.withJournal(false)); + driver.setReadConcern(ReadConcern.LOCAL); - return MongockSpring5.builder() - .setDriver(springDataMongoV3Driver) - .addChangeLogsScanPackages(List.of("org.lowcoder.runner.migrations")) + return MongockSpringboot.builder() + .setDriver(driver) + .addMigrationScanPackages(List.of("org.lowcoder.runner.migrations")) .setSpringContext(springContext) .buildApplicationRunner(); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/Datasource.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/Datasource.java index 852e00db7..c5d00b6c8 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/Datasource.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/Datasource.java @@ -1,19 +1,11 @@ package org.lowcoder.domain.datasource.model; -import static org.lowcoder.domain.datasource.model.DatasourceCreationSource.LEGACY_WORKSPACE_PREDEFINED; -import static org.lowcoder.domain.datasource.model.DatasourceCreationSource.SYSTEM_STATIC; -import static org.lowcoder.domain.plugin.DatasourceMetaInfoConstants.GRAPHQL_API; -import static org.lowcoder.domain.plugin.DatasourceMetaInfoConstants.REST_API; - -import java.util.Locale; -import java.util.Optional; -import java.util.Set; - -import javax.annotation.Nullable; - -import com.fasterxml.jackson.annotation.JsonCreator; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.annotation.Nullable; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; import org.apache.commons.lang3.ObjectUtils; @@ -28,12 +20,14 @@ import org.lowcoder.sdk.util.LocaleUtils; import org.springframework.data.annotation.Transient; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; -import lombok.Getter; -import lombok.Setter; -import org.springframework.data.mongodb.core.mapping.Document; +import static org.lowcoder.domain.datasource.model.DatasourceCreationSource.LEGACY_WORKSPACE_PREDEFINED; +import static org.lowcoder.domain.datasource.model.DatasourceCreationSource.SYSTEM_STATIC; +import static org.lowcoder.domain.plugin.DatasourceMetaInfoConstants.GRAPHQL_API; +import static org.lowcoder.domain.plugin.DatasourceMetaInfoConstants.REST_API; @Getter @Setter diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/DatasourceDO.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/DatasourceDO.java index 33beee768..c13e0bace 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/DatasourceDO.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/model/DatasourceDO.java @@ -22,7 +22,7 @@ @Jacksonized @SuperBuilder @NoArgsConstructor -@AllArgsConstructor(onConstructor_ = { @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)}) +@AllArgsConstructor public class DatasourceDO extends HasIdAndAuditing { private String name; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/DatasourceConnectionPool.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/DatasourceConnectionPool.java index 7f7a34db9..1cf0f34d6 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/DatasourceConnectionPool.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/DatasourceConnectionPool.java @@ -1,10 +1,8 @@ package org.lowcoder.domain.datasource.service; -import javax.annotation.Nullable; - +import jakarta.annotation.Nullable; import org.lowcoder.domain.datasource.model.Datasource; import org.lowcoder.domain.datasource.model.DatasourceConnectionHolder; - import reactor.core.publisher.Mono; public interface DatasourceConnectionPool { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/ClientBasedConnectionPool.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/ClientBasedConnectionPool.java index 509dbff45..ca0f9f793 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/ClientBasedConnectionPool.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/ClientBasedConnectionPool.java @@ -3,7 +3,10 @@ import com.google.common.cache.*; import com.google.common.collect.ImmutableList; import io.micrometer.core.instrument.Tags; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.datasource.model.ClientBasedDatasourceConnectionHolder; @@ -22,8 +25,6 @@ import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.time.Duration; import java.time.Instant; import java.util.List; @@ -42,6 +43,7 @@ * and their status management, so these clients will be cached and invalidated once datasource is updated. */ @Slf4j +@RequiredArgsConstructor @Service public class ClientBasedConnectionPool implements DatasourceConnectionPool { @@ -55,10 +57,8 @@ public class ClientBasedConnectionPool implements DatasourceConnectionPool { ); private static final Map HIKARI_PERF_WRAPPER_MAP = new ConcurrentHashMap<>(); - @Autowired - private DatasourceMetaInfoService datasourceMetaInfoService; - @Autowired - private PerfHelper perfHelper; + private final DatasourceMetaInfoService datasourceMetaInfoService; + private final PerfHelper perfHelper; @PostConstruct public void init() { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceConnectionPoolFacade.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceConnectionPoolFacade.java index cb0d6be25..35e6a2e3a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceConnectionPoolFacade.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceConnectionPoolFacade.java @@ -1,6 +1,7 @@ package org.lowcoder.domain.datasource.service.impl; import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.datasource.model.Datasource; import org.lowcoder.domain.datasource.model.DatasourceConnectionHolder; @@ -25,15 +26,13 @@ import static org.lowcoder.domain.plugin.DatasourceMetaInfoConstants.REST_API; @Primary +@RequiredArgsConstructor @Service @Slf4j public class DatasourceConnectionPoolFacade implements DatasourceConnectionPool { - @Autowired - private List pools; - - @Autowired - private DatasourceMetaInfoService metaInfoService; + private final List pools; + private final DatasourceMetaInfoService metaInfoService; private Map, DatasourceConnectionPool> poolMap; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceServiceImpl.java index 3a9f19df0..cd488cd10 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/DatasourceServiceImpl.java @@ -1,19 +1,9 @@ package org.lowcoder.domain.datasource.service.impl; -import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; -import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; -import static org.lowcoder.sdk.util.ExceptionUtils.ofError; -import static org.lowcoder.sdk.util.LocaleUtils.getLocale; - -import java.time.Duration; -import java.util.Collection; -import java.util.Locale; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.annotation.Nonnull; - +import com.google.common.base.Joiner; +import jakarta.annotation.Nonnull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.application.model.ApplicationStatus; @@ -33,16 +23,23 @@ import org.lowcoder.sdk.models.DatasourceTestResult; import org.lowcoder.sdk.models.JsDatasourceConnectionConfig; import org.lowcoder.sdk.util.LocaleUtils; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; - -import com.google.common.base.Joiner; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; +import java.util.Collection; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; +import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; +import static org.lowcoder.sdk.util.ExceptionUtils.ofError; +import static org.lowcoder.sdk.util.LocaleUtils.getLocale; + @Slf4j @Service @RequiredArgsConstructor @@ -53,6 +50,7 @@ public class DatasourceServiceImpl implements DatasourceService { private final DatasourceMetaInfoService datasourceMetaInfoService; private final ApplicationRepository applicationRepository; + @Lazy private final ResourcePermissionService resourcePermissionService; private final DatasourceRepository repository; private final DatasourcePluginClient datasourcePluginClient; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/TokenBasedConnectionPool.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/TokenBasedConnectionPool.java index 51442bf49..8095820ce 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/TokenBasedConnectionPool.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/datasource/service/impl/TokenBasedConnectionPool.java @@ -5,6 +5,7 @@ import static org.lowcoder.sdk.exception.BizError.PLUGIN_CREATE_CONNECTION_FAILED; import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.datasource.model.Datasource; import org.lowcoder.domain.datasource.model.DatasourceConnectionHolder; import org.lowcoder.domain.datasource.model.TokenBasedConnection; @@ -20,15 +21,13 @@ import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; +@RequiredArgsConstructor @Service @Slf4j public class TokenBasedConnectionPool implements DatasourceConnectionPool { - @Autowired - private DatasourceMetaInfoService datasourceMetaInfoService; - - @Autowired - private TokenBasedConnectionRepository connectionRepository; + private final DatasourceMetaInfoService datasourceMetaInfoService; + private final TokenBasedConnectionRepository connectionRepository; @Override public Mono getOrCreateConnection(Datasource datasource) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/model/Folder.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/model/Folder.java index 9d9dab71d..a26592fd1 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/model/Folder.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/model/Folder.java @@ -1,14 +1,13 @@ package org.lowcoder.domain.folder.model; -import javax.annotation.Nullable; +import jakarta.annotation.Nullable; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import org.lowcoder.sdk.models.HasIdAndAuditing; import org.springframework.data.mongodb.core.mapping.Document; -import lombok.Getter; -import lombok.Setter; - @Getter @Setter @Document diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/ElementNode.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/ElementNode.java index 591ae8e51..6168b2ca4 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/ElementNode.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/ElementNode.java @@ -1,12 +1,11 @@ package org.lowcoder.domain.folder.service; -import java.util.function.Function; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; import lombok.Getter; import lombok.Setter; +import java.util.function.Function; + @Setter @Getter public class ElementNode implements Node { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationService.java index fc8696739..ca778379a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationService.java @@ -1,39 +1,17 @@ package org.lowcoder.domain.folder.service; -import static org.lowcoder.infra.birelation.BiRelationBizType.FOLDER_ELEMENT; - -import java.util.List; - import org.lowcoder.domain.folder.model.FolderElement; -import org.lowcoder.infra.birelation.BiRelationBizType; -import org.lowcoder.infra.birelation.BiRelationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Service -public class FolderElementRelationService { - - @Autowired - private BiRelationService biRelationService; +import java.util.List; - public Mono deleteByFolderIds(List folderIds) { - return biRelationService.removeAllBiRelations(FOLDER_ELEMENT, folderIds); - } +public interface FolderElementRelationService { + Mono deleteByFolderIds(List folderIds); - public Mono deleteByElementId(String elementId) { - return biRelationService.removeAllBiRelationsByTargetId(FOLDER_ELEMENT, elementId); - } + Mono deleteByElementId(String elementId); - public Mono create(String folderId, String elementId) { - return biRelationService.addBiRelation(BiRelationBizType.FOLDER_ELEMENT, folderId, elementId, null, null) - .then(); - } + Mono create(String folderId, String elementId); - public Flux getByElementIds(List elementIds) { - return biRelationService.getByTargetIds(BiRelationBizType.FOLDER_ELEMENT, elementIds) - .map(biRelation -> new FolderElement(biRelation.getSourceId(), biRelation.getTargetId())); - } + Flux getByElementIds(List elementIds); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationServiceImpl.java new file mode 100644 index 000000000..ec0aa6b0c --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderElementRelationServiceImpl.java @@ -0,0 +1,44 @@ +package org.lowcoder.domain.folder.service; + +import static org.lowcoder.infra.birelation.BiRelationBizType.FOLDER_ELEMENT; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.folder.model.FolderElement; +import org.lowcoder.infra.birelation.BiRelationBizType; +import org.lowcoder.infra.birelation.BiRelationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class FolderElementRelationServiceImpl implements FolderElementRelationService { + + private final BiRelationService biRelationService; + + @Override + public Mono deleteByFolderIds(List folderIds) { + return biRelationService.removeAllBiRelations(FOLDER_ELEMENT, folderIds); + } + + @Override + public Mono deleteByElementId(String elementId) { + return biRelationService.removeAllBiRelationsByTargetId(FOLDER_ELEMENT, elementId); + } + + @Override + public Mono create(String folderId, String elementId) { + return biRelationService.addBiRelation(BiRelationBizType.FOLDER_ELEMENT, folderId, elementId, null, null) + .then(); + } + + @Override + public Flux getByElementIds(List elementIds) { + return biRelationService.getByTargetIds(BiRelationBizType.FOLDER_ELEMENT, elementIds) + .map(biRelation -> new FolderElement(biRelation.getSourceId(), biRelation.getTargetId())); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderNode.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderNode.java index 6eb09db0e..24117f0d1 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderNode.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderNode.java @@ -1,19 +1,14 @@ package org.lowcoder.domain.folder.service; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.PriorityQueue; -import java.util.function.Consumer; -import java.util.function.Function; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import lombok.Getter; import lombok.Setter; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; + @Getter @Setter public class FolderNode implements Node { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderService.java index c0e9a9bac..1ac2d5e6f 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderService.java @@ -1,67 +1,21 @@ package org.lowcoder.domain.folder.service; -import static org.lowcoder.sdk.exception.BizError.NO_RESOURCE_FOUND; - -import java.util.Collection; - import org.lowcoder.domain.folder.model.Folder; -import org.lowcoder.domain.folder.repository.FolderRepository; -import org.lowcoder.infra.mongo.MongoUpsertHelper; -import org.lowcoder.sdk.constants.FieldName; -import org.lowcoder.sdk.exception.BizError; -import org.lowcoder.sdk.exception.BizException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Service -public class FolderService { - - @Autowired - private FolderRepository repository; - - @Autowired - private MongoUpsertHelper mongoUpsertHelper; - - public Mono updateById(String id, Folder resource) { - if (id == null) { - return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); - } - - return mongoUpsertHelper.updateById(resource, id); - } +import java.util.Collection; - public Mono findById(String id) { - if (id == null) { - return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); - } +public interface FolderService { + Mono updateById(String id, Folder resource); - return repository.findById(id) - .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "FOLDER_NOT_FOUND", id))); - } + Mono findById(String id); - public Mono create(Folder folder) { - return repository.save(folder); - } + Mono create(Folder folder); - public Flux findByOrganizationId(String organizationId) { - return repository.findByOrganizationId(organizationId); - } + Flux findByOrganizationId(String organizationId); - public Mono deleteAllById(Collection ids) { - return repository.deleteAllById(ids); - } + Mono deleteAllById(Collection ids); - public Mono exist(String id) { - return findById(id) - .hasElement() - .onErrorResume(throwable -> { - if (throwable instanceof BizException bizException && bizException.getError() == NO_RESOURCE_FOUND) { - return Mono.just(false); - } - return Mono.error(throwable); - }); - } + Mono exist(String id); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderServiceImpl.java new file mode 100644 index 000000000..2ad876946 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/FolderServiceImpl.java @@ -0,0 +1,72 @@ +package org.lowcoder.domain.folder.service; + +import static org.lowcoder.sdk.exception.BizError.NO_RESOURCE_FOUND; + +import java.util.Collection; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.folder.model.Folder; +import org.lowcoder.domain.folder.repository.FolderRepository; +import org.lowcoder.infra.mongo.MongoUpsertHelper; +import org.lowcoder.sdk.constants.FieldName; +import org.lowcoder.sdk.exception.BizError; +import org.lowcoder.sdk.exception.BizException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class FolderServiceImpl implements FolderService { + + private final FolderRepository repository; + private final MongoUpsertHelper mongoUpsertHelper; + + @Override + public Mono updateById(String id, Folder resource) { + if (id == null) { + return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); + } + + return mongoUpsertHelper.updateById(resource, id); + } + + @Override + public Mono findById(String id) { + if (id == null) { + return Mono.error(new BizException(BizError.INVALID_PARAMETER, "INVALID_PARAMETER", FieldName.ID)); + } + + return repository.findById(id) + .switchIfEmpty(Mono.error(new BizException(BizError.NO_RESOURCE_FOUND, "FOLDER_NOT_FOUND", id))); + } + + @Override + public Mono create(Folder folder) { + return repository.save(folder); + } + + @Override + public Flux findByOrganizationId(String organizationId) { + return repository.findByOrganizationId(organizationId); + } + + @Override + public Mono deleteAllById(Collection ids) { + return repository.deleteAllById(ids); + } + + @Override + public Mono exist(String id) { + return findById(id) + .hasElement() + .onErrorResume(throwable -> { + if (throwable instanceof BizException bizException && bizException.getError() == NO_RESOURCE_FOUND) { + return Mono.just(false); + } + return Mono.error(throwable); + }); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/Tree.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/Tree.java index ec9f2e973..86b8199c5 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/Tree.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/folder/service/Tree.java @@ -1,5 +1,9 @@ package org.lowcoder.domain.folder.service; +import jakarta.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -7,12 +11,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import javax.annotation.Nullable; - -import org.apache.commons.lang3.StringUtils; - -import lombok.extern.slf4j.Slf4j; - @Slf4j public class Tree extends FolderNode { private static final int DEFAULT_DEPTH = 1; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/group/model/Group.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/group/model/Group.java index e4f9f5638..80019d852 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/group/model/Group.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/group/model/Group.java @@ -1,12 +1,12 @@ package org.lowcoder.domain.group.model; -import java.beans.Transient; -import java.util.Comparator; -import java.util.Locale; - -import javax.annotation.Nonnull; - +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.annotation.Nonnull; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; import org.apache.commons.lang3.BooleanUtils; @@ -15,12 +15,9 @@ import org.lowcoder.sdk.models.HasIdAndAuditing; import org.springframework.data.mongodb.core.mapping.Document; -import com.fasterxml.jackson.annotation.JsonIgnore; - -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import java.beans.Transient; +import java.util.Comparator; +import java.util.Locale; @Setter @ToString diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionService.java index a0b1f884f..82a172d06 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionService.java @@ -1,30 +1,12 @@ package org.lowcoder.domain.interaction; -import java.time.Instant; - -import org.lowcoder.infra.birelation.BiRelation; -import org.lowcoder.infra.birelation.BiRelationBizType; -import org.lowcoder.infra.birelation.BiRelationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Service -public class UserApplicationInteractionService { - - @Autowired - private BiRelationService biRelationService; - - public Mono upsert(String userId, String applicationId, Instant lastViewTime) { - BiRelation biRelation = new UserApplicationInteraction(userId, applicationId, lastViewTime).toBiRelation(); +import java.time.Instant; - return biRelationService.upsert(biRelation).then(); - } +public interface UserApplicationInteractionService { + Mono upsert(String userId, String applicationId, Instant lastViewTime); - public Flux findByUserId(String userId) { - return biRelationService.getBySourceId(BiRelationBizType.USER_APP_INTERACTION, userId) - .map(UserApplicationInteraction::of); - } + Flux findByUserId(String userId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionServiceImpl.java new file mode 100644 index 000000000..2e1bf5bdb --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserApplicationInteractionServiceImpl.java @@ -0,0 +1,33 @@ +package org.lowcoder.domain.interaction; + +import java.time.Instant; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.infra.birelation.BiRelation; +import org.lowcoder.infra.birelation.BiRelationBizType; +import org.lowcoder.infra.birelation.BiRelationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class UserApplicationInteractionServiceImpl implements UserApplicationInteractionService { + + private final BiRelationService biRelationService; + + @Override + public Mono upsert(String userId, String applicationId, Instant lastViewTime) { + BiRelation biRelation = new UserApplicationInteraction(userId, applicationId, lastViewTime).toBiRelation(); + + return biRelationService.upsert(biRelation).then(); + } + + @Override + public Flux findByUserId(String userId) { + return biRelationService.getBySourceId(BiRelationBizType.USER_APP_INTERACTION, userId) + .map(UserApplicationInteraction::of); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionService.java index f339229d9..770b7cdf7 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionService.java @@ -1,32 +1,12 @@ package org.lowcoder.domain.interaction; -import java.time.Instant; - -import org.lowcoder.infra.birelation.BiRelation; -import org.lowcoder.infra.birelation.BiRelationBizType; -import org.lowcoder.infra.birelation.BiRelationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -/** - * relation service of user-folder - */ -@Service -public class UserFolderInteractionService { - - @Autowired - private BiRelationService biRelationService; +import java.time.Instant; - public Mono upsert(String userId, String folderId, Instant lastViewTime) { - BiRelation biRelation = new UserFolderInteraction(userId, folderId, lastViewTime).toBiRelation(); - return biRelationService.upsert(biRelation).then(); - } +public interface UserFolderInteractionService { + Mono upsert(String userId, String folderId, Instant lastViewTime); - public Flux findByUserId(String userId) { - return biRelationService.getBySourceId(BiRelationBizType.USER_FOLDER_INTERACTION, userId) - .map(UserFolderInteraction::of); - } + Flux findByUserId(String userId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionServiceImpl.java new file mode 100644 index 000000000..13dd8110b --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/interaction/UserFolderInteractionServiceImpl.java @@ -0,0 +1,35 @@ +package org.lowcoder.domain.interaction; + +import java.time.Instant; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.infra.birelation.BiRelation; +import org.lowcoder.infra.birelation.BiRelationBizType; +import org.lowcoder.infra.birelation.BiRelationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * relation service of user-folder + */ +@RequiredArgsConstructor +@Service +public class UserFolderInteractionServiceImpl implements UserFolderInteractionService { + + private final BiRelationService biRelationService; + + @Override + public Mono upsert(String userId, String folderId, Instant lastViewTime) { + BiRelation biRelation = new UserFolderInteraction(userId, folderId, lastViewTime).toBiRelation(); + return biRelationService.upsert(biRelation).then(); + } + + @Override + public Flux findByUserId(String userId) { + return biRelationService.getBySourceId(BiRelationBizType.USER_FOLDER_INTERACTION, userId) + .map(UserFolderInteraction::of); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/repository/CustomInvitationRepositoryImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/repository/CustomInvitationRepositoryImpl.java index 825f6f24d..2efae95ec 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/repository/CustomInvitationRepositoryImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/repository/CustomInvitationRepositoryImpl.java @@ -2,6 +2,7 @@ import static org.lowcoder.domain.util.QueryDslUtils.fieldName; +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.invitation.model.Invitation; import org.lowcoder.domain.invitation.model.QInvitation; import org.lowcoder.sdk.constants.FieldName; @@ -17,10 +18,10 @@ import reactor.core.publisher.Mono; @Repository +@RequiredArgsConstructor public class CustomInvitationRepositoryImpl implements CustomInvitationRepository { - @Autowired - private ReactiveMongoTemplate mongoTemplate; + private final ReactiveMongoTemplate mongoTemplate; @Override public Mono addInvitedUser(String invitationId, String userId) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationService.java index 04c27276f..ea0debec4 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationService.java @@ -1,41 +1,13 @@ package org.lowcoder.domain.invitation.service; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; import org.lowcoder.domain.invitation.model.Invitation; -import org.lowcoder.domain.invitation.repository.InvitationRepository; -import org.lowcoder.domain.organization.model.MemberRole; -import org.lowcoder.domain.organization.service.OrgMemberService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Mono; -@Lazy -@Service -public class InvitationService { - - @Autowired - private InvitationRepository invitationRepository; - - @Autowired - private OrgMemberService orgMemberService; - - @Autowired - private InvitationRepository repository; - - public Mono create(Invitation invitation) { - return repository.save(invitation); - } - - public Mono getById(@Nonnull String invitationId) { - return invitationRepository.findById(invitationId); - } +public interface InvitationService { + Mono create(Invitation invitation); - public Mono inviteToOrg(String userId, String orgId) { - return orgMemberService.addMember(orgId, userId, MemberRole.MEMBER); - } + Mono getById(@Nonnull String invitationId); + Mono inviteToOrg(String userId, String orgId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationServiceImpl.java new file mode 100644 index 000000000..81d3e2109 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/invitation/service/InvitationServiceImpl.java @@ -0,0 +1,38 @@ +package org.lowcoder.domain.invitation.service; + + +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.invitation.model.Invitation; +import org.lowcoder.domain.invitation.repository.InvitationRepository; +import org.lowcoder.domain.organization.model.MemberRole; +import org.lowcoder.domain.organization.service.OrgMemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class InvitationServiceImpl implements InvitationService { + + private final InvitationRepository invitationRepository; + private final OrgMemberService orgMemberService; + private final InvitationRepository repository; + + @Override + public Mono create(Invitation invitation) { + return repository.save(invitation); + } + + @Override + public Mono getById(@Nonnull String invitationId) { + return invitationRepository.findById(invitationId); + } + + @Override + public Mono inviteToOrg(String userId, String orgId) { + return orgMemberService.addMember(orgId, userId, MemberRole.MEMBER); + } + +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/material/service/meta/MaterialMetaServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/material/service/meta/MaterialMetaServiceImpl.java index 16e23b436..0e02c704f 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/material/service/meta/MaterialMetaServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/material/service/meta/MaterialMetaServiceImpl.java @@ -2,6 +2,7 @@ import java.util.Map; +import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.MapUtils; import org.lowcoder.domain.material.model.MaterialMeta; import org.lowcoder.domain.material.repository.MaterialMateRepository; @@ -19,14 +20,12 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +@RequiredArgsConstructor @Service public class MaterialMetaServiceImpl implements MaterialMetaService { - @Autowired - private ReactiveMongoTemplate reactiveMongoTemplate; - - @Autowired - private MaterialMateRepository repository; + private final ReactiveMongoTemplate reactiveMongoTemplate; + private final MaterialMateRepository repository; @Override public Mono existsByOrgIdAndFilename(String orgId, String filename) { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java index fda13da8f..819635d8c 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java @@ -43,6 +43,7 @@ public class OrgMemberServiceImpl implements OrgMemberService { private final BiRelationService biRelationService; private final GroupMemberService groupMemberService; private final GroupService groupService; + @Lazy private final OrganizationService organizationService; private final CommonConfig commonConfig; private final MongoUpsertHelper mongoUpsertHelper; diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java index 3abdd84bb..4c68a71fc 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java @@ -1,33 +1,16 @@ package org.lowcoder.domain.organization.service; -import static org.lowcoder.domain.authentication.AuthenticationService.DEFAULT_AUTH_CONFIG; -import static org.lowcoder.domain.organization.model.Organization.OrganizationCommonSettings.PASSWORD_RESET_EMAIL_TEMPLATE; -import static org.lowcoder.domain.organization.model.OrganizationState.ACTIVE; -import static org.lowcoder.domain.organization.model.OrganizationState.DELETED; -import static org.lowcoder.domain.util.QueryDslUtils.fieldName; -import static org.lowcoder.sdk.exception.BizError.UNABLE_TO_FIND_VALID_ORG; -import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; -import static org.lowcoder.sdk.util.ExceptionUtils.ofError; -import static org.lowcoder.sdk.util.LocaleUtils.getLocale; -import static org.lowcoder.sdk.util.LocaleUtils.getMessage; - -import java.util.Collection; -import java.util.List; -import java.util.Locale; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.lowcoder.domain.asset.model.Asset; import org.lowcoder.domain.asset.service.AssetRepository; import org.lowcoder.domain.asset.service.AssetService; import org.lowcoder.domain.group.service.GroupService; import org.lowcoder.domain.organization.event.OrgDeletedEvent; -import org.lowcoder.domain.organization.model.MemberRole; -import org.lowcoder.domain.organization.model.Organization; -import org.lowcoder.domain.organization.model.OrganizationDomain; -import org.lowcoder.domain.organization.model.OrganizationState; -import org.lowcoder.domain.organization.model.QOrganization; +import org.lowcoder.domain.organization.model.*; import org.lowcoder.domain.organization.model.Organization.OrganizationCommonSettings; import org.lowcoder.domain.organization.repository.OrganizationRepository; import org.lowcoder.domain.user.model.User; @@ -41,22 +24,33 @@ import org.lowcoder.sdk.exception.BizError; import org.lowcoder.sdk.exception.BizException; import org.lowcoder.sdk.util.UriUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Lazy; import org.springframework.data.mongodb.core.query.Update; import org.springframework.http.codec.multipart.Part; import org.springframework.stereotype.Service; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import static org.lowcoder.domain.authentication.AuthenticationService.DEFAULT_AUTH_CONFIG; +import static org.lowcoder.domain.organization.model.OrganizationState.ACTIVE; +import static org.lowcoder.domain.organization.model.OrganizationState.DELETED; +import static org.lowcoder.domain.util.QueryDslUtils.fieldName; +import static org.lowcoder.sdk.exception.BizError.UNABLE_TO_FIND_VALID_ORG; +import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; +import static org.lowcoder.sdk.util.ExceptionUtils.ofError; +import static org.lowcoder.sdk.util.LocaleUtils.getLocale; +import static org.lowcoder.sdk.util.LocaleUtils.getMessage; + @Slf4j +@RequiredArgsConstructor @Service public class OrganizationServiceImpl implements OrganizationService { - private final Conf logoMaxSizeInKb; + private Conf logoMaxSizeInKb; private static final String PASSWORD_RESET_EMAIL_TEMPLATE_DEFAULT = "

Hi, %s
" + "Here is the link to reset your password: %s
" + @@ -64,33 +58,19 @@ public class OrganizationServiceImpl implements OrganizationService { "Regards,
" + "The Lowcoder Team

"; - @Autowired - private AssetRepository assetRepository; - - @Autowired - private AssetService assetService; - - @Lazy - @Autowired - private OrgMemberService orgMemberService; - - @Autowired - private MongoUpsertHelper mongoUpsertHelper; - - @Autowired - private OrganizationRepository repository; - - @Autowired - private GroupService groupService; - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private CommonConfig commonConfig; - - @Autowired - public OrganizationServiceImpl(ConfigCenter configCenter) { + private final AssetRepository assetRepository; + private final AssetService assetService; + private final OrgMemberService orgMemberService; + private final MongoUpsertHelper mongoUpsertHelper; + private final OrganizationRepository repository; + private final GroupService groupService; + private final ApplicationContext applicationContext; + private final CommonConfig commonConfig; + private final ConfigCenter configCenter; + + @PostConstruct + private void init() + { logoMaxSizeInKb = configCenter.asset().ofInteger("logoMaxSizeInKb", 300); } 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 da442e7e0..a3cd2d6a3 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 @@ -1,18 +1,16 @@ package org.lowcoder.domain.permission.model; -import static com.google.common.collect.Multimaps.toMultimap; -import static java.util.Collections.emptySet; -import static org.apache.commons.lang3.ObjectUtils.firstNonNull; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; +import jakarta.annotation.Nonnull; +import lombok.Getter; import java.util.Arrays; import java.util.Set; -import javax.annotation.Nonnull; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.SetMultimap; - -import lombok.Getter; +import static com.google.common.collect.Multimaps.toMultimap; +import static java.util.Collections.emptySet; +import static org.apache.commons.lang3.ObjectUtils.firstNonNull; @Getter public enum ResourceAction { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceHolder.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceHolder.java index 8b4d36a84..6ac1b9469 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceHolder.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceHolder.java @@ -1,12 +1,11 @@ package org.lowcoder.domain.permission.model; -import static org.lowcoder.domain.permission.config.PermissionConst.ID_SPLITTER; +import jakarta.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; import java.util.Arrays; -import javax.annotation.Nullable; - -import org.apache.commons.lang3.StringUtils; +import static org.lowcoder.domain.permission.config.PermissionConst.ID_SPLITTER; public enum ResourceHolder { USER("u"), diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceRole.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceRole.java index 249fa88bb..ae9018f2f 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceRole.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/model/ResourceRole.java @@ -1,26 +1,19 @@ package org.lowcoder.domain.permission.model; -import static com.google.common.collect.Maps.newHashMap; -import static org.lowcoder.sdk.util.StreamUtils.collectMap; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.collect.Streams; +import jakarta.annotation.Nullable; import org.jgrapht.Graph; import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.traverse.BreadthFirstIterator; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.google.common.collect.Streams; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.google.common.collect.Maps.newHashMap; +import static org.lowcoder.sdk.util.StreamUtils.collectMap; public enum ResourceRole { 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 c97c2b236..7c92cc3d4 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 @@ -1,20 +1,6 @@ package org.lowcoder.domain.permission.service; -import static com.google.common.collect.Sets.newHashSet; -import static java.util.Collections.emptyMap; -import static java.util.function.Function.identity; -import static org.apache.commons.collections4.SetUtils.union; -import static org.lowcoder.domain.permission.model.ResourceHolder.USER; -import static org.lowcoder.sdk.constants.Authentication.ANONYMOUS_USER_ID; -import static org.lowcoder.sdk.util.StreamUtils.collectMap; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.application.model.Application; import org.lowcoder.domain.application.model.ApplicationRequestType; import org.lowcoder.domain.application.service.ApplicationService; @@ -22,23 +8,30 @@ import org.lowcoder.domain.permission.model.ResourcePermission; import org.lowcoder.domain.permission.model.ResourceRole; import org.lowcoder.domain.permission.model.ResourceType; -import org.lowcoder.domain.solutions.TemplateSolution; -import org.springframework.beans.factory.annotation.Autowired; +import org.lowcoder.domain.solutions.TemplateSolutionService; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; - import reactor.core.publisher.Mono; -@Lazy +import java.util.*; + +import static com.google.common.collect.Sets.newHashSet; +import static java.util.Collections.emptyMap; +import static java.util.function.Function.identity; +import static org.apache.commons.collections4.SetUtils.union; +import static org.lowcoder.domain.permission.model.ResourceHolder.USER; +import static org.lowcoder.sdk.constants.Authentication.ANONYMOUS_USER_ID; +import static org.lowcoder.sdk.util.StreamUtils.collectMap; + +@RequiredArgsConstructor @Component class ApplicationPermissionHandler extends ResourcePermissionHandler { private static final ResourceRole ANONYMOUS_USER_ROLE = ResourceRole.VIEWER; - @Autowired - private ApplicationService applicationService; - @Autowired - private TemplateSolution templateSolution; + @Lazy + private final ApplicationService applicationService; + private final TemplateSolutionService templateSolutionService; @Override protected Mono>> getAnonymousUserPermissions(Collection resourceIds, @@ -49,7 +42,7 @@ protected Mono>> getAnonymousUserPermission Set applicationIds = newHashSet(resourceIds); return Mono.zip(applicationService.getPublicApplicationIds(applicationIds), - templateSolution.getTemplateApplicationIds(applicationIds)) + templateSolutionService.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); Set templateAppIds = tuple.getT2(); @@ -64,7 +57,7 @@ protected Mono>> getAnonymousUserPermission Set applicationIds = newHashSet(resourceIds); return Mono.zip(applicationService.getPrivateApplicationIds(applicationIds), - templateSolution.getTemplateApplicationIds(applicationIds)) + templateSolutionService.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); Set templateAppIds = tuple.getT2(); @@ -84,7 +77,7 @@ protected Mono>> getAnonymousUserApplicatio Set applicationIds = newHashSet(resourceIds); return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.TRUE, config.getMarketplace().isPrivateMode()) .defaultIfEmpty(new HashSet<>()), - templateSolution.getTemplateApplicationIds(applicationIds) + templateSolutionService.getTemplateApplicationIds(applicationIds) .defaultIfEmpty(new HashSet<>()) ).map(tuple -> { Set publicAppIds = tuple.getT1(); @@ -98,7 +91,7 @@ protected Mono>> getNonAnonymousUserApplica Collection resourceIds, ResourceAction resourceAction, ApplicationRequestType requestType) { Set applicationIds = newHashSet(resourceIds); return Mono.zip(applicationService.getFilteredPublicApplicationIds(requestType, applicationIds, Boolean.FALSE, config.getMarketplace().isPrivateMode()), - templateSolution.getTemplateApplicationIds(applicationIds)) + templateSolutionService.getTemplateApplicationIds(applicationIds)) .map(tuple -> { Set publicAppIds = tuple.getT1(); Set templateAppIds = tuple.getT2(); 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 75e034218..200a9b6a8 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,14 +1,7 @@ package org.lowcoder.domain.permission.service; -import static org.lowcoder.domain.permission.model.ResourceHolder.USER; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - +import com.google.common.collect.Maps; +import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.lowcoder.domain.application.model.ApplicationRequestType; import org.lowcoder.domain.datasource.model.Datasource; @@ -17,22 +10,25 @@ import org.lowcoder.domain.permission.model.ResourcePermission; import org.lowcoder.domain.permission.model.ResourceRole; import org.lowcoder.domain.permission.model.ResourceType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; -import com.google.common.collect.Maps; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; -import reactor.core.publisher.Mono; +import static org.lowcoder.domain.permission.model.ResourceHolder.USER; -@Lazy +@RequiredArgsConstructor @Component class DatasourcePermissionHandler extends ResourcePermissionHandler { private static final ResourceRole SYSTEM_STATIC_DATASOURCE_USER_ROLE = ResourceRole.OWNER; - @Autowired - private DatasourceService datasourceService; + private final DatasourceService datasourceService; @Override protected Mono>> getAnonymousUserPermissions(Collection resourceIds, ResourceAction resourceAction) { 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 3841a42b9..115d74eb0 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 @@ -1,42 +1,29 @@ package org.lowcoder.domain.permission.service; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; -import static java.util.function.Function.identity; -import static java.util.stream.Collectors.toMap; -import static org.lowcoder.sdk.constants.Authentication.isAnonymousUser; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.Nonnull; - +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import jakarta.annotation.Nonnull; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.lowcoder.domain.application.model.ApplicationRequestType; import org.lowcoder.domain.group.service.GroupMemberService; import org.lowcoder.domain.organization.service.OrgMemberService; -import org.lowcoder.domain.permission.model.ResourceAction; -import org.lowcoder.domain.permission.model.ResourceHolder; -import org.lowcoder.domain.permission.model.ResourcePermission; -import org.lowcoder.domain.permission.model.ResourceRole; -import org.lowcoder.domain.permission.model.ResourceType; -import org.lowcoder.domain.permission.model.UserPermissionOnResourceStatus; +import org.lowcoder.domain.permission.model.*; import org.lowcoder.sdk.config.CommonConfig; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import reactor.core.publisher.Mono; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import java.util.*; -import reactor.core.publisher.Mono; +import static java.util.Collections.*; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; +import static org.lowcoder.sdk.constants.Authentication.isAnonymousUser; -abstract class ResourcePermissionHandler { +abstract class ResourcePermissionHandler implements ResourcePermissionHandlerService { + @Lazy @Autowired private ResourcePermissionService resourcePermissionService; @@ -49,9 +36,10 @@ abstract class ResourcePermissionHandler { @Autowired protected CommonConfig config; + @Override public Mono>> getAllMatchingPermissions(String userId, - Collection resourceIds, - ResourceAction resourceAction) { + Collection resourceIds, + ResourceAction resourceAction) { ResourceType resourceType = resourceAction.getResourceType(); @@ -81,8 +69,9 @@ public Mono>> getAllMatchingPermissions(Str }); } + @Override public Mono checkUserPermissionStatusOnResource(String userId, - String resourceId, ResourceAction resourceAction) { + String resourceId, ResourceAction resourceAction) { ResourceType resourceType = resourceAction.getResourceType(); @@ -221,8 +210,9 @@ private Mono> getUserGroupIds(String orgId, String userId) { protected abstract Mono getOrgId(String resourceId); - public Mono checkUserPermissionStatusOnApplication(String userId, String resourceId, - ResourceAction resourceAction, ApplicationRequestType requestType) + @Override + public Mono checkUserPermissionStatusOnApplication(String userId, String resourceId, + ResourceAction resourceAction, ApplicationRequestType requestType) { ResourceType resourceType = resourceAction.getResourceType(); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandlerService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandlerService.java new file mode 100644 index 000000000..b8315d0e1 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandlerService.java @@ -0,0 +1,23 @@ +package org.lowcoder.domain.permission.service; + +import org.lowcoder.domain.application.model.ApplicationRequestType; +import org.lowcoder.domain.permission.model.ResourceAction; +import org.lowcoder.domain.permission.model.ResourcePermission; +import org.lowcoder.domain.permission.model.UserPermissionOnResourceStatus; +import reactor.core.publisher.Mono; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public interface ResourcePermissionHandlerService { + Mono>> getAllMatchingPermissions(String userId, + Collection resourceIds, + ResourceAction resourceAction); + + Mono checkUserPermissionStatusOnResource(String userId, + String resourceId, ResourceAction resourceAction); + + Mono checkUserPermissionStatusOnApplication(String userId, String resourceId, + ResourceAction resourceAction, ApplicationRequestType requestType); +} 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 13900333b..9e2154cbc 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 @@ -1,245 +1,75 @@ package org.lowcoder.domain.permission.service; -import static java.util.Collections.singleton; -import static org.apache.commons.collections4.SetUtils.emptyIfNull; -import static org.lowcoder.sdk.exception.BizError.INVALID_PERMISSION_OPERATION; -import static org.lowcoder.sdk.exception.BizError.NOT_AUTHORIZED; -import static org.lowcoder.sdk.util.ExceptionUtils.ofError; -import static org.lowcoder.sdk.util.ExceptionUtils.ofException; +import jakarta.annotation.Nullable; +import org.lowcoder.domain.application.model.ApplicationRequestType; +import org.lowcoder.domain.permission.model.*; +import org.lowcoder.infra.annotation.NonEmptyMono; +import org.lowcoder.infra.annotation.PossibleEmptyMono; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; -import jakarta.annotation.Nullable; -import jakarta.validation.constraints.NotNull; +public interface ResourcePermissionService { + Mono>> getByResourceTypeAndResourceIds(ResourceType resourceType, + Collection resourceIds); -import org.apache.commons.collections4.CollectionUtils; -import org.lowcoder.domain.application.model.ApplicationRequestType; -import org.lowcoder.domain.permission.model.ResourceAction; -import org.lowcoder.domain.permission.model.ResourceHolder; -import org.lowcoder.domain.permission.model.ResourcePermission; -import org.lowcoder.domain.permission.model.ResourceRole; -import org.lowcoder.domain.permission.model.ResourceType; -import org.lowcoder.domain.permission.model.UserPermissionOnResourceStatus; -import org.lowcoder.infra.annotation.NonEmptyMono; -import org.lowcoder.infra.annotation.PossibleEmptyMono; -import org.lowcoder.sdk.exception.BizException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; + @NonEmptyMono + Mono> getByResourceTypeAndResourceId(ResourceType resourceType, String resourceId); -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; + @NonEmptyMono + Mono> getByApplicationId(String applicationId); -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; + @NonEmptyMono + Mono> getByDataSourceId(String dataSourceId); -@Service -public class ResourcePermissionService { + Mono insertBatchPermission(ResourceType resourceType, String resourceId, @Nullable Set userIds, + @Nullable Set groupIds, ResourceRole role); - @Autowired - private ResourcePermissionRepository repository; + Mono addDataSourcePermissionToUser(String dataSourceId, + String userId, + ResourceRole role); - @Lazy - @Autowired - private ApplicationPermissionHandler applicationPermissionHandler; + Mono addApplicationPermissionToUser(String applicationId, + String userId, + ResourceRole role); - @Lazy - @Autowired - private DatasourcePermissionHandler datasourcePermissionHandler; + Mono addApplicationPermissionToGroup(String applicationId, + String groupId, + ResourceRole role); - public Mono>> getByResourceTypeAndResourceIds(ResourceType resourceType, - Collection resourceIds) { - return repository.getByResourceTypeAndResourceIds(resourceType, resourceIds); - } + Mono getById(String permissionId); - @NonEmptyMono - public Mono> getByResourceTypeAndResourceId(ResourceType resourceType, String resourceId) { - return repository.getByResourceTypeAndResourceId(resourceType, resourceId); - } + Mono removeById(String permissionId); - @NonEmptyMono - public Mono> getByApplicationId(String applicationId) { - return getByResourceTypeAndResourceId(ResourceType.APPLICATION, applicationId); - } + Mono updateRoleById(String permissionId, ResourceRole role); - @NonEmptyMono - public Mono> getByDataSourceId(String dataSourceId) { - return getByResourceTypeAndResourceId(ResourceType.DATASOURCE, dataSourceId); - } - - public Mono insertBatchPermission(ResourceType resourceType, String resourceId, @Nullable Set userIds, - @Nullable Set groupIds, ResourceRole role) { - if (CollectionUtils.isEmpty(userIds) && CollectionUtils.isEmpty(groupIds)) { - return Mono.empty(); - } - return repository.insertBatchPermission(resourceType, resourceId, buildResourceHolders(emptyIfNull(userIds), emptyIfNull(groupIds)), role); - } - - private Multimap buildResourceHolders(@NotNull Set userIds, @NotNull Set groupIds) { - HashMultimap result = HashMultimap.create(); - for (String userId : userIds) { - result.put(ResourceHolder.USER, userId); - } - for (String groupId : groupIds) { - result.put(ResourceHolder.GROUP, groupId); - } - return result; - } - - @SuppressWarnings("SameParameterValue") - Mono addPermission(ResourceType resourceType, String resourceId, - ResourceHolder holderType, String holderId, - ResourceRole resourceRole) { - return repository.addPermission(resourceType, resourceId, holderType, holderId, resourceRole); - } - - public Mono addDataSourcePermissionToUser(String dataSourceId, - String userId, - ResourceRole role) { - return addPermission(ResourceType.DATASOURCE, dataSourceId, ResourceHolder.USER, userId, role); - } - - public Mono addApplicationPermissionToUser(String applicationId, - String userId, - ResourceRole role) { - return addPermission(ResourceType.APPLICATION, applicationId, ResourceHolder.USER, userId, role); - } - - public Mono addApplicationPermissionToGroup(String applicationId, - String groupId, - ResourceRole role) { - return addPermission(ResourceType.APPLICATION, applicationId, ResourceHolder.GROUP, groupId, role); - } - - public Mono getById(String permissionId) { - return repository.getById(permissionId); - } - - public Mono removeById(String permissionId) { - return repository.removePermissionById(permissionId); - } - - public Mono updateRoleById(String permissionId, ResourceRole role) { - return repository.updatePermissionRoleById(permissionId, role); - } - - /** - * @return map key: resourceId, value: all permissions user have for this resource - */ - private Mono>> getAllMatchingPermissions(String userId, - Collection resourceIds, - ResourceAction resourceAction) { - ResourceType resourceType = resourceAction.getResourceType(); - var resourcePermissionHandler = getResourcePermissionHandler(resourceType); - return resourcePermissionHandler.getAllMatchingPermissions(userId, resourceIds, resourceAction); - } - - private ResourcePermissionHandler getResourcePermissionHandler(ResourceType resourceType) { - if (resourceType == ResourceType.DATASOURCE) { - return datasourcePermissionHandler; - } - - if (resourceType == ResourceType.APPLICATION) { - return applicationPermissionHandler; - } - - throw ofException(INVALID_PERMISSION_OPERATION, "INVALID_PERMISSION_OPERATION", resourceType); - } - - public Flux filterResourceWithPermission(String userId, Collection resourceIds, ResourceAction resourceAction) { - return getAllMatchingPermissions(userId, resourceIds, resourceAction) - .flatMapIterable(Map::entrySet) - .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue())) - .map(Entry::getKey); - } - - public Mono checkResourcePermissionWithError(String userId, String resourceId, ResourceAction action) { - return getAllMatchingPermissions(userId, singleton(resourceId), action) - .flatMap(map -> { - List resourcePermissions = map.get(resourceId); - if (CollectionUtils.isNotEmpty(resourcePermissions)) { - return Mono.empty(); - } - return Mono.error(new BizException(NOT_AUTHORIZED, "NOT_AUTHORIZED")); - }); - } + Flux filterResourceWithPermission(String userId, Collection resourceIds, ResourceAction resourceAction); + + Mono checkResourcePermissionWithError(String userId, String resourceId, ResourceAction action); @PossibleEmptyMono - public Mono getMaxMatchingPermission(String userId, String resourceId, ResourceAction resourceAction) { - return getMaxMatchingPermission(userId, Collections.singleton(resourceId), resourceAction) - .flatMap(map -> { - ResourcePermission resourcePermission = map.get(resourceId); - if (resourcePermission == null) { - return Mono.empty(); - } - return Mono.just(resourcePermission); - }); - } - - /** - * If current user has enough permissions for all resources. - */ - public Mono haveAllEnoughPermissions(String userId, Collection resourceIds, ResourceAction resourceAction) { - return getMaxMatchingPermission(userId, resourceIds, resourceAction) - .map(map -> map.keySet().containsAll(resourceIds)); - } - - public Mono> getMaxMatchingPermission(String userId, - Collection resourceIds, ResourceAction resourceAction) { - return getAllMatchingPermissions(userId, resourceIds, resourceAction) - .flatMapIterable(Map::entrySet) - .filter(it -> CollectionUtils.isNotEmpty(it.getValue())) - .collectMap(Entry::getKey, entry -> getMaxRole(entry.getValue())); - } - - @SuppressWarnings("OptionalGetWithoutIsPresent") - private ResourcePermission getMaxRole(List permissions) { - return permissions.stream() - .max(Comparator.comparingInt(it -> it.getResourceRole().getRoleWeight())) - .get(); - } - - public Mono checkAndReturnMaxPermission(String userId, String resourceId, ResourceAction resourceAction) { - return getMaxMatchingPermission(userId, Collections.singleton(resourceId), resourceAction) - .flatMap(permissionMap -> { - if (!permissionMap.containsKey(resourceId)) { - return ofError(NOT_AUTHORIZED, "NOT_AUTHORIZED"); - } - return Mono.just(permissionMap.get(resourceId)); - }); - } - - public Mono checkUserPermissionStatusOnResource - (String userId, String resourceId, ResourceAction resourceAction) { - ResourceType resourceType = resourceAction.getResourceType(); - var resourcePermissionHandler = getResourcePermissionHandler(resourceType); - return resourcePermissionHandler.checkUserPermissionStatusOnResource(userId, resourceId, resourceAction); - } - - public Mono checkUserPermissionStatusOnApplication - (String userId, String resourceId, ResourceAction resourceAction, ApplicationRequestType requestType) { - ResourceType resourceType = resourceAction.getResourceType(); - var resourcePermissionHandler = getResourcePermissionHandler(resourceType); - return resourcePermissionHandler.checkUserPermissionStatusOnApplication(userId, resourceId, resourceAction, requestType); -} - - - public Mono removeUserApplicationPermission(String appId, String userId) { - return repository.removePermissionBy(ResourceType.APPLICATION, appId, ResourceHolder.USER, userId); - } - - public Mono removeUserDatasourcePermission(String appId, String userId) { - return repository.removePermissionBy(ResourceType.APPLICATION, appId, ResourceHolder.USER, userId); - } - - public Mono getUserAssignedPermissionForApplication(String applicationId, String userId) { - return repository.getByResourceTypeAndResourceIdAndTargetId(ResourceType.APPLICATION, - applicationId, ResourceHolder.USER, userId); - } + Mono getMaxMatchingPermission(String userId, String resourceId, ResourceAction resourceAction); + + Mono haveAllEnoughPermissions(String userId, Collection resourceIds, ResourceAction resourceAction); + + Mono> getMaxMatchingPermission(String userId, + Collection resourceIds, ResourceAction resourceAction); + + Mono checkAndReturnMaxPermission(String userId, String resourceId, ResourceAction resourceAction); + + Mono checkUserPermissionStatusOnResource + (String userId, String resourceId, ResourceAction resourceAction); + + Mono checkUserPermissionStatusOnApplication + (String userId, String resourceId, ResourceAction resourceAction, ApplicationRequestType requestType); + + Mono removeUserApplicationPermission(String appId, String userId); + + Mono removeUserDatasourcePermission(String appId, String userId); + + Mono getUserAssignedPermissionForApplication(String applicationId, String userId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionServiceImpl.java new file mode 100644 index 000000000..41b464ffd --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionServiceImpl.java @@ -0,0 +1,250 @@ +package org.lowcoder.domain.permission.service; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.lowcoder.domain.application.model.ApplicationRequestType; +import org.lowcoder.domain.permission.model.*; +import org.lowcoder.infra.annotation.NonEmptyMono; +import org.lowcoder.infra.annotation.PossibleEmptyMono; +import org.lowcoder.sdk.exception.BizException; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.*; +import java.util.Map.Entry; + +import static java.util.Collections.singleton; +import static org.apache.commons.collections4.SetUtils.emptyIfNull; +import static org.lowcoder.sdk.exception.BizError.INVALID_PERMISSION_OPERATION; +import static org.lowcoder.sdk.exception.BizError.NOT_AUTHORIZED; +import static org.lowcoder.sdk.util.ExceptionUtils.ofError; +import static org.lowcoder.sdk.util.ExceptionUtils.ofException; + +@RequiredArgsConstructor +@Service +public class ResourcePermissionServiceImpl implements ResourcePermissionService { + + private final ResourcePermissionRepository repository; + @Qualifier("applicationPermissionHandler") + private final ResourcePermissionHandlerService applicationPermissionHandler; + @Qualifier("datasourcePermissionHandler") + private final ResourcePermissionHandlerService datasourcePermissionHandler; + + @Override + public Mono>> getByResourceTypeAndResourceIds(ResourceType resourceType, + Collection resourceIds) { + return repository.getByResourceTypeAndResourceIds(resourceType, resourceIds); + } + + @Override + @NonEmptyMono + public Mono> getByResourceTypeAndResourceId(ResourceType resourceType, String resourceId) { + return repository.getByResourceTypeAndResourceId(resourceType, resourceId); + } + + @Override + @NonEmptyMono + public Mono> getByApplicationId(String applicationId) { + return getByResourceTypeAndResourceId(ResourceType.APPLICATION, applicationId); + } + + @Override + @NonEmptyMono + public Mono> getByDataSourceId(String dataSourceId) { + return getByResourceTypeAndResourceId(ResourceType.DATASOURCE, dataSourceId); + } + + @Override + public Mono insertBatchPermission(ResourceType resourceType, String resourceId, @Nullable Set userIds, + @Nullable Set groupIds, ResourceRole role) { + if (CollectionUtils.isEmpty(userIds) && CollectionUtils.isEmpty(groupIds)) { + return Mono.empty(); + } + return repository.insertBatchPermission(resourceType, resourceId, buildResourceHolders(emptyIfNull(userIds), emptyIfNull(groupIds)), role); + } + + private Multimap buildResourceHolders(@NotNull Set userIds, @NotNull Set groupIds) { + HashMultimap result = HashMultimap.create(); + for (String userId : userIds) { + result.put(ResourceHolder.USER, userId); + } + for (String groupId : groupIds) { + result.put(ResourceHolder.GROUP, groupId); + } + return result; + } + + @SuppressWarnings("SameParameterValue") + Mono addPermission(ResourceType resourceType, String resourceId, + ResourceHolder holderType, String holderId, + ResourceRole resourceRole) { + return repository.addPermission(resourceType, resourceId, holderType, holderId, resourceRole); + } + + @Override + public Mono addDataSourcePermissionToUser(String dataSourceId, + String userId, + ResourceRole role) { + return addPermission(ResourceType.DATASOURCE, dataSourceId, ResourceHolder.USER, userId, role); + } + + @Override + public Mono addApplicationPermissionToUser(String applicationId, + String userId, + ResourceRole role) { + return addPermission(ResourceType.APPLICATION, applicationId, ResourceHolder.USER, userId, role); + } + + @Override + public Mono addApplicationPermissionToGroup(String applicationId, + String groupId, + ResourceRole role) { + return addPermission(ResourceType.APPLICATION, applicationId, ResourceHolder.GROUP, groupId, role); + } + + @Override + public Mono getById(String permissionId) { + return repository.getById(permissionId); + } + + @Override + public Mono removeById(String permissionId) { + return repository.removePermissionById(permissionId); + } + + @Override + public Mono updateRoleById(String permissionId, ResourceRole role) { + return repository.updatePermissionRoleById(permissionId, role); + } + + /** + * @return map key: resourceId, value: all permissions user have for this resource + */ + private Mono>> getAllMatchingPermissions(String userId, + Collection resourceIds, + ResourceAction resourceAction) { + ResourceType resourceType = resourceAction.getResourceType(); + var resourcePermissionHandler = getResourcePermissionHandler(resourceType); + return resourcePermissionHandler.getAllMatchingPermissions(userId, resourceIds, resourceAction); + } + + private ResourcePermissionHandlerService getResourcePermissionHandler(ResourceType resourceType) { + if (resourceType == ResourceType.DATASOURCE) { + return datasourcePermissionHandler; + } + + if (resourceType == ResourceType.APPLICATION) { + return applicationPermissionHandler; + } + + throw ofException(INVALID_PERMISSION_OPERATION, "INVALID_PERMISSION_OPERATION", resourceType); + } + + @Override + public Flux filterResourceWithPermission(String userId, Collection resourceIds, ResourceAction resourceAction) { + return getAllMatchingPermissions(userId, resourceIds, resourceAction) + .flatMapIterable(Map::entrySet) + .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue())) + .map(Entry::getKey); + } + + @Override + public Mono checkResourcePermissionWithError(String userId, String resourceId, ResourceAction action) { + return getAllMatchingPermissions(userId, singleton(resourceId), action) + .flatMap(map -> { + List resourcePermissions = map.get(resourceId); + if (CollectionUtils.isNotEmpty(resourcePermissions)) { + return Mono.empty(); + } + return Mono.error(new BizException(NOT_AUTHORIZED, "NOT_AUTHORIZED")); + }); + } + + @Override + @PossibleEmptyMono + public Mono getMaxMatchingPermission(String userId, String resourceId, ResourceAction resourceAction) { + return getMaxMatchingPermission(userId, Collections.singleton(resourceId), resourceAction) + .flatMap(map -> { + ResourcePermission resourcePermission = map.get(resourceId); + if (resourcePermission == null) { + return Mono.empty(); + } + return Mono.just(resourcePermission); + }); + } + + /** + * If current user has enough permissions for all resources. + */ + @Override + public Mono haveAllEnoughPermissions(String userId, Collection resourceIds, ResourceAction resourceAction) { + return getMaxMatchingPermission(userId, resourceIds, resourceAction) + .map(map -> map.keySet().containsAll(resourceIds)); + } + + @Override + public Mono> getMaxMatchingPermission(String userId, + Collection resourceIds, ResourceAction resourceAction) { + return getAllMatchingPermissions(userId, resourceIds, resourceAction) + .flatMapIterable(Map::entrySet) + .filter(it -> CollectionUtils.isNotEmpty(it.getValue())) + .collectMap(Entry::getKey, entry -> getMaxRole(entry.getValue())); + } + + @SuppressWarnings("OptionalGetWithoutIsPresent") + private ResourcePermission getMaxRole(List permissions) { + return permissions.stream() + .max(Comparator.comparingInt(it -> it.getResourceRole().getRoleWeight())) + .get(); + } + + @Override + public Mono checkAndReturnMaxPermission(String userId, String resourceId, ResourceAction resourceAction) { + return getMaxMatchingPermission(userId, Collections.singleton(resourceId), resourceAction) + .flatMap(permissionMap -> { + if (!permissionMap.containsKey(resourceId)) { + return ofError(NOT_AUTHORIZED, "NOT_AUTHORIZED"); + } + return Mono.just(permissionMap.get(resourceId)); + }); + } + + @Override + public Mono checkUserPermissionStatusOnResource + (String userId, String resourceId, ResourceAction resourceAction) { + ResourceType resourceType = resourceAction.getResourceType(); + var resourcePermissionHandler = getResourcePermissionHandler(resourceType); + return resourcePermissionHandler.checkUserPermissionStatusOnResource(userId, resourceId, resourceAction); + } + + @Override + public Mono checkUserPermissionStatusOnApplication + (String userId, String resourceId, ResourceAction resourceAction, ApplicationRequestType requestType) { + ResourceType resourceType = resourceAction.getResourceType(); + var resourcePermissionHandler = getResourcePermissionHandler(resourceType); + return resourcePermissionHandler.checkUserPermissionStatusOnApplication(userId, resourceId, resourceAction, requestType); +} + + + @Override + public Mono removeUserApplicationPermission(String appId, String userId) { + return repository.removePermissionBy(ResourceType.APPLICATION, appId, ResourceHolder.USER, userId); + } + + @Override + public Mono removeUserDatasourcePermission(String appId, String userId) { + return repository.removePermissionBy(ResourceType.APPLICATION, appId, ResourceHolder.USER, userId); + } + + @Override + public Mono getUserAssignedPermissionForApplication(String applicationId, String userId) { + return repository.getByResourceTypeAndResourceIdAndTargetId(ResourceType.APPLICATION, + applicationId, ResourceHolder.USER, userId); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/impl/ResourcePermissionRepositoryImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/impl/ResourcePermissionRepositoryImpl.java index 87bfa85e9..91c68b828 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/impl/ResourcePermissionRepositoryImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/impl/ResourcePermissionRepositoryImpl.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.permission.model.ResourceHolder; import org.lowcoder.domain.permission.model.ResourcePermission; import org.lowcoder.domain.permission.model.ResourceRole; @@ -26,15 +27,12 @@ import reactor.core.publisher.Mono; @Slf4j -@Lazy +@RequiredArgsConstructor @Service public class ResourcePermissionRepositoryImpl implements ResourcePermissionRepository { - @Autowired - private MongoUpsertHelper mongoUpsertHelper; - - @Autowired - private BiRelationService biRelationService; + private final MongoUpsertHelper mongoUpsertHelper; + private final BiRelationService biRelationService; @Override public Mono>> getByResourceTypeAndResourceIds(ResourceType resourceType, diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionService.java new file mode 100644 index 000000000..120172b9b --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionService.java @@ -0,0 +1,12 @@ +package org.lowcoder.domain.permission.solution; + +import org.lowcoder.domain.user.model.User; +import reactor.core.publisher.Mono; + +import java.util.List; + +public interface SuggestAppAdminSolutionService { + Mono> getApplicationAdminUsers(String applicationId, int limit); + + Mono getSuggestAppAdminNames(String applicationId); +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolution.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionServiceImpl.java similarity index 89% rename from server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolution.java rename to server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionServiceImpl.java index 4b648bf84..a5063416c 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolution.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/solution/SuggestAppAdminSolutionServiceImpl.java @@ -1,15 +1,7 @@ package org.lowcoder.domain.permission.solution; -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Sets.newHashSet; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; import org.lowcoder.domain.group.model.GroupMember; import org.lowcoder.domain.group.service.GroupMemberService; import org.lowcoder.domain.permission.model.ResourcePermission; @@ -17,26 +9,29 @@ import org.lowcoder.domain.permission.service.ResourcePermissionService; import org.lowcoder.domain.user.model.User; import org.lowcoder.domain.user.service.UserService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Service -public class SuggestAppAdminSolution { +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; - private static final int LIMIT_COUNT_FOR_DISPLAY_ADMIN_NAMES = 7; +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; - @Autowired - private GroupMemberService groupMemberService; +@RequiredArgsConstructor +@Service +public class SuggestAppAdminSolutionServiceImpl implements SuggestAppAdminSolutionService { - @Autowired - private UserService userService; + private static final int LIMIT_COUNT_FOR_DISPLAY_ADMIN_NAMES = 7; - @Autowired - private ResourcePermissionService resourcePermissionService; + private final GroupMemberService groupMemberService; + private final UserService userService; + private final ResourcePermissionService resourcePermissionService; + @Override public Mono> getApplicationAdminUsers(String applicationId, int limit) { return resourcePermissionService.getByApplicationId(applicationId) .flatMap(permissions -> getSuggestAdminIds(limit, permissions)) @@ -82,6 +77,7 @@ private Mono> getSuggestAdminIds(int limit, List getSuggestAppAdminNames(String applicationId) { return getApplicationAdminUsers(applicationId, LIMIT_COUNT_FOR_DISPLAY_ADMIN_NAMES) .map(users -> users.stream() diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/plugin/client/DatasourcePluginClient.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/plugin/client/DatasourcePluginClient.java index 101d2986c..f2aa878bb 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/plugin/client/DatasourcePluginClient.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/plugin/client/DatasourcePluginClient.java @@ -1,13 +1,7 @@ package org.lowcoder.domain.plugin.client; -import static org.lowcoder.sdk.constants.GlobalContext.REQUEST; - -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -19,19 +13,25 @@ import org.lowcoder.sdk.exception.ServerException; import org.lowcoder.sdk.models.DatasourceTestResult; import org.lowcoder.sdk.models.QueryExecutionResult; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static org.lowcoder.sdk.constants.GlobalContext.REQUEST; + @Slf4j +@RequiredArgsConstructor @Component public class DatasourcePluginClient implements NodeServerClient { @@ -44,10 +44,8 @@ public class DatasourcePluginClient implements NodeServerClient { .exchangeStrategies(EXCHANGE_STRATEGIES) .build(); - @Autowired - private CommonConfigHelper commonConfigHelper; - @Autowired - private NodeServerHelper nodeServerHelper; + private final CommonConfigHelper commonConfigHelper; + private final NodeServerHelper nodeServerHelper; private static final String PLUGINS_PATH = "plugins"; private static final String RUN_PLUGIN_QUERY = "runPluginQuery"; @@ -78,7 +76,7 @@ public Mono> getPluginDynamicConfig(List() { }); } - log.error("request /getPluginDynamicConfig error.{},{}", getPluginDynamicConfigRequestDTOS, response.rawStatusCode()); + log.error("request /getPluginDynamicConfig error.{},{}", getPluginDynamicConfigRequestDTOS, response.statusCode().value()); return Mono.error(new ServerException("get dynamic config error")); }) .timeout(Duration.ofSeconds(10)) @@ -105,7 +103,7 @@ public Flux getDatasourcePluginDefinitions() { return response.bodyToMono(new ParameterizedTypeReference>() { }); } - log.error("request /plugins error.{}", response.rawStatusCode()); + log.error("request /plugins error.{}", response.statusCode().value()); return Mono.just(Collections.emptyList()); }) .timeout(Duration.ofSeconds(10)) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordService.java index 816c12b55..4e412fd50 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordService.java @@ -1,66 +1,23 @@ package org.lowcoder.domain.query.service; -import static org.lowcoder.sdk.exception.BizError.LIBRARY_QUERY_NOT_FOUND; -import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; - -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.lowcoder.domain.query.model.LibraryQueryRecord; -import org.lowcoder.domain.query.repository.LibraryQueryRecordRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Mono; -@Service -public class LibraryQueryRecordService { - - @Autowired - private LibraryQueryRecordRepository libraryQueryRecordRepository; - - public Mono insert(LibraryQueryRecord libraryQueryRecord) { - return libraryQueryRecordRepository.save(libraryQueryRecord); - } - - /** - * get all published versions - */ - public Mono> getByLibraryQueryId(String libraryQueryId) { - return libraryQueryRecordRepository.findByLibraryQueryId(libraryQueryId) - .sort(Comparator.comparing(LibraryQueryRecord::getCreatedAt).reversed()) - .collectList(); - } +import java.util.List; +import java.util.Map; - public Mono>> getByLibraryQueryIdIn(List libraryQueryIdList) { - return libraryQueryRecordRepository.findByLibraryQueryIdIn(libraryQueryIdList) - .sort(Comparator.comparing(LibraryQueryRecord::getCreatedAt).reversed()) - .collectList() - .map(libraryQueryRecords -> libraryQueryRecords.stream() - .collect(Collectors.groupingBy(LibraryQueryRecord::getLibraryQueryId))); - } +public interface LibraryQueryRecordService { + Mono insert(LibraryQueryRecord libraryQueryRecord); - public Mono getById(String id) { - return libraryQueryRecordRepository.findById(id) - .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); - } + Mono> getByLibraryQueryId(String libraryQueryId); - /** - * get the latest published version - */ - public Mono getLatestRecordByLibraryQueryId(String libraryQueryId) { - return libraryQueryRecordRepository.findTop1ByLibraryQueryIdOrderByCreatedAtDesc(libraryQueryId); - } + Mono>> getByLibraryQueryIdIn(List libraryQueryIdList); - public Mono deleteAllLibraryQueryTagByLibraryQueryId(String libraryQueryId) { - return libraryQueryRecordRepository.deleteByLibraryQueryId(libraryQueryId); - } + Mono getById(String id); - public Mono deleteById(String id) { - return libraryQueryRecordRepository.deleteById(id); - } + Mono getLatestRecordByLibraryQueryId(String libraryQueryId); + Mono deleteAllLibraryQueryTagByLibraryQueryId(String libraryQueryId); + Mono deleteById(String id); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordServiceImpl.java new file mode 100644 index 000000000..1ec370eeb --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryRecordServiceImpl.java @@ -0,0 +1,74 @@ +package org.lowcoder.domain.query.service; + +import static org.lowcoder.sdk.exception.BizError.LIBRARY_QUERY_NOT_FOUND; +import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.query.model.LibraryQueryRecord; +import org.lowcoder.domain.query.repository.LibraryQueryRecordRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class LibraryQueryRecordServiceImpl implements LibraryQueryRecordService { + + private final LibraryQueryRecordRepository libraryQueryRecordRepository; + + @Override + public Mono insert(LibraryQueryRecord libraryQueryRecord) { + return libraryQueryRecordRepository.save(libraryQueryRecord); + } + + /** + * get all published versions + */ + @Override + public Mono> getByLibraryQueryId(String libraryQueryId) { + return libraryQueryRecordRepository.findByLibraryQueryId(libraryQueryId) + .sort(Comparator.comparing(LibraryQueryRecord::getCreatedAt).reversed()) + .collectList(); + } + + @Override + public Mono>> getByLibraryQueryIdIn(List libraryQueryIdList) { + return libraryQueryRecordRepository.findByLibraryQueryIdIn(libraryQueryIdList) + .sort(Comparator.comparing(LibraryQueryRecord::getCreatedAt).reversed()) + .collectList() + .map(libraryQueryRecords -> libraryQueryRecords.stream() + .collect(Collectors.groupingBy(LibraryQueryRecord::getLibraryQueryId))); + } + + @Override + public Mono getById(String id) { + return libraryQueryRecordRepository.findById(id) + .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); + } + + /** + * get the latest published version + */ + @Override + public Mono getLatestRecordByLibraryQueryId(String libraryQueryId) { + return libraryQueryRecordRepository.findTop1ByLibraryQueryIdOrderByCreatedAtDesc(libraryQueryId); + } + + @Override + public Mono deleteAllLibraryQueryTagByLibraryQueryId(String libraryQueryId) { + return libraryQueryRecordRepository.deleteByLibraryQueryId(libraryQueryId); + } + + @Override + public Mono deleteById(String id) { + return libraryQueryRecordRepository.deleteById(id); + } + + +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryService.java index 8ec5faafe..2f1193d9f 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryService.java @@ -1,74 +1,28 @@ package org.lowcoder.domain.query.service; -import static org.lowcoder.sdk.exception.BizError.LIBRARY_QUERY_NOT_FOUND; -import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; - -import java.util.Map; - import org.lowcoder.domain.query.model.BaseQuery; import org.lowcoder.domain.query.model.LibraryQuery; -import org.lowcoder.domain.query.model.LibraryQueryRecord; -import org.lowcoder.domain.query.repository.LibraryQueryRepository; -import org.lowcoder.infra.mongo.MongoUpsertHelper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Service -public class LibraryQueryService { - - @Autowired - private LibraryQueryRepository libraryQueryRepository; - - @Autowired - private LibraryQueryRecordService libraryQueryRecordService; - - @Autowired - private MongoUpsertHelper mongoUpsertHelper; +import java.util.Map; - public Mono getById(String libraryQueryId) { - return libraryQueryRepository.findById(libraryQueryId) - .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); - } +public interface LibraryQueryService { + Mono getById(String libraryQueryId); - public Mono getByName(String libraryQueryName) { - return libraryQueryRepository.findByName(libraryQueryName) - .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); - } + Mono getByName(String libraryQueryName); - public Flux getByOrganizationId(String organizationId) { - return libraryQueryRepository.findByOrganizationId(organizationId); - } + Flux getByOrganizationId(String organizationId); - public Mono insert(LibraryQuery libraryQuery) { - return libraryQueryRepository.save(libraryQuery); - } + Mono insert(LibraryQuery libraryQuery); - public Mono update(String libraryQueryId, LibraryQuery libraryQuery) { - return mongoUpsertHelper.updateById(libraryQuery, libraryQueryId); - } + Mono update(String libraryQueryId, LibraryQuery libraryQuery); - public Mono delete(String libraryQueryId) { - return libraryQueryRepository.deleteById(libraryQueryId); - } + Mono delete(String libraryQueryId); - public Mono getEditingBaseQueryByLibraryQueryId(String libraryQueryId) { - return getById(libraryQueryId).map(LibraryQuery::getQuery); - } + Mono getEditingBaseQueryByLibraryQueryId(String libraryQueryId); - public Mono getLiveBaseQueryByLibraryQueryId(String libraryQueryId) { - return libraryQueryRecordService.getLatestRecordByLibraryQueryId(libraryQueryId) - .map(LibraryQueryRecord::getQuery) - .switchIfEmpty(getById(libraryQueryId) - .map(LibraryQuery::getQuery)); - } + Mono getLiveBaseQueryByLibraryQueryId(String libraryQueryId); - public Mono> getLiveDSLByLibraryQueryId(String libraryQueryId) { - return libraryQueryRecordService.getLatestRecordByLibraryQueryId(libraryQueryId) - .map(LibraryQueryRecord::getLibraryQueryDSL) - .switchIfEmpty(getById(libraryQueryId) - .map(LibraryQuery::getLibraryQueryDSL)); - } + Mono> getLiveDSLByLibraryQueryId(String libraryQueryId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryServiceImpl.java new file mode 100644 index 000000000..7c25fa562 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/LibraryQueryServiceImpl.java @@ -0,0 +1,80 @@ +package org.lowcoder.domain.query.service; + +import static org.lowcoder.sdk.exception.BizError.LIBRARY_QUERY_NOT_FOUND; +import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; + +import java.util.Map; + +import lombok.RequiredArgsConstructor; +import org.lowcoder.domain.query.model.BaseQuery; +import org.lowcoder.domain.query.model.LibraryQuery; +import org.lowcoder.domain.query.model.LibraryQueryRecord; +import org.lowcoder.domain.query.repository.LibraryQueryRepository; +import org.lowcoder.infra.mongo.MongoUpsertHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequiredArgsConstructor +@Service +public class LibraryQueryServiceImpl implements LibraryQueryService { + + private final LibraryQueryRepository libraryQueryRepository; + private final LibraryQueryRecordService libraryQueryRecordService; + private final MongoUpsertHelper mongoUpsertHelper; + + @Override + public Mono getById(String libraryQueryId) { + return libraryQueryRepository.findById(libraryQueryId) + .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); + } + + @Override + public Mono getByName(String libraryQueryName) { + return libraryQueryRepository.findByName(libraryQueryName) + .switchIfEmpty(deferredError(LIBRARY_QUERY_NOT_FOUND, "LIBRARY_QUERY_NOT_FOUND")); + } + + @Override + public Flux getByOrganizationId(String organizationId) { + return libraryQueryRepository.findByOrganizationId(organizationId); + } + + @Override + public Mono insert(LibraryQuery libraryQuery) { + return libraryQueryRepository.save(libraryQuery); + } + + @Override + public Mono update(String libraryQueryId, LibraryQuery libraryQuery) { + return mongoUpsertHelper.updateById(libraryQuery, libraryQueryId); + } + + @Override + public Mono delete(String libraryQueryId) { + return libraryQueryRepository.deleteById(libraryQueryId); + } + + @Override + public Mono getEditingBaseQueryByLibraryQueryId(String libraryQueryId) { + return getById(libraryQueryId).map(LibraryQuery::getQuery); + } + + @Override + public Mono getLiveBaseQueryByLibraryQueryId(String libraryQueryId) { + return libraryQueryRecordService.getLatestRecordByLibraryQueryId(libraryQueryId) + .map(LibraryQueryRecord::getQuery) + .switchIfEmpty(getById(libraryQueryId) + .map(LibraryQuery::getQuery)); + } + + @Override + public Mono> getLiveDSLByLibraryQueryId(String libraryQueryId) { + return libraryQueryRecordService.getLatestRecordByLibraryQueryId(libraryQueryId) + .map(LibraryQueryRecord::getLibraryQueryDSL) + .switchIfEmpty(getById(libraryQueryId) + .map(LibraryQuery::getLibraryQueryDSL)); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java index 6a4d1fb02..e78f4655b 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java @@ -1,122 +1,13 @@ package org.lowcoder.domain.query.service; -import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.datasource.model.Datasource; -import org.lowcoder.domain.datasource.model.DatasourceConnectionHolder; -import org.lowcoder.domain.datasource.service.DatasourceConnectionPool; -import org.lowcoder.domain.plugin.client.DatasourcePluginClient; -import org.lowcoder.domain.plugin.service.DatasourceMetaInfoService; -import org.lowcoder.domain.query.util.QueryTimeoutUtils; -import org.lowcoder.sdk.config.CommonConfig; -import org.lowcoder.sdk.exception.BizException; -import org.lowcoder.sdk.exception.PluginException; -import org.lowcoder.sdk.models.JsDatasourceConnectionConfig; -import org.lowcoder.sdk.models.Property; import org.lowcoder.sdk.models.QueryExecutionResult; -import org.lowcoder.sdk.query.QueryExecutionContext; import org.lowcoder.sdk.query.QueryVisitorContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; -import java.time.Duration; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; -import static org.lowcoder.sdk.exception.BizError.QUERY_EXECUTION_ERROR; -import static org.lowcoder.sdk.exception.PluginCommonError.QUERY_EXECUTION_TIMEOUT; -import static org.lowcoder.sdk.util.ExceptionUtils.ofException; - -@Slf4j -@Service -public class QueryExecutionService { - - @Autowired - private DatasourceConnectionPool datasourceConnectionPool; - - @Autowired - private DatasourceMetaInfoService datasourceMetaInfoService; - - @Autowired - private DatasourcePluginClient datasourcePluginClient; - - @Autowired - private CommonConfig common; - - public Mono executeQuery(Datasource datasource, Map queryConfig, Map requestParams, - String timeoutStr, QueryVisitorContext queryVisitorContext) { - - int timeoutMs = QueryTimeoutUtils.parseQueryTimeoutMs(timeoutStr, requestParams, common.getMaxQueryTimeout()); - queryConfig.putIfAbsent("timeoutMs", String.valueOf(timeoutMs)); - - return Mono.defer(() -> { - if (datasourceMetaInfoService.isJsDatasourcePlugin(datasource.getType())) { - return executeByNodeJs(datasource, queryConfig, requestParams, queryVisitorContext); - } - return executeLocally(datasource, queryConfig, requestParams, queryVisitorContext); - }) - .timeout(Duration.ofMillis(timeoutMs)) - .onErrorMap(TimeoutException.class, e -> new PluginException(QUERY_EXECUTION_TIMEOUT, "PLUGIN_EXECUTION_TIMEOUT", timeoutMs)) - .onErrorResume(PluginException.class, pluginException -> Mono.just(QueryExecutionResult.error(pluginException))) - .onErrorMap(exception -> { - if (exception instanceof BizException) { - return exception; - } - log.error("query exception", exception); - return ofException(QUERY_EXECUTION_ERROR, "QUERY_EXECUTION_ERROR", exception.getMessage()); - }); - } - - private Mono executeLocally(Datasource datasource, Map queryConfig, Map requestParams, - QueryVisitorContext queryVisitorContext) { - var queryExecutor = datasourceMetaInfoService.getQueryExecutor(datasource.getType()); - - return queryExecutor.buildQueryExecutionContextMono(datasource.getDetailConfig(), queryConfig, requestParams, queryVisitorContext) - .zipWhen(context -> datasourceConnectionPool.getOrCreateConnection(datasource)) - .flatMap(tuple -> { - QueryExecutionContext queryExecutionRequest = tuple.getT1(); - DatasourceConnectionHolder connectionHolder = tuple.getT2(); - return queryExecutor.doExecuteQuery(connectionHolder.connection(), queryExecutionRequest) - .doOnError(connectionHolder::onQueryError); - }); - } - - private Mono executeByNodeJs(Datasource datasource, Map queryConfig, Map requestParams, QueryVisitorContext queryVisitorContext) { - List> context = requestParams.entrySet() - .stream() - .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) - .collect(Collectors.toList()); - - //forward cookies to js datasource - List> cookies = queryVisitorContext.getCookies().entrySet() - .stream() - .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) - .collect(Collectors.toList()); - context.addAll(cookies); - - // forward oauth2 access token in case of oauth2(inherit from login) - - if(datasource.getDetailConfig() instanceof JsDatasourceConnectionConfig jsDatasourceConnectionConfig - && jsDatasourceConnectionConfig.isOauth2InheritFromLogin()) { - return Mono.defer(() -> injectOauth2Token(queryVisitorContext, context)) - .then(Mono.defer(() -> datasourcePluginClient.executeQuery(datasource.getType(), queryConfig, context, datasource.getDetailConfig()))); - } else { - return datasourcePluginClient.executeQuery(datasource.getType(), queryConfig, context, datasource.getDetailConfig()); - } - - - } - - private Mono injectOauth2Token(QueryVisitorContext queryVisitorContext, List> context) { - return queryVisitorContext.getAuthTokenMono() - .doOnNext(properties -> { - for (Property property : properties) { - context.add(Map.of("key" , property.getKey(), "value", property.getValue())); - } - }) - .then(); - } +public interface QueryExecutionService { + Mono executeQuery(Datasource datasource, Map queryConfig, Map requestParams, + String timeoutStr, QueryVisitorContext queryVisitorContext); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionServiceImpl.java new file mode 100644 index 000000000..6807ebc32 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionServiceImpl.java @@ -0,0 +1,117 @@ +package org.lowcoder.domain.query.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.lowcoder.domain.datasource.model.Datasource; +import org.lowcoder.domain.datasource.model.DatasourceConnectionHolder; +import org.lowcoder.domain.datasource.service.DatasourceConnectionPool; +import org.lowcoder.domain.plugin.client.DatasourcePluginClient; +import org.lowcoder.domain.plugin.service.DatasourceMetaInfoService; +import org.lowcoder.domain.query.util.QueryTimeoutUtils; +import org.lowcoder.sdk.config.CommonConfig; +import org.lowcoder.sdk.exception.BizException; +import org.lowcoder.sdk.exception.PluginException; +import org.lowcoder.sdk.models.JsDatasourceConnectionConfig; +import org.lowcoder.sdk.models.Property; +import org.lowcoder.sdk.models.QueryExecutionResult; +import org.lowcoder.sdk.query.QueryExecutionContext; +import org.lowcoder.sdk.query.QueryVisitorContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import static org.lowcoder.sdk.exception.BizError.QUERY_EXECUTION_ERROR; +import static org.lowcoder.sdk.exception.PluginCommonError.QUERY_EXECUTION_TIMEOUT; +import static org.lowcoder.sdk.util.ExceptionUtils.ofException; + +@RequiredArgsConstructor +@Slf4j +@Service +public class QueryExecutionServiceImpl implements QueryExecutionService { + + private final DatasourceConnectionPool datasourceConnectionPool; + private final DatasourceMetaInfoService datasourceMetaInfoService; + private final DatasourcePluginClient datasourcePluginClient; + private final CommonConfig common; + + @Override + public Mono executeQuery(Datasource datasource, Map queryConfig, Map requestParams, + String timeoutStr, QueryVisitorContext queryVisitorContext) { + + int timeoutMs = QueryTimeoutUtils.parseQueryTimeoutMs(timeoutStr, requestParams, common.getMaxQueryTimeout()); + queryConfig.putIfAbsent("timeoutMs", String.valueOf(timeoutMs)); + + return Mono.defer(() -> { + if (datasourceMetaInfoService.isJsDatasourcePlugin(datasource.getType())) { + return executeByNodeJs(datasource, queryConfig, requestParams, queryVisitorContext); + } + return executeLocally(datasource, queryConfig, requestParams, queryVisitorContext); + }) + .timeout(Duration.ofMillis(timeoutMs)) + .onErrorMap(TimeoutException.class, e -> new PluginException(QUERY_EXECUTION_TIMEOUT, "PLUGIN_EXECUTION_TIMEOUT", timeoutMs)) + .onErrorResume(PluginException.class, pluginException -> Mono.just(QueryExecutionResult.error(pluginException))) + .onErrorMap(exception -> { + if (exception instanceof BizException) { + return exception; + } + log.error("query exception", exception); + return ofException(QUERY_EXECUTION_ERROR, "QUERY_EXECUTION_ERROR", exception.getMessage()); + }); + } + + private Mono executeLocally(Datasource datasource, Map queryConfig, Map requestParams, + QueryVisitorContext queryVisitorContext) { + var queryExecutor = datasourceMetaInfoService.getQueryExecutor(datasource.getType()); + + return queryExecutor.buildQueryExecutionContextMono(datasource.getDetailConfig(), queryConfig, requestParams, queryVisitorContext) + .zipWhen(context -> datasourceConnectionPool.getOrCreateConnection(datasource)) + .flatMap(tuple -> { + QueryExecutionContext queryExecutionRequest = tuple.getT1(); + DatasourceConnectionHolder connectionHolder = tuple.getT2(); + return queryExecutor.doExecuteQuery(connectionHolder.connection(), queryExecutionRequest) + .doOnError(connectionHolder::onQueryError); + }); + } + + private Mono executeByNodeJs(Datasource datasource, Map queryConfig, Map requestParams, QueryVisitorContext queryVisitorContext) { + List> context = requestParams.entrySet() + .stream() + .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) + .collect(Collectors.toList()); + + //forward cookies to js datasource + List> cookies = queryVisitorContext.getCookies().entrySet() + .stream() + .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) + .collect(Collectors.toList()); + context.addAll(cookies); + + // forward oauth2 access token in case of oauth2(inherit from login) + + if(datasource.getDetailConfig() instanceof JsDatasourceConnectionConfig jsDatasourceConnectionConfig + && jsDatasourceConnectionConfig.isOauth2InheritFromLogin()) { + return Mono.defer(() -> injectOauth2Token(queryVisitorContext, context)) + .then(Mono.defer(() -> datasourcePluginClient.executeQuery(datasource.getType(), queryConfig, context, datasource.getDetailConfig()))); + } else { + return datasourcePluginClient.executeQuery(datasource.getType(), queryConfig, context, datasource.getDetailConfig()); + } + + + } + + private Mono injectOauth2Token(QueryVisitorContext queryVisitorContext, List> context) { + return queryVisitorContext.getAuthTokenMono() + .doOnNext(properties -> { + for (Property property : properties) { + context.add(Map.of("key" , property.getKey(), "value", property.getValue())); + } + }) + .then(); + } +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionService.java new file mode 100644 index 000000000..7576a8ed0 --- /dev/null +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionService.java @@ -0,0 +1,15 @@ +package org.lowcoder.domain.solutions; + +import org.lowcoder.domain.application.model.Application; +import org.lowcoder.infra.annotation.NonEmptyMono; +import reactor.core.publisher.Mono; + +import java.util.Collection; +import java.util.Set; + +public interface TemplateSolutionService { + Mono createFromTemplate(String templateId, String orgId, String visitorId); + + @NonEmptyMono + Mono> getTemplateApplicationIds(Collection applicationIds); +} diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolution.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionServiceImpl.java similarity index 94% rename from server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolution.java rename to server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionServiceImpl.java index 85d73b84b..fb55cb173 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolution.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/solutions/TemplateSolutionServiceImpl.java @@ -1,19 +1,7 @@ package org.lowcoder.domain.solutions; -import static java.util.Objects.isNull; -import static org.lowcoder.sdk.exception.BizError.TEMPLATE_NOT_CORRECT; -import static org.lowcoder.sdk.exception.BizError.TEMPLATE_NOT_EXIST; -import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; -import static org.lowcoder.sdk.util.ExceptionUtils.ofError; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.tuple.Pair; import org.lowcoder.domain.application.model.Application; @@ -28,28 +16,35 @@ import org.lowcoder.infra.annotation.NonEmptyMono; import org.lowcoder.infra.util.TupleUtils; import org.lowcoder.sdk.util.JsonUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Lazy -@Service -public class TemplateSolution { +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; - private static final int RANDOM_LENGTH = 6; +import static java.util.Objects.isNull; +import static org.lowcoder.sdk.exception.BizError.TEMPLATE_NOT_CORRECT; +import static org.lowcoder.sdk.exception.BizError.TEMPLATE_NOT_EXIST; +import static org.lowcoder.sdk.util.ExceptionUtils.deferredError; +import static org.lowcoder.sdk.util.ExceptionUtils.ofError; - @Autowired - private TemplateService templateService; +@RequiredArgsConstructor +@Service +public class TemplateSolutionServiceImpl implements TemplateSolutionService { - @Autowired - private DatasourceService datasourceService; + private static final int RANDOM_LENGTH = 6; - @Autowired - private ApplicationService applicationService; + private final TemplateService templateService; + private final DatasourceService datasourceService; + @Lazy + private final ApplicationService applicationService; + @Override public Mono createFromTemplate(String templateId, String orgId, String visitorId) { return templateService.getById(templateId) .switchIfEmpty(deferredError(TEMPLATE_NOT_EXIST, "TEMPLATE_NOT_EXIST")) @@ -80,6 +75,7 @@ public Mono createFromTemplate(String templateId, String orgId, Str } + @Override @NonEmptyMono public Mono> getTemplateApplicationIds(Collection applicationIds) { return templateService.getByApplicationIds(applicationIds) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/repository/TemplateRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/repository/TemplateRepository.java index 0e6762c3f..8ddb5416b 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/repository/TemplateRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/repository/TemplateRepository.java @@ -1,16 +1,14 @@ package org.lowcoder.domain.template.repository; -import java.util.Collection; - -import javax.annotation.Nonnull; - +import jakarta.annotation.Nonnull; import org.lowcoder.domain.template.model.Template; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import org.springframework.stereotype.Repository; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Collection; + @Repository public interface TemplateRepository extends ReactiveMongoRepository { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/service/TemplateService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/service/TemplateService.java index 6e2831f48..a440ade39 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/service/TemplateService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/template/service/TemplateService.java @@ -1,32 +1,15 @@ package org.lowcoder.domain.template.service; -import java.util.Collection; - import org.lowcoder.domain.template.model.Template; -import org.lowcoder.domain.template.repository.TemplateRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -@Slf4j -@Service -public class TemplateService { - - @Autowired - private TemplateRepository templateRepository; +import java.util.Collection; - public Mono