fix: fixed failing queries using aggregation pipeline (#26132)
## Description > Queries using aggregation update failing. hence added a fallback. #### PR fixes following issue(s) Fixes #26090 Fixes https://github.com/appsmithorg/appsmith-ee/issues/1659 #### Type of change - Bug fix (non-breaking change which fixes an issue) ## Testing > #### How Has This Been Tested? - [x] Manual - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
parent
9964be125a
commit
439af21522
|
|
@ -15,7 +15,7 @@ import com.appsmith.server.dtos.ce.ImportActionResultDTO;
|
||||||
import com.appsmith.server.dtos.ce.ImportedActionAndCollectionMapsDTO;
|
import com.appsmith.server.dtos.ce.ImportedActionAndCollectionMapsDTO;
|
||||||
import com.appsmith.server.helpers.ce.ImportApplicationPermissionProvider;
|
import com.appsmith.server.helpers.ce.ImportApplicationPermissionProvider;
|
||||||
import com.appsmith.server.services.CrudService;
|
import com.appsmith.server.services.CrudService;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
@ -138,7 +138,7 @@ public interface NewActionServiceCE extends CrudService<NewAction, String> {
|
||||||
ImportActionCollectionResultDTO importActionCollectionResultDTO,
|
ImportActionCollectionResultDTO importActionCollectionResultDTO,
|
||||||
ImportActionResultDTO importActionResultDTO);
|
ImportActionResultDTO importActionResultDTO);
|
||||||
|
|
||||||
Mono<UpdateResult> publishActions(String applicationId, AclPermission permission);
|
Mono<List<BulkWriteResult>> publishActions(String applicationId, AclPermission permission);
|
||||||
|
|
||||||
Flux<PluginTypeAndCountDTO> countActionsByPluginType(String applicationId);
|
Flux<PluginTypeAndCountDTO> countActionsByPluginType(String applicationId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
import com.appsmith.server.solutions.DatasourcePermission;
|
import com.appsmith.server.solutions.DatasourcePermission;
|
||||||
import com.appsmith.server.solutions.PagePermission;
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
import com.appsmith.server.solutions.PolicySolution;
|
import com.appsmith.server.solutions.PolicySolution;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -664,7 +664,7 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<NewAction> findAllById(Iterable<String> id) {
|
public Flux<NewAction> findAllById(Iterable<String> id) {
|
||||||
return repository.findAllById(id).flatMap(this::sanitizeAction);
|
return repository.findAllByIdIn(id).flatMap(this::sanitizeAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1908,7 +1908,7 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
|
||||||
}
|
}
|
||||||
|
|
||||||
return repository
|
return repository
|
||||||
.findAllById(actionIds)
|
.findAllByIdIn(actionIds)
|
||||||
.map(newAction -> {
|
.map(newAction -> {
|
||||||
// Update collectionId and defaultCollectionIds in actionDTOs
|
// Update collectionId and defaultCollectionIds in actionDTOs
|
||||||
ActionDTO unpublishedAction = newAction.getUnpublishedAction();
|
ActionDTO unpublishedAction = newAction.getUnpublishedAction();
|
||||||
|
|
@ -1960,12 +1960,13 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
|
||||||
* This method is used to publish actions of an application. It does two things:
|
* This method is used to publish actions of an application. It does two things:
|
||||||
* 1. it deletes actions which are deleted from the edit mode.
|
* 1. it deletes actions which are deleted from the edit mode.
|
||||||
* 2. It updates actions in bulk by setting publishedAction=unpublishedAction
|
* 2. It updates actions in bulk by setting publishedAction=unpublishedAction
|
||||||
|
*
|
||||||
* @param applicationId
|
* @param applicationId
|
||||||
* @param permission
|
* @param permission
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Mono<UpdateResult> publishActions(String applicationId, AclPermission permission) {
|
public Mono<List<BulkWriteResult>> publishActions(String applicationId, AclPermission permission) {
|
||||||
// delete the actions that were deleted in edit mode
|
// delete the actions that were deleted in edit mode
|
||||||
return repository
|
return repository
|
||||||
.archiveDeletedUnpublishedActions(applicationId, permission)
|
.archiveDeletedUnpublishedActions(applicationId, permission)
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,9 @@ public class BaseRepositoryImpl<T extends BaseDomain, ID extends Serializable>
|
||||||
.flatMapMany(principal -> {
|
.flatMapMany(principal -> {
|
||||||
Query query = new Query(notDeleted());
|
Query query = new Query(notDeleted());
|
||||||
return mongoOperations.find(
|
return mongoOperations.find(
|
||||||
query, entityInformation.getJavaType(), entityInformation.getCollectionName());
|
query.cursorBatchSize(10000),
|
||||||
|
entityInformation.getJavaType(),
|
||||||
|
entityInformation.getCollectionName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.appsmith.server.repositories;
|
||||||
|
|
||||||
import com.appsmith.server.repositories.ce.CustomNewActionRepositoryCEImpl;
|
import com.appsmith.server.repositories.ce.CustomNewActionRepositoryCEImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -14,7 +15,8 @@ public class CustomNewActionRepositoryImpl extends CustomNewActionRepositoryCEIm
|
||||||
public CustomNewActionRepositoryImpl(
|
public CustomNewActionRepositoryImpl(
|
||||||
ReactiveMongoOperations mongoOperations,
|
ReactiveMongoOperations mongoOperations,
|
||||||
MongoConverter mongoConverter,
|
MongoConverter mongoConverter,
|
||||||
CacheableRepositoryHelper cacheableRepositoryHelper) {
|
CacheableRepositoryHelper cacheableRepositoryHelper,
|
||||||
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
MongoTemplate mongoTemplate) {
|
||||||
|
super(mongoOperations, mongoConverter, cacheableRepositoryHelper, mongoTemplate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.appsmith.server.repositories;
|
||||||
|
|
||||||
import com.appsmith.server.repositories.ce.CustomNewPageRepositoryCEImpl;
|
import com.appsmith.server.repositories.ce.CustomNewPageRepositoryCEImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -13,7 +14,8 @@ public class CustomNewPageRepositoryImpl extends CustomNewPageRepositoryCEImpl i
|
||||||
public CustomNewPageRepositoryImpl(
|
public CustomNewPageRepositoryImpl(
|
||||||
ReactiveMongoOperations mongoOperations,
|
ReactiveMongoOperations mongoOperations,
|
||||||
MongoConverter mongoConverter,
|
MongoConverter mongoConverter,
|
||||||
CacheableRepositoryHelper cacheableRepositoryHelper) {
|
CacheableRepositoryHelper cacheableRepositoryHelper,
|
||||||
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
MongoTemplate mongoTemplate) {
|
||||||
|
super(mongoOperations, mongoConverter, cacheableRepositoryHelper, mongoTemplate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update;
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||||
|
import org.springframework.data.mongodb.repository.Meta;
|
||||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
@ -166,7 +167,7 @@ public abstract class BaseAppsmithRepositoryCEImpl<T extends BaseDomain> {
|
||||||
|
|
||||||
return mongoOperations
|
return mongoOperations
|
||||||
.query(this.genericDomain)
|
.query(this.genericDomain)
|
||||||
.matching(query)
|
.matching(query.cursorBatchSize(10000))
|
||||||
.one()
|
.one()
|
||||||
.flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups));
|
.flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups));
|
||||||
});
|
});
|
||||||
|
|
@ -331,6 +332,7 @@ public abstract class BaseAppsmithRepositoryCEImpl<T extends BaseDomain> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Meta(cursorBatchSize = 10000)
|
||||||
protected Mono<T> queryOne(
|
protected Mono<T> queryOne(
|
||||||
List<Criteria> criterias, List<String> projectionFieldNames, Optional<AclPermission> permission) {
|
List<Criteria> criterias, List<String> projectionFieldNames, Optional<AclPermission> permission) {
|
||||||
Mono<Set<String>> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission);
|
Mono<Set<String>> permissionGroupsMono = getCurrentUserPermissionGroupsIfRequired(permission);
|
||||||
|
|
@ -539,7 +541,7 @@ public abstract class BaseAppsmithRepositoryCEImpl<T extends BaseDomain> {
|
||||||
sortOptional.ifPresent(sort -> query.with(sort));
|
sortOptional.ifPresent(sort -> query.with(sort));
|
||||||
return mongoOperations
|
return mongoOperations
|
||||||
.query(this.genericDomain)
|
.query(this.genericDomain)
|
||||||
.matching(query)
|
.matching(query.cursorBatchSize(10000))
|
||||||
.all()
|
.all()
|
||||||
.flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups));
|
.flatMap(obj -> setUserPermissionsInObject(obj, permissionGroups));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ public interface CustomNewActionRepositoryCE extends AppsmithRepository<NewActio
|
||||||
|
|
||||||
Mono<List<BulkWriteResult>> bulkUpdate(List<NewAction> newActions);
|
Mono<List<BulkWriteResult>> bulkUpdate(List<NewAction> newActions);
|
||||||
|
|
||||||
Mono<UpdateResult> publishActions(String applicationId, AclPermission permission);
|
Mono<List<BulkWriteResult>> publishActions(String applicationId, AclPermission permission);
|
||||||
|
|
||||||
Mono<UpdateResult> archiveDeletedUnpublishedActions(String applicationId, AclPermission permission);
|
Mono<UpdateResult> archiveDeletedUnpublishedActions(String applicationId, AclPermission permission);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
|
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.Fields;
|
||||||
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
|
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
|
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
|
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
|
||||||
|
|
@ -52,11 +55,15 @@ import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||||
public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl<NewAction>
|
public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl<NewAction>
|
||||||
implements CustomNewActionRepositoryCE {
|
implements CustomNewActionRepositoryCE {
|
||||||
|
|
||||||
|
private final MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
public CustomNewActionRepositoryCEImpl(
|
public CustomNewActionRepositoryCEImpl(
|
||||||
ReactiveMongoOperations mongoOperations,
|
ReactiveMongoOperations mongoOperations,
|
||||||
MongoConverter mongoConverter,
|
MongoConverter mongoConverter,
|
||||||
CacheableRepositoryHelper cacheableRepositoryHelper) {
|
CacheableRepositoryHelper cacheableRepositoryHelper,
|
||||||
|
MongoTemplate mongoTemplate) {
|
||||||
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -571,16 +578,33 @@ public class CustomNewActionRepositoryCEImpl extends BaseAppsmithRepositoryImpl<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<UpdateResult> publishActions(String applicationId, AclPermission permission) {
|
public Mono<List<BulkWriteResult>> publishActions(String applicationId, AclPermission permission) {
|
||||||
Criteria applicationIdCriteria =
|
Criteria applicationIdCriteria =
|
||||||
where(fieldName(QNewAction.newAction.applicationId)).is(applicationId);
|
where(fieldName(QNewAction.newAction.applicationId)).is(applicationId);
|
||||||
// using aggregation update instead of regular update here
|
|
||||||
// it's required to set a field to a value of another field from the same domain
|
|
||||||
AggregationUpdate aggregationUpdate = AggregationUpdate.update()
|
|
||||||
.set(fieldName(QNewAction.newAction.publishedAction))
|
|
||||||
.toValue("$" + fieldName(QNewAction.newAction.unpublishedAction));
|
|
||||||
|
|
||||||
return updateByCriteria(List.of(applicationIdCriteria), aggregationUpdate, permission);
|
Mono<Set<String>> permissionGroupsMono =
|
||||||
|
getCurrentUserPermissionGroupsIfRequired(Optional.ofNullable(permission));
|
||||||
|
|
||||||
|
return permissionGroupsMono.flatMap(permissionGroups -> {
|
||||||
|
AggregationOperation matchAggregationWithPermission = null;
|
||||||
|
if (permission == null) {
|
||||||
|
matchAggregationWithPermission = Aggregation.match(new Criteria().andOperator(notDeleted()));
|
||||||
|
} else {
|
||||||
|
matchAggregationWithPermission = Aggregation.match(
|
||||||
|
new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission)));
|
||||||
|
}
|
||||||
|
AggregationOperation matchAggregation = Aggregation.match(applicationIdCriteria);
|
||||||
|
AggregationOperation wholeProjection = Aggregation.project(NewAction.class);
|
||||||
|
AggregationOperation addFieldsOperation = Aggregation.addFields()
|
||||||
|
.addField(fieldName(QNewAction.newAction.publishedAction))
|
||||||
|
.withValueOf(Fields.field(fieldName(QNewAction.newAction.unpublishedAction)))
|
||||||
|
.build();
|
||||||
|
Aggregation combinedAggregation = Aggregation.newAggregation(
|
||||||
|
matchAggregation, matchAggregationWithPermission, wholeProjection, addFieldsOperation);
|
||||||
|
AggregationResults<NewAction> updatedResults =
|
||||||
|
mongoTemplate.aggregate(combinedAggregation, NewAction.class, NewAction.class);
|
||||||
|
return bulkUpdate(updatedResults.getMappedResults());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package com.appsmith.server.repositories.ce;
|
||||||
import com.appsmith.server.acl.AclPermission;
|
import com.appsmith.server.acl.AclPermission;
|
||||||
import com.appsmith.server.domains.NewPage;
|
import com.appsmith.server.domains.NewPage;
|
||||||
import com.appsmith.server.repositories.AppsmithRepository;
|
import com.appsmith.server.repositories.AppsmithRepository;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
|
@ -43,5 +43,7 @@ public interface CustomNewPageRepositoryCE extends AppsmithRepository<NewPage> {
|
||||||
Mono<NewPage> findByGitSyncIdAndDefaultApplicationId(
|
Mono<NewPage> findByGitSyncIdAndDefaultApplicationId(
|
||||||
String defaultApplicationId, String gitSyncId, Optional<AclPermission> permission);
|
String defaultApplicationId, String gitSyncId, Optional<AclPermission> permission);
|
||||||
|
|
||||||
Mono<UpdateResult> publishPages(Collection<String> pageIds, AclPermission permission);
|
Mono<List<BulkWriteResult>> publishPages(Collection<String> pageIds, AclPermission permission);
|
||||||
|
|
||||||
|
Mono<List<BulkWriteResult>> bulkUpdate(List<NewPage> newPages);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,32 @@ import com.appsmith.server.domains.QNewPage;
|
||||||
import com.appsmith.server.dtos.PageDTO;
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl;
|
import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl;
|
||||||
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
|
import com.mongodb.client.model.UpdateOneModel;
|
||||||
|
import com.mongodb.client.model.WriteModel;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bson.Document;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
|
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||||
|
import org.springframework.data.mongodb.core.aggregation.Fields;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.springframework.data.mongodb.core.query.Criteria.where;
|
import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||||
|
|
||||||
|
|
@ -30,11 +42,15 @@ import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||||
public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl<NewPage>
|
public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl<NewPage>
|
||||||
implements CustomNewPageRepositoryCE {
|
implements CustomNewPageRepositoryCE {
|
||||||
|
|
||||||
|
private final MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
public CustomNewPageRepositoryCEImpl(
|
public CustomNewPageRepositoryCEImpl(
|
||||||
ReactiveMongoOperations mongoOperations,
|
ReactiveMongoOperations mongoOperations,
|
||||||
MongoConverter mongoConverter,
|
MongoConverter mongoConverter,
|
||||||
CacheableRepositoryHelper cacheableRepositoryHelper) {
|
CacheableRepositoryHelper cacheableRepositoryHelper,
|
||||||
|
MongoTemplate mongoTemplate) {
|
||||||
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
super(mongoOperations, mongoConverter, cacheableRepositoryHelper);
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -251,14 +267,55 @@ public class CustomNewPageRepositoryCEImpl extends BaseAppsmithRepositoryImpl<Ne
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<UpdateResult> publishPages(Collection<String> pageIds, AclPermission permission) {
|
public Mono<List<BulkWriteResult>> publishPages(Collection<String> pageIds, AclPermission permission) {
|
||||||
Criteria applicationIdCriteria = where(fieldName(QNewPage.newPage.id)).in(pageIds);
|
Criteria applicationIdCriteria = where(fieldName(QNewPage.newPage.id)).in(pageIds);
|
||||||
// using aggregation update instead of regular update here
|
|
||||||
// it's required to set a field to a value of another field from the same domain
|
|
||||||
AggregationUpdate aggregationUpdate = AggregationUpdate.update()
|
|
||||||
.set(fieldName(QNewPage.newPage.publishedPage))
|
|
||||||
.toValue("$" + fieldName(QNewPage.newPage.unpublishedPage));
|
|
||||||
|
|
||||||
return updateByCriteria(List.of(applicationIdCriteria), aggregationUpdate, permission);
|
Mono<Set<String>> permissionGroupsMono =
|
||||||
|
getCurrentUserPermissionGroupsIfRequired(Optional.ofNullable(permission));
|
||||||
|
|
||||||
|
return permissionGroupsMono.flatMap(permissionGroups -> {
|
||||||
|
AggregationOperation matchAggregationWithPermission = null;
|
||||||
|
if (permission == null) {
|
||||||
|
matchAggregationWithPermission = Aggregation.match(new Criteria().andOperator(notDeleted()));
|
||||||
|
} else {
|
||||||
|
matchAggregationWithPermission = Aggregation.match(
|
||||||
|
new Criteria().andOperator(notDeleted(), userAcl(permissionGroups, permission)));
|
||||||
|
}
|
||||||
|
AggregationOperation matchAggregation = Aggregation.match(applicationIdCriteria);
|
||||||
|
AggregationOperation wholeProjection = Aggregation.project(NewPage.class);
|
||||||
|
AggregationOperation addFieldsOperation = Aggregation.addFields()
|
||||||
|
.addField(fieldName(QNewPage.newPage.publishedPage))
|
||||||
|
.withValueOf(Fields.field(fieldName(QNewPage.newPage.unpublishedPage)))
|
||||||
|
.build();
|
||||||
|
Aggregation combinedAggregation = Aggregation.newAggregation(
|
||||||
|
matchAggregation, matchAggregationWithPermission, wholeProjection, addFieldsOperation);
|
||||||
|
AggregationResults<NewPage> updatedResults =
|
||||||
|
mongoTemplate.aggregate(combinedAggregation, NewPage.class, NewPage.class);
|
||||||
|
return bulkUpdate(updatedResults.getMappedResults());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<List<BulkWriteResult>> bulkUpdate(List<NewPage> newPages) {
|
||||||
|
if (CollectionUtils.isEmpty(newPages)) {
|
||||||
|
return Mono.just(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the list of new pages to a list of DBObjects
|
||||||
|
List<WriteModel<Document>> dbObjects = newPages.stream()
|
||||||
|
.map(newPage -> {
|
||||||
|
assert newPage.getId() != null;
|
||||||
|
Document document = new Document();
|
||||||
|
mongoOperations.getConverter().write(newPage, document);
|
||||||
|
document.remove("_id");
|
||||||
|
return (WriteModel<Document>) new UpdateOneModel<Document>(
|
||||||
|
new Document("_id", new ObjectId(newPage.getId())), new Document("$set", document));
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return mongoOperations
|
||||||
|
.getCollection(mongoOperations.getCollectionName(NewPage.class))
|
||||||
|
.flatMapMany(documentMongoCollection -> documentMongoCollection.bulkWrite(dbObjects))
|
||||||
|
.collectList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,17 @@ package com.appsmith.server.repositories.ce;
|
||||||
import com.appsmith.server.domains.NewAction;
|
import com.appsmith.server.domains.NewAction;
|
||||||
import com.appsmith.server.repositories.BaseRepository;
|
import com.appsmith.server.repositories.BaseRepository;
|
||||||
import com.appsmith.server.repositories.CustomNewActionRepository;
|
import com.appsmith.server.repositories.CustomNewActionRepository;
|
||||||
|
import org.springframework.data.mongodb.repository.Meta;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
public interface NewActionRepositoryCE extends BaseRepository<NewAction, String>, CustomNewActionRepository {
|
public interface NewActionRepositoryCE extends BaseRepository<NewAction, String>, CustomNewActionRepository {
|
||||||
|
|
||||||
|
@Meta(cursorBatchSize = 10000)
|
||||||
Flux<NewAction> findByApplicationId(String applicationId);
|
Flux<NewAction> findByApplicationId(String applicationId);
|
||||||
|
|
||||||
|
@Meta(cursorBatchSize = 10000)
|
||||||
|
Flux<NewAction> findAllByIdIn(Iterable<String> ids);
|
||||||
|
|
||||||
Mono<Long> countByDeletedAtNull();
|
Mono<Long> countByDeletedAtNull();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
import com.appsmith.server.solutions.PagePermission;
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
import com.appsmith.server.solutions.WorkspacePermission;
|
import com.appsmith.server.solutions.WorkspacePermission;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.client.result.UpdateResult;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
@ -1146,7 +1147,7 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
||||||
if (isPublishedManually) {
|
if (isPublishedManually) {
|
||||||
application.setLastDeployedAt(Instant.now());
|
application.setLastDeployedAt(Instant.now());
|
||||||
}
|
}
|
||||||
Mono<UpdateResult> publishPagesMono =
|
Mono<List<BulkWriteResult>> publishPagesMono =
|
||||||
newPageService.publishPages(editedPageIds, pagePermission.getEditPermission());
|
newPageService.publishPages(editedPageIds, pagePermission.getEditPermission());
|
||||||
|
|
||||||
// Archive the deleted pages and save the application changes and then return the pages so that
|
// Archive the deleted pages and save the application changes and then return the pages so that
|
||||||
|
|
@ -1156,7 +1157,7 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
||||||
})
|
})
|
||||||
.cache(); // caching as we'll need this to send analytics attributes after publishing the app
|
.cache(); // caching as we'll need this to send analytics attributes after publishing the app
|
||||||
|
|
||||||
Mono<UpdateResult> publishActionsMono =
|
Mono<List<BulkWriteResult>> publishActionsMono =
|
||||||
newActionService.publishActions(applicationId, actionPermission.getEditPermission());
|
newActionService.publishActions(applicationId, actionPermission.getEditPermission());
|
||||||
|
|
||||||
// this is a map of pluginType to count of actions for that pluginType, required for analytics
|
// this is a map of pluginType to count of actions for that pluginType, required for analytics
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import com.appsmith.server.domains.NewPage;
|
||||||
import com.appsmith.server.dtos.ApplicationPagesDTO;
|
import com.appsmith.server.dtos.ApplicationPagesDTO;
|
||||||
import com.appsmith.server.dtos.PageDTO;
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
import com.appsmith.server.services.CrudService;
|
import com.appsmith.server.services.CrudService;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
|
@ -93,5 +93,5 @@ public interface NewPageServiceCE extends CrudService<NewPage, String> {
|
||||||
|
|
||||||
Flux<NewPage> findPageSlugsByApplicationIds(List<String> applicationIds, AclPermission aclPermission);
|
Flux<NewPage> findPageSlugsByApplicationIds(List<String> applicationIds, AclPermission aclPermission);
|
||||||
|
|
||||||
Mono<UpdateResult> publishPages(Collection<String> pageIds, AclPermission permission);
|
Mono<List<BulkWriteResult>> publishPages(Collection<String> pageIds, AclPermission permission);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import com.appsmith.server.services.BaseService;
|
||||||
import com.appsmith.server.services.UserDataService;
|
import com.appsmith.server.services.UserDataService;
|
||||||
import com.appsmith.server.solutions.ApplicationPermission;
|
import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
import com.appsmith.server.solutions.PagePermission;
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.bulk.BulkWriteResult;
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.minidev.json.JSONObject;
|
import net.minidev.json.JSONObject;
|
||||||
|
|
@ -696,7 +696,7 @@ public class NewPageServiceCEImpl extends BaseService<NewPageRepository, NewPage
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<UpdateResult> publishPages(Collection<String> pageIds, AclPermission permission) {
|
public Mono<List<BulkWriteResult>> publishPages(Collection<String> pageIds, AclPermission permission) {
|
||||||
return repository.publishPages(pageIds, permission);
|
return repository.publishPages(pageIds, permission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
import com.appsmith.server.solutions.DatasourcePermission;
|
import com.appsmith.server.solutions.DatasourcePermission;
|
||||||
import com.appsmith.server.solutions.PagePermission;
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
import com.appsmith.server.solutions.PolicySolution;
|
import com.appsmith.server.solutions.PolicySolution;
|
||||||
import com.mongodb.client.result.UpdateResult;
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
import jakarta.validation.Validator;
|
import jakarta.validation.Validator;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -40,6 +39,8 @@ import reactor.core.publisher.Mono;
|
||||||
import reactor.core.scheduler.Scheduler;
|
import reactor.core.scheduler.Scheduler;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
|
||||||
|
|
@ -200,9 +201,8 @@ public class NewActionServiceUnitTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPublishActionArchivesAndPublishesActions() {
|
public void testPublishActionArchivesAndPublishesActions() {
|
||||||
String applicationId = "dummy-application-id";
|
String applicationId = "dummy-application-id";
|
||||||
UpdateResult updateResult = Mockito.mock(UpdateResult.class);
|
List updateResult = Mockito.mock(List.class);
|
||||||
Mockito.when(updateResult.getModifiedCount()).thenReturn(10L);
|
Mockito.when(updateResult.size()).thenReturn(10);
|
||||||
Mockito.when(updateResult.getMatchedCount()).thenReturn(5L);
|
|
||||||
|
|
||||||
Mockito.when(newActionRepository.archiveDeletedUnpublishedActions(
|
Mockito.when(newActionRepository.archiveDeletedUnpublishedActions(
|
||||||
applicationId, actionPermission.getEditPermission()))
|
applicationId, actionPermission.getEditPermission()))
|
||||||
|
|
@ -213,8 +213,7 @@ public class NewActionServiceUnitTest {
|
||||||
|
|
||||||
StepVerifier.create(newActionService.publishActions(applicationId, actionPermission.getEditPermission()))
|
StepVerifier.create(newActionService.publishActions(applicationId, actionPermission.getEditPermission()))
|
||||||
.assertNext(updateResult1 -> {
|
.assertNext(updateResult1 -> {
|
||||||
assertEquals(10L, updateResult1.getModifiedCount());
|
assertEquals(10, updateResult1.size());
|
||||||
assertEquals(5L, updateResult1.getMatchedCount());
|
|
||||||
})
|
})
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user