From dbb72c4778c10742b3befe70061b6a927eecb940 Mon Sep 17 00:00:00 2001 From: sidhantgoel Date: Wed, 21 Dec 2022 23:35:11 +0530 Subject: [PATCH] feat: Support for Import/Export without ACL (#18997) For EE RBAC compatibility, import/export for git sync does not use ACL --- .../repositories/AppsmithRepository.java | 5 + .../ce/BaseAppsmithRepositoryCEImpl.java | 310 +++++++++++------- .../CustomActionCollectionRepositoryCE.java | 3 + ...ustomActionCollectionRepositoryCEImpl.java | 10 + .../ce/CustomApplicationRepositoryCE.java | 3 + .../ce/CustomApplicationRepositoryCEImpl.java | 12 + .../ce/CustomDatasourceRepositoryCE.java | 5 + .../ce/CustomDatasourceRepositoryCEImpl.java | 16 + .../ce/CustomGroupRepositoryCEImpl.java | 3 +- .../ce/CustomNewActionRepositoryCE.java | 5 + .../ce/CustomNewActionRepositoryCEImpl.java | 22 +- .../ce/CustomNewPageRepositoryCE.java | 4 + .../ce/CustomNewPageRepositoryCEImpl.java | 7 + .../server/services/GitServiceImpl.java | 6 +- .../ce/ActionCollectionServiceCE.java | 2 + .../ce/ActionCollectionServiceCEImpl.java | 12 +- .../services/ce/ApplicationPageServiceCE.java | 2 + .../ce/ApplicationPageServiceCEImpl.java | 26 +- .../services/ce/ApplicationServiceCE.java | 7 + .../services/ce/ApplicationServiceCEImpl.java | 26 +- .../services/ce/DatasourceServiceCE.java | 7 + .../services/ce/DatasourceServiceCEImpl.java | 28 +- .../server/services/ce/GitServiceCEImpl.java | 18 +- .../services/ce/NewActionServiceCE.java | 5 + .../services/ce/NewActionServiceCEImpl.java | 25 ++ .../server/services/ce/NewPageServiceCE.java | 9 + .../services/ce/NewPageServiceCEImpl.java | 27 +- .../services/ce/WorkspaceServiceCE.java | 3 + .../services/ce/WorkspaceServiceCEImpl.java | 6 + .../ImportExportApplicationServiceImplV2.java | 2 +- ...mportExportApplicationServiceCEImplV2.java | 95 +++--- .../ActionCollectionServiceImplTest.java | 34 +- .../services/ce/GitServiceCEImplTest.java | 5 +- 33 files changed, 550 insertions(+), 200 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/AppsmithRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/AppsmithRepository.java index 180af348e9..7762389a48 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/AppsmithRepository.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/AppsmithRepository.java @@ -9,12 +9,15 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; public interface AppsmithRepository { Mono findById(String id, AclPermission permission); + Mono findById(String id, Optional permission); + Mono findById(String id, List projectionFieldNames, AclPermission permission); Mono updateById(String id, T resource, AclPermission permission); @@ -31,5 +34,7 @@ public interface AppsmithRepository { Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, AclPermission permission); + Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, Optional permission); + Mono isPermissionPresentForUser(Set policies, String permission, String username); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java index dff271d240..8fd387e827 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/BaseAppsmithRepositoryCEImpl.java @@ -14,7 +14,7 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.client.result.UpdateResult; import com.querydsl.core.types.Path; -import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.GenericTypeResolver; import org.springframework.data.domain.Sort; @@ -60,7 +60,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank; * ``` * Ref: https://theappsmith.slack.com/archives/CPQNLFHTN/p1669100205502599?thread_ts=1668753437.497369&cid=CPQNLFHTN */ -@Slf4j public abstract class BaseAppsmithRepositoryCEImpl { protected final ReactiveMongoOperations mongoOperations; @@ -74,6 +73,7 @@ public abstract class BaseAppsmithRepositoryCEImpl { protected final static int NO_RECORD_LIMIT = -1; @Autowired + @SuppressWarnings("unchecked") public BaseAppsmithRepositoryCEImpl(ReactiveMongoOperations mongoOperations, MongoConverter mongoConverter, CacheableRepositoryHelper cacheableRepositoryHelper) { this.mongoOperations = mongoOperations; @@ -110,8 +110,8 @@ public abstract class BaseAppsmithRepositoryCEImpl { }); } - public static final String fieldName(Path path) { - return path != null ? path.getMetadata().getName() : null; + public static final String fieldName(Path path) { + return Optional.ofNullable(path).map(p -> p.getMetadata().getName()).orElse(""); } public static final Criteria notDeleted() { @@ -129,30 +129,36 @@ public abstract class BaseAppsmithRepositoryCEImpl { ); } + @Deprecated public static final Criteria userAcl(Set permissionGroups, AclPermission permission) { + Optional criteria = userAcl(permissionGroups, Optional.ofNullable(permission)); + return criteria.orElse(null); + } + + public static final Optional userAcl(Set permissionGroups, Optional permission) { + if(permission.isEmpty()) { + return Optional.empty(); + } // Check if the permission is being provided by any of the permission groups Criteria permissionGroupCriteria = Criteria.where(fieldName(QBaseDomain.baseDomain.policies)) .elemMatch(Criteria.where("permissionGroups").in(permissionGroups) - .and("permission").is(permission.getValue())); + .and("permission").is(permission.get().getValue())); - return permissionGroupCriteria; + return Optional.of(permissionGroupCriteria); } protected Criteria getIdCriteria(Object id) { return where("id").is(id); } - private Criteria getBranchCriteria(String branchName) { - return where(FieldName.DEFAULT_RESOURCES + "." + FieldName.BRANCH_NAME).is(branchName); - } - protected DBObject getDbObject(Object o) { BasicDBObject basicDBObject = new BasicDBObject(); mongoConverter.write(o, basicDBObject); return basicDBObject; } + @Deprecated public Mono findById(String id, AclPermission permission) { return findById(id, null, permission); } @@ -161,60 +167,69 @@ public abstract class BaseAppsmithRepositoryCEImpl { if (id == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); } - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(permissionGroups -> { - Query query = new Query(getIdCriteria(id)); - query.addCriteria(new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission))); - - if(!isEmpty(projectionFieldNames)) { - projectionFieldNames.stream() - .forEach(projectionFieldName -> { - query.fields().include(projectionFieldName); - }); - } - - return mongoOperations.query(this.genericDomain) - .matching(query) - .one() - .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); - }); + return findById(id, Optional.ofNullable(permission)); } + public Mono findById(String id, Optional permission) { + return getCurrentUserPermissionGroupsIfRequired(permission).flatMap(permissionGroups -> { + Query query = new Query(getIdCriteria(id)); + query.addCriteria(notDeleted()); + Optional userAcl = userAcl(permissionGroups, permission); + if(userAcl.isPresent()) { + query.addCriteria(userAcl.get()); + } + return mongoOperations.query(this.genericDomain) + .matching(query) + .one() + .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); + }); + } + + @Deprecated public Mono updateById(String id, T resource, AclPermission permission) { if (id == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); } + if (resource == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } + return updateById(id, resource, Optional.ofNullable(permission)); + } + + public Mono updateById(String id, T resource, Optional permission) { + Query query = new Query(Criteria.where("id").is(id)); + + // Set policies to null in the update object + resource.setPolicies(null); + resource.setUpdatedAt(Instant.now()); + + DBObject update = getDbObject(resource); + Update updateObj = new Update(); + update.keySet().stream().forEach(entry -> updateObj.set(entry, update.get(entry))); + return ReactiveSecurityContextHolder.getContext() .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .zipWhen(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(touple -> { - User user = (User) touple.getT1(); - Set permissionGroups = touple.getT2(); - Query query = new Query(Criteria.where("id").is(id)); - query.addCriteria(new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission))); - - // Set policies to null in the update object - resource.setPolicies(null); - resource.setUpdatedAt(Instant.now()); + .map(auth -> (User) auth.getPrincipal()) + .flatMap(user -> { resource.setModifiedBy(user.getUsername()); - - DBObject update = getDbObject(resource); - Update updateObj = new Update(); - Map updateMap = update.toMap(); - updateMap.entrySet().stream().forEach(entry -> updateObj.set(entry.getKey(), entry.getValue())); - - return mongoOperations.updateFirst(query, updateObj, resource.getClass()) - .flatMap(obj -> { - if (obj.getMatchedCount() == 0) { - return Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, resource.getClass().getSimpleName().toLowerCase(), id)); + return (permission.isPresent() ? getAllPermissionGroupsForUser(user) : Mono.just(Set.of())) + .flatMap(permissionGroups -> { + Optional userAcl = userAcl(permissionGroups, permission); + query.addCriteria(notDeleted()); + if(userAcl.isPresent()) { + query.addCriteria(userAcl.get()); } - return findById(id, permission); - }) - .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); + return mongoOperations.updateFirst(query, updateObj, resource.getClass()) + .flatMap(obj -> { + if (obj.getMatchedCount() == 0) { + return Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, resource.getClass().getSimpleName().toLowerCase(), id)); + } + return findById(id, permission); + }) + .flatMap(obj -> { + return setUserPermissionsInObject(obj, permissionGroups); + }); + }); }); } @@ -246,13 +261,21 @@ public abstract class BaseAppsmithRepositoryCEImpl { if (id == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); } - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(permissionGroups -> { - Query query = new Query(Criteria.where("id").is(id)); - query.addCriteria(new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission))); + if (updateObj == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } + return updateById(id, updateObj, Optional.ofNullable(permission)); + } + + public Mono updateById(String id, Update updateObj, Optional permission) { + Query query = new Query(Criteria.where("id").is(id)); + + if(permission.isEmpty()) { + return mongoOperations.updateFirst(query, updateObj, this.genericDomain); + } + + return getCurrentUserPermissionGroupsIfRequired(permission).flatMap(permissionGroups -> { + query.addCriteria(new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission.get()))); return mongoOperations.updateFirst(query, updateObj, this.genericDomain); }); } @@ -261,47 +284,81 @@ public abstract class BaseAppsmithRepositoryCEImpl { if (criteriaList == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "criteriaList")); } + if (updateObj == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "updateObj")); + } List allCriterias = new ArrayList<>(criteriaList); allCriterias.add(notDeleted()); Query query = new Query(new Criteria().andOperator(allCriterias)); return mongoOperations.updateMulti(query, updateObj, this.genericDomain); } + @Deprecated protected Mono queryOne(List criterias, AclPermission aclPermission) { - return queryOne(criterias, null, aclPermission); + return queryOne(criterias, Optional.ofNullable(aclPermission)); } - protected Mono queryOne(List criterias, List projectionFieldNames, AclPermission aclPermission) { + protected Mono> getCurrentUserPermissionGroupsIfRequired(Optional permission) { + if(permission.isEmpty()) { + return Mono.just(Set.of()); + } + return getCurrentUserPermissionGroups(); + } + + protected Mono> getCurrentUserPermissionGroups() { return ReactiveSecurityContextHolder.getContext() .map(ctx -> ctx.getAuthentication()) .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(permissionGroups -> { + .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)); + } + + protected Mono queryOne(List criterias, List projectionFieldNames, AclPermission permission) { + Mono> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(Optional.ofNullable(permission)); + + return permissionGroupsMono.flatMap(permissionGroups -> { return mongoOperations.query(this.genericDomain) - .matching(createQueryWithPermission(criterias, projectionFieldNames, permissionGroups, aclPermission)) + .matching(createQueryWithPermission(criterias, projectionFieldNames, permissionGroups, permission)) .one() .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); }); } - protected Mono queryFirst(List criterias, AclPermission aclPermission) { - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(permissionGroups -> { + protected Mono queryOne(List criterias, Optional permission) { + Mono> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission); + + return permissionGroupsMono.flatMap(permissionGroups -> { return mongoOperations.query(this.genericDomain) - .matching(createQueryWithPermission(criterias, permissionGroups, aclPermission)) - .first() + .matching(createQueryWithPermission(criterias, permissionGroups, permission)) + .one() .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); }); } - protected Query createQueryWithPermission(List criterias, Set permissionGroups, - AclPermission aclPermission) { + @Deprecated + protected Mono queryFirst(List criterias, AclPermission aclPermission) { + return queryFirst(criterias, Optional.ofNullable(aclPermission)); + } + + protected Mono queryFirst(List criterias, Optional permission) { + Mono> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission); + + return permissionGroupsMono.flatMap(permissionGroups -> { + return mongoOperations.query(this.genericDomain) + .matching(createQueryWithPermission(criterias, permissionGroups, permission)) + .first() + .flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups)); + }); + } + + @Deprecated + protected Query createQueryWithPermission(List criterias, Set permissionGroups, AclPermission aclPermission) { return createQueryWithPermission(criterias, null, permissionGroups, aclPermission); } + protected Query createQueryWithPermission(List criterias, Set permissionGroups, Optional permission) { + return createQueryWithPermission(criterias, null, permissionGroups, permission.orElse(null)); + } + protected Query createQueryWithPermission(List criterias, List projectionFieldNames, Set permissionGroups, AclPermission aclPermission) { @@ -322,76 +379,91 @@ public abstract class BaseAppsmithRepositoryCEImpl { return query; } + @Deprecated protected Mono count(List criterias, AclPermission aclPermission) { - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMap(permissionGroups -> - mongoOperations.count( - createQueryWithPermission(criterias, permissionGroups, aclPermission), this.genericDomain - ) - ); + return count(criterias, Optional.ofNullable(aclPermission)); } - protected Mono count(List criteriaList) { - return mongoOperations.count( - createQueryWithPermission(criteriaList, null, null), this.genericDomain + protected Mono count(List criterias, Optional permission) { + Mono> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission); + + return permissionGroupsMono.flatMap(permissionGroups -> + mongoOperations.count(createQueryWithPermission(criterias, permissionGroups, permission), this.genericDomain) ); } + protected Mono count(List criteriaList) { + return count(criteriaList, Optional.empty()); + } + + @Deprecated public Flux queryAll(List criterias, AclPermission aclPermission) { - return queryAll(criterias, aclPermission, null); + return queryAll(criterias, Optional.empty(), Optional.ofNullable(aclPermission), Optional.empty(), NO_RECORD_LIMIT); } + public Flux queryAll(List criterias, Optional permission) { + return queryAll(criterias, permission, Optional.empty()); + } + + @Deprecated public Flux queryAll(List criterias, AclPermission aclPermission, Sort sort) { - return queryAll(criterias, null, aclPermission, sort); + return queryAll(criterias, Optional.empty(), Optional.ofNullable(aclPermission), Optional.ofNullable(sort), NO_RECORD_LIMIT); } + public Flux queryAll(List criterias, Optional permission, Optional sort) { + return queryAll(criterias, Optional.empty(), permission, sort, NO_RECORD_LIMIT); + } + + @Deprecated public Flux queryAll(List criterias, List includeFields, AclPermission aclPermission, Sort sort) { + return queryAll(criterias, Optional.ofNullable(includeFields), Optional.ofNullable(aclPermission), Optional.ofNullable(sort), NO_RECORD_LIMIT); + } + + public Flux queryAll(List criterias, Optional> includeFields, Optional aclPermission, Optional sort) { return queryAll(criterias, includeFields, aclPermission, sort, NO_RECORD_LIMIT); } + @Deprecated public Flux queryAll(List criterias, List includeFields, AclPermission aclPermission, Sort sort, int limit) { - final ArrayList criteriaList = new ArrayList<>(criterias); - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) - .flatMapMany(permissionGroups -> queryAllWithPermissionGroups(criteriaList, includeFields, aclPermission, sort, permissionGroups, limit)); + return queryAll(criterias, Optional.ofNullable(includeFields), Optional.ofNullable(aclPermission), Optional.ofNullable(sort), limit); } + public Flux queryAll( List criterias, Optional> includeFields, Optional permission, Optional sort, int limit) { + final ArrayList criteriaList = new ArrayList<>(criterias); + Mono> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission); + return permissionGroupsMono.flatMapMany(permissionGroups -> queryAllWithPermissionGroups(criterias, includeFields, permission, sort, permissionGroups, limit)); + } + + @Deprecated public Flux queryAllWithPermissionGroups(List criterias, List includeFields, AclPermission aclPermission, Sort sort, Set permissionGroups, int limit) { + return queryAllWithPermissionGroups(criterias, Optional.ofNullable(includeFields), Optional.ofNullable(aclPermission), Optional.ofNullable(sort), permissionGroups, limit); + } + + public Flux queryAllWithPermissionGroups(List criterias, + Optional> includeFields, + Optional aclPermission, + Optional sortOptional, + Set permissionGroups, + int limit) { final ArrayList criteriaList = new ArrayList<>(criterias); Query query = new Query(); - if (!CollectionUtils.isEmpty(includeFields)) { - for (String includeField : includeFields) { - query.fields().include(includeField); - } - } - + includeFields.ifPresent(fields -> { + fields.forEach(field -> query.fields().include(field)); + }); if (limit != NO_RECORD_LIMIT) { query.limit(limit); } Criteria andCriteria = new Criteria(); - criteriaList.add(notDeleted()); - if (aclPermission != null) { - criteriaList.add(userAcl(permissionGroups, aclPermission)); - } - + userAcl(permissionGroups, aclPermission).ifPresent(criteria -> criteriaList.add(criteria)); andCriteria.andOperator(criteriaList.toArray(new Criteria[0])); - query.addCriteria(andCriteria); - if (sort != null) { - query.with(sort); - } - + sortOptional.ifPresent(sort-> query.with(sort)); return mongoOperations.query(this.genericDomain) .matching(query) .all() @@ -399,17 +471,15 @@ public abstract class BaseAppsmithRepositoryCEImpl { } public Mono setUserPermissionsInObject(T obj) { - return ReactiveSecurityContextHolder.getContext() - .map(ctx -> ctx.getAuthentication()) - .map(auth -> auth.getPrincipal()) - .flatMap(principal -> getAllPermissionGroupsForUser((User) principal)) + return getCurrentUserPermissionGroups() .flatMap(permissionGroups -> setUserPermissionsInObject(obj, permissionGroups)); } public Mono setUserPermissionsInObject(T obj, Set permissionGroups) { Set permissions = new HashSet<>(); + obj.setUserPermissions(permissions); - if (CollectionUtils.isEmpty(obj.getPolicies())) { + if (CollectionUtils.isEmpty(obj.getPolicies()) || permissionGroups.isEmpty()) { return Mono.just(obj); } @@ -426,11 +496,15 @@ public abstract class BaseAppsmithRepositoryCEImpl { } } - obj.setUserPermissions(permissions); return Mono.just(obj); } + @Deprecated public Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, AclPermission permission) { + return findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, gitSyncId, Optional.ofNullable(permission)); + } + + public Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, Optional permission) { final String defaultResources = fieldName(QBaseDomain.baseDomain.defaultResources); Criteria defaultAppIdCriteria = where(defaultResources + "." + FieldName.APPLICATION_ID).is(defaultApplicationId); Criteria gitSyncIdCriteria = where(FieldName.GIT_SYNC_ID).is(gitSyncId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java index 67b26f5c75..f6a5051b7e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java @@ -8,11 +8,14 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; public interface CustomActionCollectionRepositoryCE extends AppsmithRepository { Flux findByApplicationId(String applicationId, AclPermission aclPermission, Sort sort); + Flux findByApplicationId(String applicationId, Optional aclPermission, Optional sort); + Flux findByApplicationIdAndViewMode(String applicationId, boolean viewMode, AclPermission aclPermission); Flux findAllActionCollectionsByNamePageIdsViewModeAndBranch(String name, List pageIds, boolean viewMode, String branchName, AclPermission aclPermission, Sort sort); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java index 642a6853bf..c2b04687c0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java @@ -16,6 +16,7 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -28,6 +29,7 @@ public class CustomActionCollectionRepositoryCEImpl extends BaseAppsmithReposito @Override + @Deprecated public Flux findByApplicationId(String applicationId, AclPermission aclPermission, Sort sort) { Criteria applicationCriteria = where(fieldName(QActionCollection.actionCollection.applicationId)).is(applicationId); @@ -35,6 +37,14 @@ public class CustomActionCollectionRepositoryCEImpl extends BaseAppsmithReposito return queryAll(List.of(applicationCriteria), aclPermission, sort); } + @Override + public Flux findByApplicationId(String applicationId, Optional aclPermission, Optional sort) { + + Criteria applicationCriteria = where(fieldName(QActionCollection.actionCollection.applicationId)).is(applicationId); + + return queryAll(List.of(applicationCriteria), aclPermission, sort); + } + @Override public Flux findByApplicationIdAndViewMode(String applicationId, boolean viewMode, AclPermission aclPermission) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java index e8d90e1fb5..9c75b9c58b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java @@ -10,6 +10,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.Map; @@ -42,6 +43,8 @@ public interface CustomApplicationRepositoryCE extends AppsmithRepository setGitAuth(String applicationId, GitAuth gitAuth, AclPermission aclPermission); + Mono getApplicationByGitBranchAndDefaultApplicationId(String defaultApplicationId, String branchName, Optional permission); + Mono getApplicationByGitBranchAndDefaultApplicationId(String defaultApplicationId, String branchName, AclPermission aclPermission); Mono getApplicationByGitBranchAndDefaultApplicationId(String defaultApplicationId, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java index b9f5a9a343..8c6638713d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java @@ -27,6 +27,7 @@ import reactor.core.publisher.Mono; import java.time.Instant; import java.util.List; +import java.util.Optional; import java.util.Map; import java.util.Set; @@ -163,6 +164,7 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp } @Override + @Deprecated public Mono getApplicationByGitBranchAndDefaultApplicationId(String defaultApplicationId, String branchName, AclPermission aclPermission) { return getApplicationByGitBranchAndDefaultApplicationId(defaultApplicationId, null, branchName, aclPermission); } @@ -179,6 +181,16 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp return queryOne(List.of(defaultAppCriteria, branchNameCriteria), projectionFieldNames, aclPermission); } + @Override + public Mono getApplicationByGitBranchAndDefaultApplicationId(String defaultApplicationId, String branchName, Optional aclPermission) { + + String gitApplicationMetadata = fieldName(QApplication.application.gitApplicationMetadata); + + Criteria defaultAppCriteria = where(gitApplicationMetadata + "." + fieldName(QApplication.application.gitApplicationMetadata.defaultApplicationId)).is(defaultApplicationId); + Criteria branchNameCriteria = where(gitApplicationMetadata + "." + fieldName(QApplication.application.gitApplicationMetadata.branchName)).is(branchName); + return queryOne(List.of(defaultAppCriteria, branchNameCriteria), aclPermission); + } + @Override public Flux getApplicationByGitDefaultApplicationId(String defaultApplicationId, AclPermission permission) { String gitApplicationMetadata = fieldName(QApplication.application.gitApplicationMetadata); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCE.java index 414601700e..91a8939211 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCE.java @@ -8,14 +8,19 @@ import com.mongodb.client.result.UpdateResult; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Optional; import java.util.Set; public interface CustomDatasourceRepositoryCE extends AppsmithRepository { Flux findAllByWorkspaceId(String workspaceId, AclPermission permission); + Flux findAllByWorkspaceId(String workspaceId, Optional permission); + Mono findByNameAndWorkspaceId(String name, String workspaceId, AclPermission aclPermission); + Mono findByNameAndWorkspaceId(String name, String workspaceId, Optional permission); + Mono findById(String id, AclPermission aclPermission); Flux findAllByIds(Set ids, AclPermission permission); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCEImpl.java index cac4d8337d..90f5caeffd 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomDatasourceRepositoryCEImpl.java @@ -16,6 +16,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -28,18 +29,33 @@ public class CustomDatasourceRepositoryCEImpl extends BaseAppsmithRepositoryImpl } @Override + @Deprecated public Flux findAllByWorkspaceId(String workspaceId, AclPermission permission) { Criteria workspaceIdCriteria = where(fieldName(QDatasource.datasource.workspaceId)).is(workspaceId); return queryAll(List.of(workspaceIdCriteria), permission, Sort.by(fieldName(QDatasource.datasource.name))); } @Override + public Flux findAllByWorkspaceId(String workspaceId, Optional permission) { + Criteria workspaceIdCriteria = where(fieldName(QDatasource.datasource.workspaceId)).is(workspaceId); + return queryAll(List.of(workspaceIdCriteria), permission, Optional.of(Sort.by(fieldName(QDatasource.datasource.name)))); + } + + @Override + @Deprecated public Mono findByNameAndWorkspaceId(String name, String workspaceId, AclPermission aclPermission) { Criteria nameCriteria = where(fieldName(QDatasource.datasource.name)).is(name); Criteria workspaceIdCriteria = where(fieldName(QDatasource.datasource.workspaceId)).is(workspaceId); return queryOne(List.of(nameCriteria, workspaceIdCriteria), aclPermission); } + @Override + public Mono findByNameAndWorkspaceId(String name, String workspaceId, Optional aclPermission) { + Criteria nameCriteria = where(fieldName(QDatasource.datasource.name)).is(name); + Criteria workspaceIdCriteria = where(fieldName(QDatasource.datasource.workspaceId)).is(workspaceId); + return queryOne(List.of(nameCriteria, workspaceIdCriteria), aclPermission); + } + @Override public Flux findAllByIds(Set ids, AclPermission permission) { Criteria idcriteria = where(fieldName(QDatasource.datasource.id)).in(ids); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomGroupRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomGroupRepositoryCEImpl.java index c5558db4e1..cb9add30b3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomGroupRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomGroupRepositoryCEImpl.java @@ -11,6 +11,7 @@ import org.springframework.data.mongodb.core.query.Criteria; import reactor.core.publisher.Flux; import java.util.List; +import java.util.Optional; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -26,6 +27,6 @@ public class CustomGroupRepositoryCEImpl extends BaseAppsmithRepositoryImpl getAllByWorkspaceId(String workspaceId) { Criteria workspaceIdCriteria = where(fieldName(QGroup.group.workspaceId)).is(workspaceId); - return queryAll(List.of(workspaceIdCriteria), null); + return queryAll(List.of(workspaceIdCriteria), Optional.empty()); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java index e3def5c8c3..e5d350873b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java @@ -8,6 +8,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; public interface CustomNewActionRepositoryCE extends AppsmithRepository { @@ -18,6 +19,8 @@ public interface CustomNewActionRepositoryCE extends AppsmithRepository findByPageId(String pageId, AclPermission aclPermission); + Flux findByPageId(String pageId, Optional aclPermission); + Flux findByPageId(String pageId); Flux findByPageIdAndViewMode(String pageId, Boolean viewMode, AclPermission aclPermission); @@ -38,6 +41,8 @@ public interface CustomNewActionRepositoryCE extends AppsmithRepository findByApplicationId(String applicationId, AclPermission aclPermission, Sort sort); + Flux findByApplicationId(String applicationId, Optional aclPermission, Optional sort); + Flux findByApplicationIdAndViewMode(String applicationId, Boolean viewMode, AclPermission aclPermission); Mono countByDatasourceId(String datasourceId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java index 929369e503..11364ddd49 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java @@ -19,6 +19,7 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -38,6 +39,12 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< return queryAll(List.of(applicationIdCriteria), aclPermission); } + @Override + public Flux findByApplicationId(String applicationId, Optional aclPermission, Optional sort) { + Criteria applicationIdCriteria = where(fieldName(QNewAction.newAction.applicationId)).is(applicationId); + return queryAll(List.of(applicationIdCriteria), aclPermission, sort); + } + @Override public Mono findByUnpublishedNameAndPageId(String name, String pageId, AclPermission aclPermission) { Criteria nameCriteria = where(fieldName(QNewAction.newAction.unpublishedAction) + "." + fieldName(QNewAction.newAction.unpublishedAction.name)).is(name); @@ -61,9 +68,22 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl< return queryAll(List.of(pageCriteria), aclPermission); } + @Override + public Flux findByPageId(String pageId, Optional aclPermission) { + String unpublishedPage = fieldName(QNewAction.newAction.unpublishedAction) + "." + fieldName(QNewAction.newAction.unpublishedAction.pageId); + String publishedPage = fieldName(QNewAction.newAction.publishedAction) + "." + fieldName(QNewAction.newAction.publishedAction.pageId); + + Criteria pageCriteria = new Criteria().orOperator( + where(unpublishedPage).is(pageId), + where(publishedPage).is(pageId) + ); + + return queryAll(List.of(pageCriteria), aclPermission); + } + @Override public Flux findByPageId(String pageId) { - return this.findByPageId(pageId, null); + return this.findByPageId(pageId, Optional.empty()); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java index 61885bc6e8..5a6e66407a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java @@ -7,11 +7,15 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; public interface CustomNewPageRepositoryCE extends AppsmithRepository { + @Deprecated Flux findByApplicationId(String applicationId, AclPermission aclPermission); + Flux findByApplicationId(String applicationId, Optional permission); + Flux findByApplicationIdAndNonDeletedEditMode(String applicationId, AclPermission aclPermission); Mono findByIdAndLayoutsIdAndViewMode(String id, String layoutId, AclPermission aclPermission, Boolean viewMode); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java index 07ee57c4d6..4d768b25c8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java @@ -18,6 +18,7 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -35,6 +36,12 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl findByApplicationId(String applicationId, Optional permission) { + Criteria applicationIdCriteria = where(fieldName(QNewPage.newPage.applicationId)).is(applicationId); + return queryAll(List.of(applicationIdCriteria), permission); + } + @Override public Flux findByApplicationIdAndNonDeletedEditMode(String applicationId, AclPermission aclPermission) { Criteria applicationIdCriteria = where(fieldName(QNewPage.newPage.applicationId)).is(applicationId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/GitServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/GitServiceImpl.java index 6c84da3318..880e63f6d8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/GitServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/GitServiceImpl.java @@ -46,12 +46,14 @@ public class GitServiceImpl extends GitServiceCEImpl implements GitService { DatasourcePermission datasourcePermission, ApplicationPermission applicationPermission, PagePermission pagePermission, - ActionPermission actionPermission) { + ActionPermission actionPermission, + WorkspaceService workspaceService) { super(userService, userDataService, sessionUserService, applicationService, applicationPageService, newPageService, newActionService, actionCollectionService, fileUtils, importExportApplicationService, gitExecutor, responseUtils, emailConfig, analyticsService, gitCloudServicesUtils, gitDeployKeysRepository, datasourceService, pluginService, datasourcePermission, applicationPermission, pagePermission, - actionPermission); + actionPermission, workspaceService); } + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCE.java index 0d479db0fd..02cc1e972e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCE.java @@ -37,6 +37,8 @@ public interface ActionCollectionServiceCE extends CrudService update(String id, ActionCollectionDTO actionCollectionDTO); Mono deleteUnpublishedActionCollection(String id); + + Mono deleteWithoutPermissionUnpublishedActionCollection(String id); Mono deleteUnpublishedActionCollection(String id, String branchName); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCEImpl.java index f0f4b14a9b..8655ca52e2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ActionCollectionServiceCEImpl.java @@ -45,6 +45,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -322,9 +323,18 @@ public class ActionCollectionServiceCEImpl extends BaseService deleteWithoutPermissionUnpublishedActionCollection(String id) { + return deleteUnpublishedActionCollectionEx(id, Optional.empty()); + } + @Override public Mono deleteUnpublishedActionCollection(String id) { - Mono actionCollectionMono = repository.findById(id, actionPermission.getDeletePermission()) + return deleteUnpublishedActionCollectionEx(id, Optional.of(actionPermission.getDeletePermission())); + } + + public Mono deleteUnpublishedActionCollectionEx(String id, Optional permission) { + Mono actionCollectionMono = repository.findById(id, permission) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION_COLLECTION, id))); return actionCollectionMono .flatMap(toDelete -> { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCE.java index dfedd06ed0..cb686fdcc0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCE.java @@ -45,6 +45,8 @@ public interface ApplicationPageServiceCE { Mono deleteUnpublishedPage(String id); + Mono deleteWithoutPermissionUnpublishedPage(String id); + Mono publish(String applicationId, boolean isPublishedManually); Mono publish(String defaultApplicationId, String branchName, boolean isPublishedManually); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java index 36ac48012e..a152613483 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java @@ -831,9 +831,31 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE { * @return */ @Override - public Mono deleteUnpublishedPage(String id) { + public Mono deleteWithoutPermissionUnpublishedPage(String id) { + return deleteUnpublishedPageEx(id, Optional.empty()); + } - return newPageService.findById(id, pagePermission.getDeletePermission()) + @Override + public Mono deleteUnpublishedPage(String id) { + return deleteUnpublishedPageEx(id, Optional.of(pagePermission.getDeletePermission())); + } + + + /** + * This function archives the unpublished page. This also archives the unpublished action. The reason that the + * entire action is not deleted at this point is to handle the following edge case : + * An application is published with 1 page and 1 action. + * Post publish, create a new page and move the action from the existing page to the new page. Now delete this newly + * created page. + * In this scenario, if we were to delete all actions associated with the page, we would end up deleting an action + * which is currently in published state and is being used. + * + * @param id The pageId which needs to be archived. + * @return + */ + private Mono deleteUnpublishedPageEx(String id, Optional permission) { + + return newPageService.findById(id, permission) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, id))) .flatMap(page -> { log.debug("Going to archive pageId: {} for applicationId: {}", page.getId(), page.getApplicationId()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java index 1d79721e46..d995f0005b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java @@ -1,5 +1,8 @@ package com.appsmith.server.services.ce; +import java.util.Optional; + + import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.GitAuth; @@ -21,6 +24,8 @@ public interface ApplicationServiceCE extends CrudService { Mono findById(String id, AclPermission aclPermission); + Mono findById(String id, Optional aclPermission); + Mono findByIdAndWorkspaceId(String id, String workspaceId, AclPermission permission); Flux findByWorkspaceId(String workspaceId, AclPermission permission); @@ -61,6 +66,8 @@ public interface ApplicationServiceCE extends CrudService { String defaultApplicationId, AclPermission aclPermission); + Mono findBranchedApplicationId(Optional branchName, String defaultApplicationId, Optional permission); + Mono findByBranchNameAndDefaultApplicationId(String branchName, String defaultApplicationId, List projectionFieldNames, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java index 9fb136f7e2..5824a4514b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java @@ -58,6 +58,7 @@ import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS; @@ -170,11 +171,18 @@ public class ApplicationServiceCEImpl extends BaseService findById(String id, AclPermission aclPermission) { return repository.findById(id, aclPermission) .flatMap(this::setTransientFields); } + @Override + public Mono findById(String id, Optional aclPermission) { + return repository.findById(id, aclPermission) + .flatMap(this::setTransientFields); + } + @Override public Mono findByIdAndWorkspaceId(String id, String workspaceId, AclPermission permission) { return repository.findByIdAndWorkspaceId(id, workspaceId, permission) @@ -679,8 +687,8 @@ public class ApplicationServiceCEImpl extends BaseService findBranchedApplicationId(String branchName, String defaultApplicationId, AclPermission permission) { - if (StringUtils.isEmpty(branchName)) { - if (StringUtils.isEmpty(defaultApplicationId)) { + if (!StringUtils.hasLength(branchName)) { + if (!StringUtils.hasLength(defaultApplicationId)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATION_ID, defaultApplicationId)); } return Mono.just(defaultApplicationId); @@ -692,6 +700,20 @@ public class ApplicationServiceCEImpl extends BaseService findBranchedApplicationId(Optional branchName, String defaultApplicationId, Optional permission) { + if (branchName.isEmpty()) { + if (!StringUtils.hasLength(defaultApplicationId)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATION_ID, defaultApplicationId)); + } + return Mono.just(defaultApplicationId); + } + return repository.getApplicationByGitBranchAndDefaultApplicationId(defaultApplicationId, branchName.get(), permission) + .switchIfEmpty(Mono.error( + new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION, defaultApplicationId + ", " + branchName)) + ) + .map(Application::getId); + } + /** * As part of git sync feature a new application will be created for each branch with reference to main application * feat/new-branch ----> new application in Appsmith diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCE.java index 4a1bfb3df5..bdc2ce1be4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCE.java @@ -10,6 +10,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; public interface DatasourceServiceCE extends CrudService { @@ -18,6 +19,8 @@ public interface DatasourceServiceCE extends CrudService { Mono findByNameAndWorkspaceId(String name, String workspaceId, AclPermission permission); + Mono findByNameAndWorkspaceId(String name, String workspaceId, Optional permission); + Mono findById(String id, AclPermission aclPermission); Mono findById(String id); @@ -30,6 +33,8 @@ public interface DatasourceServiceCE extends CrudService { Flux findAllByWorkspaceId(String workspaceId, AclPermission readDatasources); + Flux findAllByWorkspaceId(String workspaceId, Optional readDatasources); + Flux saveAll(List datasourceList); Mono populateHintMessages(Datasource datasource); @@ -38,4 +43,6 @@ public interface DatasourceServiceCE extends CrudService { Mono getValidDatasourceFromActionMono(ActionDTO actionDTO, AclPermission aclPermission); + Mono createWithoutPermissions(Datasource datasource); + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCEImpl.java index 9dff1cf0c5..c9527dbe30 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/DatasourceServiceCEImpl.java @@ -55,6 +55,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties; @@ -107,6 +108,15 @@ public class DatasourceServiceCEImpl extends BaseService create(@NotNull Datasource datasource) { + return createEx(datasource, Optional.of(workspacePermission.getDatasourceCreatePermission())); + } + + @Override + public Mono createWithoutPermissions(Datasource datasource) { + return createEx(datasource, Optional.empty()); + } + + private Mono createEx(@NotNull Datasource datasource, Optional permission) { String workspaceId = datasource.getWorkspaceId(); if (workspaceId == null) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID)); @@ -131,7 +141,7 @@ public class DatasourceServiceCEImpl extends BaseService datasourceWithPoliciesMono = datasourceMono .flatMap(datasource1 -> { Mono userMono = sessionUserService.getCurrentUser(); - return generateAndSetDatasourcePolicies(userMono, datasource1); + return generateAndSetDatasourcePolicies(userMono, datasource1, permission); }); return datasourceWithPoliciesMono @@ -143,10 +153,11 @@ public class DatasourceServiceCEImpl extends BaseService generateAndSetDatasourcePolicies(Mono userMono, Datasource datasource) { + private Mono generateAndSetDatasourcePolicies(Mono userMono, Datasource datasource, Optional permission) { return userMono .flatMap(user -> { - Mono workspaceMono = workspaceService.findById(datasource.getWorkspaceId(), workspacePermission.getDatasourceCreatePermission()) + Mono workspaceMono = workspaceService.findById(datasource.getWorkspaceId(), permission) + .log() .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, datasource.getWorkspaceId()))); return workspaceMono.map(workspace -> { @@ -390,6 +401,11 @@ public class DatasourceServiceCEImpl extends BaseService findByNameAndWorkspaceId(String name, String workspaceId, Optional permission) { + return repository.findByNameAndWorkspaceId(name, workspaceId, permission); + } + @Override public Mono findById(String id, AclPermission aclPermission) { return repository.findById(id, aclPermission); @@ -435,6 +451,12 @@ public class DatasourceServiceCEImpl extends BaseService findAllByWorkspaceId(String workspaceId, Optional permission) { + return repository.findAllByWorkspaceId(workspaceId, permission) + .flatMap(this::populateHintMessages); + } + @Override public Flux saveAll(List datasourceList) { datasourceList diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/GitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/GitServiceCEImpl.java index ca04049d22..99f12ec312 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/GitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/GitServiceCEImpl.java @@ -9,6 +9,7 @@ import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.GitExecutor; import com.appsmith.external.models.Datasource; import com.appsmith.git.service.GitExecutorImpl; +import com.appsmith.server.acl.AclPermission; import com.appsmith.server.configurations.EmailConfig; import com.appsmith.server.constants.Assets; import com.appsmith.server.constants.Entity; @@ -24,6 +25,7 @@ import com.appsmith.server.domains.GitDeployKeys; import com.appsmith.server.domains.GitProfile; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.UserData; +import com.appsmith.server.domains.Workspace; import com.appsmith.server.dtos.ApplicationImportDTO; import com.appsmith.server.dtos.GitCommitDTO; import com.appsmith.server.dtos.GitConnectDTO; @@ -51,6 +53,7 @@ import com.appsmith.server.services.PluginService; import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.UserDataService; import com.appsmith.server.services.UserService; +import com.appsmith.server.services.WorkspaceService; import com.appsmith.server.solutions.ActionPermission; import com.appsmith.server.solutions.ApplicationPermission; import com.appsmith.server.solutions.DatasourcePermission; @@ -134,6 +137,7 @@ public class GitServiceCEImpl implements GitServiceCE { private final ApplicationPermission applicationPermission; private final PagePermission pagePermission; private final ActionPermission actionPermission; + private final WorkspaceService workspaceService; @Override public Mono updateGitMetadata(String applicationId, GitApplicationMetadata gitApplicationMetadata) { @@ -367,9 +371,8 @@ public class GitServiceCEImpl implements GitServiceCE { updateProfiles.put(DEFAULT, gitProfile); } - UserData update = new UserData(); - update.setGitProfiles(updateProfiles); - return userDataService.update(userData.getUserId(), update); + userData.setGitProfiles(updateProfiles); + return userDataService.updateForCurrentUser(userData); }); } return Mono.just(userData); @@ -1044,14 +1047,14 @@ public class GitServiceCEImpl implements GitServiceCE { // Update all the resources to replace defaultResource Ids with the resource Ids as branchName // will be deleted Flux.fromIterable(application.getPages()) - .flatMap(page -> newPageService.findById(page.getId(), pagePermission.getEditPermission())) + .flatMap(page -> newPageService.findById(page.getId(), Optional.empty())) .map(newPage -> { newPage.setDefaultResources(null); return createDefaultIdsOrUpdateWithGivenResourceIds(newPage, null); }) .collectList() .flatMapMany(newPageService::saveAll) - .flatMap(newPage -> newActionService.findByPageId(newPage.getId(), actionPermission.getEditPermission()) + .flatMap(newPage -> newActionService.findByPageId(newPage.getId(), Optional.empty()) .map(newAction -> { newAction.setDefaultResources(null); if (newAction.getUnpublishedAction() != null) { @@ -1831,9 +1834,12 @@ public class GitServiceCEImpl implements GitServiceCE { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "Invalid workspace id")); } + Mono workspaceMono = workspaceService.findById(workspaceId, AclPermission.WORKSPACE_CREATE_APPLICATION) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId))); + final String repoName = GitUtils.getRepoName(gitConnectDTO.getRemoteUrl()); Mono isPrivateRepoMono = GitUtils.isRepoPrivate(GitUtils.convertSshUrlToBrowserSupportedUrl(gitConnectDTO.getRemoteUrl())).cache(); - Mono importedApplicationMono = getSSHKeyForCurrentUser() + Mono importedApplicationMono = workspaceMono.then(getSSHKeyForCurrentUser()) .zipWith(isPrivateRepoMono) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, "Unable to find git configuration for logged-in user. Please contact Appsmith team for support"))) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCE.java index 981e6a00e9..5878d8f07a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCE.java @@ -18,6 +18,7 @@ import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; public interface NewActionServiceCE extends CrudService { @@ -58,10 +59,14 @@ public interface NewActionServiceCE extends CrudService { Flux findByPageId(String pageId, AclPermission permission); + Flux findByPageId(String pageId, Optional permission); + Flux findByPageIdAndViewMode(String pageId, Boolean viewMode, AclPermission permission); Flux findAllByApplicationIdAndViewMode(String applicationId, Boolean viewMode, AclPermission permission, Sort sort); + Flux findAllByApplicationIdAndViewMode(String applicationId, Boolean viewMode, Optional permission, Optional sort); + Flux getActionsForViewMode(String applicationId); Flux getActionsForViewMode(String defaultApplicationId, String branchName); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java index 00447d4735..84e4d58539 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java @@ -1463,6 +1463,12 @@ public class NewActionServiceCEImpl extends BaseService findByPageId(String pageId, Optional permission) { + return repository.findByPageId(pageId, permission) + .flatMap(this::sanitizeAction); + } @Override public Flux findByPageIdAndViewMode(String pageId, Boolean viewMode, AclPermission permission) { @@ -1489,6 +1495,25 @@ public class NewActionServiceCEImpl extends BaseService findAllByApplicationIdAndViewMode(String applicationId, Boolean viewMode, Optional permission, Optional sort) { + return repository.findByApplicationId(applicationId, permission, sort) + // In case of view mode being true, filter out all the actions which haven't been published + .flatMap(action -> { + if (Boolean.TRUE.equals(viewMode)) { + // In case we are trying to fetch published actions but this action has not been published, do not return + if (action.getPublishedAction() == null) { + return Mono.empty(); + } + } + // No need to handle the edge case of unpublished action not being present. This is not possible because + // every created action starts from an unpublishedAction state. + + return Mono.just(action); + }) + .flatMap(this::sanitizeAction); + } + @Override public Flux getActionsForViewMode(String defaultApplicationId, String branchName) { return applicationService.findBranchedApplicationId(branchName, defaultApplicationId, applicationPermission.getReadPermission()) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCE.java index 3e195dea78..9bc7a8db56 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCE.java @@ -11,6 +11,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; public interface NewPageServiceCE extends CrudService { @@ -18,12 +19,16 @@ public interface NewPageServiceCE extends CrudService { Mono findById(String pageId, AclPermission aclPermission); + Mono findById(String pageId, Optional aclPermission); + Mono findPageById(String pageId, AclPermission aclPermission, Boolean view); Flux findByApplicationId(String applicationId, AclPermission permission, Boolean view); Flux findNewPagesByApplicationId(String applicationId, AclPermission permission); + Flux findNewPagesByApplicationId(String applicationId, Optional permission); + Mono saveUnpublishedPage(PageDTO page); Mono createDefault(PageDTO object); @@ -65,6 +70,8 @@ public interface NewPageServiceCE extends CrudService { Mono archiveById(String id); + Mono archiveWithoutPermissionById(String id); + Flux saveAll(List pages); Mono getNameByPageId(String pageId, boolean isPublishedName); @@ -77,5 +84,7 @@ public interface NewPageServiceCE extends CrudService { Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, AclPermission permission); + Mono findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, Optional permission); + Flux findPageSlugsByApplicationIds(List applicationIds, AclPermission aclPermission); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCEImpl.java index 6ec2e091d2..30b7f1d0a2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewPageServiceCEImpl.java @@ -42,6 +42,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -124,6 +125,11 @@ public class NewPageServiceCEImpl extends BaseService getPageByViewMode(page, view)); } + @Override + public Mono findById(String pageId, Optional aclPermission) { + return repository.findById(pageId, aclPermission); + } + @Override public Flux findByApplicationId(String applicationId, AclPermission permission, Boolean view) { return findNewPagesByApplicationId(applicationId, permission) @@ -446,6 +452,11 @@ public class NewPageServiceCEImpl extends BaseService findNewPagesByApplicationId(String applicationId, Optional permission) { + return repository.findByApplicationId(applicationId, permission); + } + @Override public Mono> archivePagesByApplicationId(String applicationId, AclPermission permission) { return findNewPagesByApplicationId(applicationId, permission) @@ -508,9 +519,18 @@ public class NewPageServiceCEImpl extends BaseService archiveWithoutPermissionById(String id) { + return archiveByIdEx(id, Optional.empty()); + } + @Override public Mono archiveById(String id) { - Mono pageMono = this.findById(id, pagePermission.getDeletePermission()) + return archiveByIdEx(id, Optional.of(pagePermission.getDeletePermission())); + } + + public Mono archiveByIdEx(String id, Optional permission) { + Mono pageMono = this.findById(id, permission) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE_ID, id))) .cache(); @@ -593,6 +613,11 @@ public class NewPageServiceCEImpl extends BaseService findByGitSyncIdAndDefaultApplicationId(String defaultApplicationId, String gitSyncId, Optional permission) { + return repository.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, gitSyncId, permission); + } + @Override public Flux findPageSlugsByApplicationIds(List applicationIds, AclPermission aclPermission) { return repository.findSlugsByApplicationIds(applicationIds, aclPermission); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCE.java index 9aac09bce2..af1755832d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCE.java @@ -10,6 +10,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; +import java.util.Optional; import java.util.Set; public interface WorkspaceServiceCE extends CrudService { @@ -24,6 +25,8 @@ public interface WorkspaceServiceCE extends CrudService { Mono findById(String id, AclPermission permission); + Mono findById(String id, Optional permission); + Mono save(Workspace workspace); Mono findByIdAndPluginsPluginId(String workspaceId, String pluginId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCEImpl.java index 109089b7a0..0f1f79122a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/WorkspaceServiceCEImpl.java @@ -51,6 +51,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -467,6 +468,11 @@ public class WorkspaceServiceCEImpl extends BaseService findById(String id, Optional permission) { + return repository.findById(id, permission); + } + @Override public Mono save(Workspace workspace) { if (StringUtils.hasLength(workspace.getName())) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationServiceImplV2.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationServiceImplV2.java index d86b8583e0..e75fc4f51f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationServiceImplV2.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationServiceImplV2.java @@ -56,7 +56,7 @@ public class ImportExportApplicationServiceImplV2 extends ImportExportApplicatio super(datasourceService, sessionUserService, newActionRepository, datasourceRepository, pluginRepository, workspaceService, applicationService, newPageService, applicationPageService, newPageRepository, newActionService, sequenceService, examplesWorkspaceCloner, actionCollectionRepository, - actionCollectionService, themeService, policyUtils, analyticsService, datasourcePermission, + actionCollectionService, themeService, analyticsService, datasourcePermission, workspacePermission, applicationPermission, pagePermission, actionPermission); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImplV2.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImplV2.java index b30f960d69..d6c0ca2b81 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImplV2.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImplV2.java @@ -36,7 +36,6 @@ import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.DefaultResourcesUtils; -import com.appsmith.server.helpers.PolicyUtils; import com.appsmith.server.helpers.TextUtils; import com.appsmith.server.migrations.ApplicationVersion; import com.appsmith.server.migrations.JsonSchemaMigration; @@ -69,7 +68,7 @@ import com.google.gson.reflect.TypeToken; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.bson.types.ObjectId; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.dao.DuplicateKeyException; @@ -90,14 +89,11 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties; -import static com.appsmith.server.acl.AclPermission.MANAGE_ACTIONS; -import static com.appsmith.server.acl.AclPermission.MANAGE_PAGES; -import static com.appsmith.server.acl.AclPermission.READ_ACTIONS; -import static com.appsmith.server.acl.AclPermission.READ_PAGES; import static com.appsmith.server.acl.AclPermission.READ_THEMES; import static com.appsmith.server.constants.ResourceModes.EDIT; import static com.appsmith.server.constants.ResourceModes.VIEW; @@ -124,7 +120,6 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli private final ActionCollectionRepository actionCollectionRepository; private final ActionCollectionService actionCollectionService; private final ThemeService themeService; - private final PolicyUtils policyUtils; private final AnalyticsService analyticsService; private final DatasourcePermission datasourcePermission; private final WorkspacePermission workspacePermission; @@ -240,9 +235,11 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli applicationJson.setExportedApplication(application); Set dbNamesUsedInActions = new HashSet<>(); - Flux pageFlux = TRUE.equals(application.getExportWithConfiguration()) - ? newPageRepository.findByApplicationId(applicationId, pagePermission.getReadPermission()) - : newPageRepository.findByApplicationId(applicationId, pagePermission.getEditPermission()); + Optional optionalPermission = isGitSync ? Optional.empty() : + TRUE.equals(application.getExportWithConfiguration()) + ? Optional.of(pagePermission.getReadPermission()) + : Optional.of(pagePermission.getEditPermission()); + Flux pageFlux = newPageRepository.findByApplicationId(applicationId, optionalPermission); return pageFlux .collectList() @@ -289,10 +286,13 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli put(FieldName.PAGE_LIST, updatedPageSet); }}); - Flux datasourceFlux = TRUE.equals(application.getExportWithConfiguration()) - ? datasourceRepository.findAllByWorkspaceId(workspaceId, datasourcePermission.getReadPermission()) - : datasourceRepository.findAllByWorkspaceId(workspaceId, datasourcePermission.getEditPermission()); + Optional optionalPermission3 = isGitSync ? Optional.empty() + : TRUE.equals(application.getExportWithConfiguration()) + ? Optional.of(datasourcePermission.getReadPermission()) + : Optional.of(datasourcePermission.getEditPermission()); + Flux datasourceFlux = + datasourceRepository.findAllByWorkspaceId(workspaceId, optionalPermission3); return datasourceFlux.collectList(); }) .flatMapMany(datasourceList -> { @@ -300,9 +300,12 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli datasourceIdToNameMap.put(datasource.getId(), datasource.getName())); applicationJson.setDatasourceList(datasourceList); - Flux actionCollectionFlux = TRUE.equals(application.getExportWithConfiguration()) - ? actionCollectionRepository.findByApplicationId(applicationId, actionPermission.getReadPermission(), null) - : actionCollectionRepository.findByApplicationId(applicationId, actionPermission.getEditPermission(), null); + Optional optionalPermission1 = isGitSync ? Optional.empty() : + TRUE.equals(application.getExportWithConfiguration()) + ? Optional.of(actionPermission.getReadPermission()) + : Optional.of(actionPermission.getEditPermission()); + Flux actionCollectionFlux = + actionCollectionRepository.findByApplicationId(applicationId, optionalPermission1, Optional.empty()); return actionCollectionFlux; }) .map(actionCollection -> { @@ -356,10 +359,13 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli applicationJson.setActionCollectionList(actionCollections); applicationJson.getUpdatedResources().put(FieldName.ACTION_COLLECTION_LIST, updatedActionCollectionSet); - Flux actionFlux = TRUE.equals(application.getExportWithConfiguration()) - ? newActionRepository.findByApplicationId(applicationId, actionPermission.getReadPermission(), null) - : newActionRepository.findByApplicationId(applicationId, actionPermission.getEditPermission(), null); + Optional optionalPermission2 = isGitSync ? Optional.empty() + : TRUE.equals(application.getExportWithConfiguration()) + ? Optional.of(actionPermission.getReadPermission()) + : Optional.of(actionPermission.getEditPermission()); + Flux actionFlux = + newActionRepository.findByApplicationId(applicationId, optionalPermission2, Optional.empty()); return actionFlux; }) .map(newAction -> { @@ -602,14 +608,12 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli * @return saved application in DB */ public Mono importApplicationInWorkspace(String workspaceId, ApplicationJson importedDoc) { - return importApplicationInWorkspace(workspaceId, importedDoc, null, null); + return importApplicationInWorkspace(workspaceId, importedDoc, null, null, false, false); } - public Mono importApplicationInWorkspace(String workspaceId, - ApplicationJson applicationJson, - String applicationId, - String branchName) { - return importApplicationInWorkspace(workspaceId, applicationJson, applicationId, branchName, false); + @Override + public Mono importApplicationInWorkspace(String workspaceId, ApplicationJson importedDoc, String applicationId, String branchName) { + return importApplicationInWorkspace(workspaceId, importedDoc, applicationId, branchName, false, !StringUtils.isEmpty(branchName)); } /** @@ -647,7 +651,8 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli ApplicationJson applicationJson, String applicationId, String branchName, - boolean appendToApp) { + boolean appendToApp, + boolean isGitSync) { /* 1. Migrate resource to latest schema 2. Fetch workspace by id @@ -686,7 +691,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli Mono currUserMono = sessionUserService.getCurrentUser().cache(); final Flux existingDatasourceFlux = datasourceRepository - .findAllByWorkspaceId(workspaceId, datasourcePermission.getEditPermission()) + .findAllByWorkspaceId(workspaceId, isGitSync ? Optional.empty() : Optional.of(datasourcePermission.getEditPermission())) .cache(); assert importedApplication != null : "Received invalid application object!"; @@ -708,7 +713,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli pluginMap.put(pluginReference, plugin.getId()); return plugin; }) - .then(workspaceService.findById(workspaceId, workspacePermission.getApplicationCreatePermission())) + .then(workspaceService.findById(workspaceId, isGitSync ? Optional.empty() : Optional.of(workspacePermission.getApplicationCreatePermission()))) .switchIfEmpty(Mono.error( new AppsmithException(AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId)) ) @@ -802,7 +807,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli importedApplication.setWorkspaceId(workspaceId); // Application Id will be present for GIT sync if (!StringUtils.isEmpty(applicationId)) { - return applicationService.findById(applicationId, applicationPermission.getEditPermission()) + return applicationService.findById(applicationId, Optional.empty()) .switchIfEmpty( Mono.error(new AppsmithException( AppsmithError.ACL_NO_RESOURCE_FOUND, @@ -870,7 +875,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli // For git-sync this will not be empty Mono> existingPagesMono = newPageService - .findNewPagesByApplicationId(importedApplication.getId(), pagePermission.getEditPermission()) + .findNewPagesByApplicationId(importedApplication.getId(), Optional.empty()) .collectList() .cache(); @@ -1003,8 +1008,8 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli // Delete the pages which were removed during git merge operation // This does not apply to the traditional import via file approach return Flux.fromIterable(invalidPageIds) - .flatMap(applicationPageService::deleteUnpublishedPage) - .flatMap(page -> newPageService.archiveById(page.getId()) + .flatMap(applicationPageService::deleteWithoutPermissionUnpublishedPage) + .flatMap(page -> newPageService.archiveWithoutPermissionById(page.getId()) .onErrorResume(e -> { log.debug("Unable to archive page {} with error {}", page.getId(), e.getMessage()); return Mono.empty(); @@ -1117,7 +1122,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli } } return Flux.fromIterable(invalidCollectionIds) - .flatMap(collectionId -> actionCollectionService.deleteUnpublishedActionCollection(collectionId) + .flatMap(collectionId -> actionCollectionService.deleteWithoutPermissionUnpublishedActionCollection(collectionId) // return an empty collection so that the filter can remove it from the list .onErrorResume(throwable -> { log.debug("Failed to delete collection with id {} during import", collectionId); @@ -1136,7 +1141,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli // Don't update gitAuth as we are using @Encrypted for private key importedApplication.setGitApplicationMetadata(null); // Map layoutOnLoadActions ids with relevant actions - return newPageService.findNewPagesByApplicationId(importedApplication.getId(), pagePermission.getEditPermission()) + return newPageService.findNewPagesByApplicationId(importedApplication.getId(), Optional.empty()) .flatMap(newPage -> { if (newPage.getDefaultResources() != null) { newPage.getDefaultResources().setBranchName(branchName); @@ -1156,7 +1161,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli stopwatch.stopAndLogTimeInMillis(); final Map data = Map.of( FieldName.APPLICATION_ID, application.getId(), - FieldName.ORGANIZATION_ID, application.getWorkspaceId(), + FieldName.WORKSPACE_ID, application.getWorkspaceId(), "pageCount", applicationJson.getPageList().size(), "actionCount", applicationJson.getActionList().size(), "JSObjectCount", applicationJson.getActionCollectionList().size(), @@ -1288,7 +1293,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli return newPageService.save(existingPage); } else if (application.getGitApplicationMetadata() != null) { final String defaultApplicationId = application.getGitApplicationMetadata().getDefaultApplicationId(); - return newPageService.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, newPage.getGitSyncId(), pagePermission.getEditPermission()) + return newPageService.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, newPage.getGitSyncId(), Optional.empty()) .switchIfEmpty(Mono.defer(() -> { // This is the first page we are saving with given gitSyncId in this instance DefaultResources defaultResources = new DefaultResources(); @@ -1408,7 +1413,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli return newActionService.save(existingAction); } else if (importedApplication.getGitApplicationMetadata() != null) { final String defaultApplicationId = importedApplication.getGitApplicationMetadata().getDefaultApplicationId(); - return newActionRepository.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, newAction.getGitSyncId(), actionPermission.getEditPermission()) + return newActionRepository.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, newAction.getGitSyncId(), Optional.empty()) .switchIfEmpty(Mono.defer(() -> { // This is the first page we are saving with given gitSyncId in this instance DefaultResources defaultResources = new DefaultResources(); @@ -1564,7 +1569,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli ); } else if (importedApplication.getGitApplicationMetadata() != null) { final String defaultApplicationId = importedApplication.getGitApplicationMetadata().getDefaultApplicationId(); - return actionCollectionRepository.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, actionCollection.getGitSyncId(), actionPermission.getEditPermission()) + return actionCollectionRepository.findByGitSyncIdAndDefaultApplicationId(defaultApplicationId, actionCollection.getGitSyncId(), Optional.empty()) .switchIfEmpty(Mono.defer(() -> { // This is the first page we are saving with given gitSyncId in this instance DefaultResources defaultResources = new DefaultResources(); @@ -1635,7 +1640,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli actionIds.addAll(unpublishedActionIdToCollectionIdMap.keySet()); actionIds.addAll(publishedActionIdToCollectionIdMap.keySet()); return Flux.fromIterable(actionIds) - .flatMap(actionId -> newActionRepository.findById(actionId, actionPermission.getEditPermission())) + .flatMap(actionId -> newActionRepository.findById(actionId, Optional.empty())) .map(newAction -> { // Update collectionId and defaultCollectionIds in actionDTOs ActionDTO unpublishedAction = newAction.getUnpublishedAction(); @@ -1906,7 +1911,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli // No matching existing datasource found, so create a new one. datasource.setIsConfigured(datasourceConfig != null && datasourceConfig.getAuthentication() != null); return datasourceService - .findByNameAndWorkspaceId(datasource.getName(), workspaceId, datasourcePermission.getEditPermission()) + .findByNameAndWorkspaceId(datasource.getName(), workspaceId, Optional.empty()) .flatMap(duplicateNameDatasource -> getUniqueSuffixForDuplicateNameEntity(duplicateNameDatasource, workspaceId) ) @@ -1914,7 +1919,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli datasource.setName(datasource.getName() + suffix); return datasource; }) - .then(datasourceService.create(datasource)); + .then(datasourceService.createWithoutPermissions(datasource)); })); } @@ -2000,8 +2005,8 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli public Mono> findDatasourceByApplicationId(String applicationId, String workspaceId) { // TODO: Investigate further why datasourcePermission.getReadPermission() is not being used. - Mono> listMono = datasourceService.findAllByWorkspaceId(workspaceId, datasourcePermission.getEditPermission()).collectList(); - return newActionService.findAllByApplicationIdAndViewMode(applicationId, false, actionPermission.getReadPermission(), null) + Mono> listMono = datasourceService.findAllByWorkspaceId(workspaceId, Optional.empty()).collectList(); + return newActionService.findAllByApplicationIdAndViewMode(applicationId, false, Optional.empty(), Optional.empty()) .collectList() .zipWith(listMono) .flatMap(objects -> { @@ -2107,7 +2112,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli applicationJson.setActionCollectionList(importedActionCollectionList); } - return importApplicationInWorkspace(workspaceId, applicationJson, applicationId, branchName, true); + return importApplicationInWorkspace(workspaceId, applicationJson, applicationId, branchName, true, !StringUtils.isEmpty(branchName)); } private Mono> updateNewPagesBeforeMerge(Mono> existingPagesMono, List newPagesList) { @@ -2150,7 +2155,7 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli */ private Mono sendImportExportApplicationAnalyticsEvent(String applicationId, AnalyticsEvents event) { - return applicationService.findById(applicationId, applicationPermission.getReadPermission()) + return applicationService.findById(applicationId, Optional.empty()) .flatMap(application -> { return Mono.zip(Mono.just(application), workspaceService.getById(application.getWorkspaceId())); }) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java index b7a06ef90f..a144e18758 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java @@ -1,6 +1,7 @@ package com.appsmith.server.services; import com.appsmith.external.models.DefaultResources; +import com.appsmith.server.acl.AclPermission; import com.appsmith.server.acl.PolicyGenerator; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.ActionCollection; @@ -53,6 +54,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -213,7 +215,7 @@ public class ActionCollectionServiceImplTest { final JsonNode jsonNode = objectMapper.readValue(mockObjects, JsonNode.class); final NewPage newPage = objectMapper.convertValue(jsonNode.get("newPage"), NewPage.class); Mockito - .when(newPageService.findById(Mockito.any(), Mockito.any())) + .when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito .when(layoutActionService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any())) @@ -256,7 +258,7 @@ public class ActionCollectionServiceImplTest { final NewPage newPage = objectMapper.convertValue(jsonNode.get("newPage"), NewPage.class); Mockito - .when(newPageService.findById(Mockito.any(), Mockito.any())) + .when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito .when(layoutActionService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any())) @@ -329,7 +331,7 @@ public class ActionCollectionServiceImplTest { final NewPage newPage = objectMapper.convertValue(jsonNode.get("newPage"), NewPage.class); Mockito - .when(newPageService.findById(Mockito.any(), Mockito.any())) + .when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito .when(layoutActionService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any())) @@ -425,7 +427,7 @@ public class ActionCollectionServiceImplTest { final NewPage newPage = objectMapper.convertValue(jsonNode.get("newPage"), NewPage.class); Mockito - .when(actionCollectionRepository.findById(Mockito.anyString(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.anyString(), Mockito.any())) .thenReturn(Mono.empty()); Mockito @@ -436,7 +438,7 @@ public class ActionCollectionServiceImplTest { Mockito .when(newPageService - .findById(Mockito.any(), Mockito.any())) + .findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); final Mono actionCollectionDTOMono = @@ -490,7 +492,7 @@ public class ActionCollectionServiceImplTest { .thenReturn(Mono.just((Mockito.mock(UpdateResult.class)))); Mockito - .when(actionCollectionRepository.findById(Mockito.anyString(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.anyString(), Mockito.any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -516,7 +518,7 @@ public class ActionCollectionServiceImplTest { Mockito .when(newPageService - .findById(Mockito.any(), Mockito.any())) + .findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito.when(actionCollectionRepository.setUserPermissionsInObject(Mockito.any())) @@ -552,7 +554,7 @@ public class ActionCollectionServiceImplTest { @Test public void testDeleteUnpublishedActionCollection_withInvalidId_throwsError() { Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.>any())) .thenReturn(Mono.empty()); final Mono actionCollectionMono = @@ -580,7 +582,7 @@ public class ActionCollectionServiceImplTest { Instant deletedAt = Instant.now(); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.>any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -614,7 +616,7 @@ public class ActionCollectionServiceImplTest { Instant deletedAt = Instant.now(); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.>any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -651,7 +653,7 @@ public class ActionCollectionServiceImplTest { actionCollection.getUnpublishedCollection().setDefaultResources(setDefaultResources(actionCollection.getUnpublishedCollection())); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.>any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -684,7 +686,7 @@ public class ActionCollectionServiceImplTest { actionCollection.getUnpublishedCollection().setDefaultResources(setDefaultResources(actionCollection.getUnpublishedCollection())); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.>any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -783,7 +785,7 @@ public class ActionCollectionServiceImplTest { .thenReturn(Mono.just(true)); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(oldActionCollection)); Mockito @@ -851,7 +853,7 @@ public class ActionCollectionServiceImplTest { .thenReturn(Mono.just(true)); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(oldActionCollection)); Mockito @@ -919,7 +921,7 @@ public class ActionCollectionServiceImplTest { action.setDefaultResources(actionResources); Mockito - .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) + .when(actionCollectionRepository.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(actionCollection)); Mockito @@ -959,7 +961,7 @@ public class ActionCollectionServiceImplTest { .thenReturn(Mono.just(newPageDTO)); Mockito - .when(newPageService.findById(Mockito.any(), Mockito.any())) + .when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); LayoutDTO layout = new LayoutDTO(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/GitServiceCEImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/GitServiceCEImplTest.java index 9ae7d83489..b50b972c8b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/GitServiceCEImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/GitServiceCEImplTest.java @@ -17,6 +17,7 @@ import com.appsmith.server.services.PluginService; import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.UserDataService; import com.appsmith.server.services.UserService; +import com.appsmith.server.services.WorkspaceService; import com.appsmith.server.solutions.ActionPermission; import com.appsmith.server.solutions.ApplicationPermission; import com.appsmith.server.solutions.DatasourcePermission; @@ -86,6 +87,8 @@ public class GitServiceCEImplTest { PagePermission pagePermission; @MockBean ActionPermission actionPermission; + @MockBean + WorkspaceService workspaceService; @BeforeEach public void setup() { @@ -94,7 +97,7 @@ public class GitServiceCEImplTest { newPageService, newActionService, actionCollectionService, gitFileUtils, importExportApplicationService, gitExecutor, responseUtils, emailConfig, analyticsService, gitCloudServicesUtils, gitDeployKeysRepository, datasourceService, pluginService, datasourcePermission, applicationPermission, pagePermission, - actionPermission + actionPermission, workspaceService ); }