fix: duplicate name issue in partial import for queries and jsobjects (#30457)
## Description When the queries and js objects are imported in the same page, the names were not updated properly which ended up with duplicate names for queries and jsobjects. This PR adds a fix which will append the number in the increasing order to avoid the duplicate entries for the above scenario. Example - jsObject will be jsObject1 #### PR fixes following issue(s) Fixes #30291 #### Type of change - Bug fix (non-breaking change which fixes an issue) ## Testing #### How Has This Been Tested? - [ ] Manual - [ ] JUnit #### 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 - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] 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 is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced import functionality to support partial imports, allowing users to selectively import components into their applications. - **Refactoring** - Codebase refactored to improve the clarity and efficiency of the import services. - **Tests** - Expanded test coverage to include new cases for partial imports and ensure the integrity of import operations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
10a98f9563
commit
ab64bf29af
|
|
@ -53,8 +53,7 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
List<ActionCollection> importedActionCollectionList =
|
||||
CollectionUtils.isEmpty(applicationJson.getActionCollectionList())
|
||||
? new ArrayList<>()
|
||||
|
|
@ -156,6 +155,15 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic
|
|||
actionCollectionsInBranchesMono = Mono.just(Collections.emptyMap());
|
||||
}
|
||||
|
||||
// update the action name in the json to avoid duplicate names for the partial import
|
||||
// It is page level action and hence the action name should be unique
|
||||
if (Boolean.TRUE.equals(importingMetaDTO.getIsPartialImport())
|
||||
&& mappedImportableResourcesDTO.getRefactoringNameReference() != null) {
|
||||
updateActionCollectionNameBeforeMerge(
|
||||
importedActionCollectionList,
|
||||
mappedImportableResourcesDTO.getRefactoringNameReference());
|
||||
}
|
||||
|
||||
return Mono.zip(actionCollectionsInCurrentAppMono, actionCollectionsInBranchesMono)
|
||||
.flatMap(objects -> {
|
||||
Map<String, ActionCollection> actionsCollectionsInCurrentApp = objects.getT1();
|
||||
|
|
@ -323,6 +331,28 @@ public class ActionCollectionImportableServiceCEImpl implements ImportableServic
|
|||
});
|
||||
}
|
||||
|
||||
private void updateActionCollectionNameBeforeMerge(
|
||||
List<ActionCollection> importedNewActionCollectionList, Set<String> refactoringNameSet) {
|
||||
|
||||
for (ActionCollection actionCollection : importedNewActionCollectionList) {
|
||||
String
|
||||
oldNameActionCollection =
|
||||
actionCollection.getUnpublishedCollection().getName(),
|
||||
newNameActionCollection =
|
||||
actionCollection.getUnpublishedCollection().getName();
|
||||
int i = 1;
|
||||
while (refactoringNameSet.contains(newNameActionCollection)) {
|
||||
newNameActionCollection = oldNameActionCollection + i++;
|
||||
}
|
||||
String oldId = actionCollection.getId().split("_")[1];
|
||||
actionCollection.setId(newNameActionCollection + "_" + oldId);
|
||||
actionCollection.getUnpublishedCollection().setName(newNameActionCollection);
|
||||
if (actionCollection.getPublishedCollection() != null) {
|
||||
actionCollection.getPublishedCollection().setName(newNameActionCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Flux<ActionCollection> getCollectionsInCurrentAppFlux(Application importedApplication) {
|
||||
return repository.findByApplicationId(importedApplication.getId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,8 +250,7 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
// Requires pageNameMap, pageNameToOldNameMap, pluginMap and actionResultDTO to be present in importable
|
||||
// resources.
|
||||
|
|
@ -262,8 +261,7 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> combinedActionImportablesMono = importedNewActionsMono.then(importedActionCollectionsMono);
|
||||
return List.of(combinedActionImportablesMono);
|
||||
|
|
@ -443,12 +441,7 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
|
||||
// Persists relevant information and updates mapped resources
|
||||
return customJSLibImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
null,
|
||||
null,
|
||||
(ApplicationJson) artifactExchangeJson,
|
||||
false);
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, (ApplicationJson) artifactExchangeJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -595,9 +588,9 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
ImportingMetaDTO importingMetaDTO) {
|
||||
return Mono.just((Application) importableContext).flatMap(application -> {
|
||||
return newActionImportableService
|
||||
.updateImportedEntities(application, importingMetaDTO, mappedImportableResourcesDTO, false)
|
||||
.updateImportedEntities(application, importingMetaDTO, mappedImportableResourcesDTO)
|
||||
.then(newPageImportableService.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO, false))
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO))
|
||||
.thenReturn(application);
|
||||
});
|
||||
}
|
||||
|
|
@ -649,8 +642,7 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
Mono.just(application),
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
// Directly updates required theme information in DB
|
||||
Mono<Void> importedThemesMono = themeImportableService.importEntities(
|
||||
|
|
@ -659,7 +651,6 @@ public class ApplicationImportServiceCEImpl implements ApplicationImportServiceC
|
|||
workspaceMono,
|
||||
Mono.just(application),
|
||||
applicationJson,
|
||||
false,
|
||||
true);
|
||||
|
||||
return Flux.merge(List.of(importedPagesMono, importedThemesMono));
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public class DatasourceImportableServiceCEImpl implements ImportableServiceCE<Da
|
|||
Mono<Workspace> workspaceMono,
|
||||
Mono<? extends ImportableArtifact> importContextMono,
|
||||
ArtifactExchangeJson importableContextJson,
|
||||
boolean isPartialImport,
|
||||
boolean isContextAgnostic) {
|
||||
return importContextMono.flatMap(importableContext -> {
|
||||
Application application = (Application) importableContext;
|
||||
|
|
@ -73,8 +72,7 @@ public class DatasourceImportableServiceCEImpl implements ImportableServiceCE<Da
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
Mono.just(application),
|
||||
applicationJson,
|
||||
isPartialImport);
|
||||
applicationJson);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -87,8 +85,7 @@ public class DatasourceImportableServiceCEImpl implements ImportableServiceCE<Da
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
return workspaceMono.flatMap(workspace -> {
|
||||
final Flux<Datasource> existingDatasourceFlux = datasourceService
|
||||
.getAllByWorkspaceIdWithStorages(workspace.getId(), Optional.empty())
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ public class ImportingMetaDTO {
|
|||
*/
|
||||
Boolean appendToArtifact;
|
||||
|
||||
Boolean isPartialImport;
|
||||
|
||||
ImportArtifactPermissionProvider permissionProvider;
|
||||
Set<String> currentUserPermissionGroups;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import lombok.NoArgsConstructor;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
|
|
@ -24,6 +25,10 @@ public class MappedImportableResourcesCE_DTO {
|
|||
// This attribute is re-usable across artifacts according to the needs
|
||||
Map<String, String> pageOrModuleNewNameToOldName;
|
||||
|
||||
// Artifact independent, used in PartialImport
|
||||
// This attribute contain set of names used/existing in page such as widgetName, action and actionCollection names
|
||||
Set<String> refactoringNameReference;
|
||||
|
||||
/**
|
||||
* Attribute used to carry objects specific to the context of the Artifacts.
|
||||
* In case of application it carries the NewPage entity
|
||||
|
|
|
|||
|
|
@ -17,14 +17,12 @@ public interface ImportableServiceCE<T extends BaseDomain> {
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport);
|
||||
ApplicationJson applicationJson);
|
||||
|
||||
default Mono<Void> updateImportedEntities(
|
||||
Application application,
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
boolean isPartialImport) {
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +32,6 @@ public interface ImportableServiceCE<T extends BaseDomain> {
|
|||
Mono<Workspace> workspaceMono,
|
||||
Mono<? extends ImportableArtifact> importContextMono,
|
||||
ArtifactExchangeJson importableContextJson,
|
||||
boolean isPartialImport,
|
||||
boolean isContextAgnostic) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
}
|
||||
|
||||
ImportingMetaDTO importingMetaDTO = new ImportingMetaDTO(
|
||||
workspaceId, applicationId, branchName, appendToApp, permissionProvider, permissionGroups);
|
||||
workspaceId, applicationId, branchName, appendToApp, false, permissionProvider, permissionGroups);
|
||||
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO = new MappedImportableResourcesDTO();
|
||||
|
||||
|
|
@ -578,9 +578,9 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
.then(importedApplicationMono)
|
||||
.flatMap(application -> {
|
||||
return newActionImportableService
|
||||
.updateImportedEntities(application, importingMetaDTO, mappedImportableResourcesDTO, false)
|
||||
.updateImportedEntities(application, importingMetaDTO, mappedImportableResourcesDTO)
|
||||
.then(newPageImportableService.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO, false))
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO))
|
||||
.thenReturn(application);
|
||||
})
|
||||
.flatMap(application -> {
|
||||
|
|
@ -713,8 +713,7 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
// Requires pluginMap to be present in importable resources.
|
||||
// Updates datasourceNameToIdMap in importable resources.
|
||||
|
|
@ -746,8 +745,7 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
// Requires pageNameMap, pageNameToOldNameMap, pluginMap and actionResultDTO to be present in importable
|
||||
// resources.
|
||||
|
|
@ -758,8 +756,7 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
false);
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> combinedActionImportablesMono = importedNewActionsMono.then(importedActionCollectionsMono);
|
||||
return List.of(combinedActionImportablesMono);
|
||||
|
|
@ -771,7 +768,7 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
|
||||
// Persists relevant information and updates mapped resources
|
||||
Mono<Void> installedJsLibsMono = customJSLibImportableService.importEntities(
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson, false);
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson);
|
||||
return installedJsLibsMono;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -446,7 +446,7 @@ public class ImportServiceCEImpl implements ImportServiceCE {
|
|||
}
|
||||
|
||||
ImportingMetaDTO importingMetaDTO = new ImportingMetaDTO(
|
||||
workspaceId, artifactId, branchName, appendToArtifact, permissionProvider, permissionGroups);
|
||||
workspaceId, artifactId, branchName, appendToArtifact, false, permissionProvider, permissionGroups);
|
||||
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO = new MappedImportableResourcesDTO();
|
||||
contextBasedImportService.syncClientAndSchemaVersion(importedDoc);
|
||||
|
|
@ -655,7 +655,6 @@ public class ImportServiceCEImpl implements ImportServiceCE {
|
|||
workspaceMono,
|
||||
importedArtifactMono,
|
||||
artifactExchangeJson,
|
||||
false,
|
||||
true);
|
||||
|
||||
// Requires pluginMap to be present in importable resources.
|
||||
|
|
@ -667,7 +666,6 @@ public class ImportServiceCEImpl implements ImportServiceCE {
|
|||
workspaceMono,
|
||||
importedArtifactMono,
|
||||
artifactExchangeJson,
|
||||
false,
|
||||
true));
|
||||
|
||||
// Directly updates required theme information in DB
|
||||
|
|
@ -677,7 +675,6 @@ public class ImportServiceCEImpl implements ImportServiceCE {
|
|||
workspaceMono,
|
||||
importedArtifactMono,
|
||||
artifactExchangeJson,
|
||||
false,
|
||||
true);
|
||||
|
||||
return Flux.merge(List.of(importedDatasourcesMono, importedThemesMono));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.appsmith.server.imports.internal;
|
||||
|
||||
import com.appsmith.external.constants.AnalyticsEvents;
|
||||
import com.appsmith.external.models.CreatorContextType;
|
||||
import com.appsmith.external.models.Datasource;
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.applications.base.ApplicationService;
|
||||
|
|
@ -8,6 +9,7 @@ import com.appsmith.server.constants.FieldName;
|
|||
import com.appsmith.server.domains.ActionCollection;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.CustomJSLib;
|
||||
import com.appsmith.server.domains.Layout;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
import com.appsmith.server.domains.NewPage;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
|
|
@ -21,6 +23,7 @@ import com.appsmith.server.exceptions.AppsmithException;
|
|||
import com.appsmith.server.helpers.ce.ImportArtifactPermissionProvider;
|
||||
import com.appsmith.server.imports.importable.ImportableService;
|
||||
import com.appsmith.server.newpages.base.NewPageService;
|
||||
import com.appsmith.server.refactors.applications.RefactoringService;
|
||||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
|
|
@ -64,6 +67,7 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
private final ImportableService<NewAction> newActionImportableService;
|
||||
private final ImportableService<ActionCollection> actionCollectionImportableService;
|
||||
private final NewPageService newPageService;
|
||||
private final RefactoringService refactoringService;
|
||||
|
||||
@Override
|
||||
public Mono<Application> importResourceInPage(
|
||||
|
|
@ -101,7 +105,7 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
.cache();
|
||||
|
||||
ImportingMetaDTO importingMetaDTO = new ImportingMetaDTO(
|
||||
workspaceId, applicationId, branchName, false, permissionProvider, null);
|
||||
workspaceId, applicationId, branchName, false, true, permissionProvider, null);
|
||||
|
||||
// Get the Application from DB
|
||||
Mono<Application> importedApplicationMono = applicationService
|
||||
|
|
@ -111,7 +115,19 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
permissionProvider.getRequiredPermissionOnTargetApplication())
|
||||
.cache();
|
||||
|
||||
return importedApplicationMono
|
||||
return newPageService
|
||||
.findByBranchNameAndDefaultPageId(branchName, pageId, AclPermission.MANAGE_PAGES)
|
||||
.flatMap(page -> {
|
||||
Layout layout =
|
||||
page.getUnpublishedPage().getLayouts().get(0);
|
||||
return refactoringService.getAllExistingEntitiesMono(
|
||||
page.getId(), CreatorContextType.PAGE, layout.getId(), false);
|
||||
})
|
||||
.flatMap(nameSet -> {
|
||||
// Fetch name of the existing resources in the page to avoid name clashing
|
||||
mappedImportableResourcesDTO.setRefactoringNameReference(nameSet);
|
||||
return importedApplicationMono;
|
||||
})
|
||||
.flatMap(application -> {
|
||||
applicationJson.setExportedApplication(application);
|
||||
return Mono.just(applicationJson);
|
||||
|
|
@ -147,9 +163,9 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
}
|
||||
return newActionImportableService
|
||||
.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO, true)
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO)
|
||||
.then(newPageImportableService.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO, true))
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO))
|
||||
.thenReturn(application);
|
||||
});
|
||||
})
|
||||
|
|
@ -221,7 +237,7 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
true);
|
||||
|
||||
Mono<Void> customJsLibMono = customJSLibImportableService.importEntities(
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson, true);
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson);
|
||||
|
||||
return pluginMono.then(datasourceMono).then(customJsLibMono).then();
|
||||
}
|
||||
|
|
@ -237,16 +253,14 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
true);
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> actionCollectionMono = actionCollectionImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson,
|
||||
true);
|
||||
applicationJson);
|
||||
|
||||
return actionMono.then(actionCollectionMono).then();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.appsmith.server.domains.NewPage;
|
|||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.imports.importable.ImportableService;
|
||||
import com.appsmith.server.newpages.base.NewPageService;
|
||||
import com.appsmith.server.refactors.applications.RefactoringService;
|
||||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
|
|
@ -47,7 +48,8 @@ public class PartialImportServiceImpl extends PartialImportServiceCEImpl impleme
|
|||
ImportableService<Datasource> datasourceImportableService,
|
||||
ImportableService<NewAction> newActionImportableService,
|
||||
ImportableService<ActionCollection> actionCollectionImportableService,
|
||||
NewPageService newPageService) {
|
||||
NewPageService newPageService,
|
||||
RefactoringService refactoringService) {
|
||||
super(
|
||||
importApplicationService,
|
||||
workspaceService,
|
||||
|
|
@ -67,6 +69,7 @@ public class PartialImportServiceImpl extends PartialImportServiceCEImpl impleme
|
|||
datasourceImportableService,
|
||||
newActionImportableService,
|
||||
actionCollectionImportableService,
|
||||
newPageService);
|
||||
newPageService,
|
||||
refactoringService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ public class CustomJSLibImportableServiceCEImpl implements ImportableServiceCE<C
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
List<CustomJSLib> customJSLibs = applicationJson.getCustomJSLibList();
|
||||
if (customJSLibs == null) {
|
||||
customJSLibs = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -63,8 +63,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
|
||||
List<NewAction> importedNewActionList = applicationJson.getActionList();
|
||||
|
||||
|
|
@ -104,7 +103,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
&& CollectionUtils.isNotEmpty(importActionResultDTO.getExistingActions())) {
|
||||
// Remove unwanted actions
|
||||
Set<String> invalidActionIds = new HashSet<>();
|
||||
if (Boolean.FALSE.equals(isPartialImport)) {
|
||||
if (Boolean.FALSE.equals(importingMetaDTO.getIsPartialImport())) {
|
||||
for (NewAction action : importActionResultDTO.getExistingActions()) {
|
||||
if (!importActionResultDTO
|
||||
.getImportedActionIds()
|
||||
|
|
@ -139,8 +138,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
public Mono<Void> updateImportedEntities(
|
||||
Application application,
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
boolean isPartialImport) {
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
|
||||
|
||||
ImportActionResultDTO importActionResultDTO = mappedImportableResourcesDTO.getActionResultDTO();
|
||||
ImportActionCollectionResultDTO importActionCollectionResultDTO =
|
||||
|
|
@ -162,7 +160,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
// the git flow only
|
||||
if (StringUtils.hasText(importingMetaDTO.getArtifactId())
|
||||
&& !TRUE.equals(importingMetaDTO.getAppendToArtifact())
|
||||
&& Boolean.FALSE.equals(isPartialImport)) {
|
||||
&& Boolean.FALSE.equals(importingMetaDTO.getIsPartialImport())) {
|
||||
// Remove unwanted action collections
|
||||
Set<String> invalidCollectionIds = new HashSet<>();
|
||||
for (ActionCollection collection :
|
||||
|
|
@ -240,6 +238,14 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
actionsInOtherBranchesMono = Mono.just(Collections.emptyMap());
|
||||
}
|
||||
|
||||
// update the action name in the json to avoid duplicate names for the partial import
|
||||
// It is page level action and hence the action name should be unique
|
||||
if (Boolean.TRUE.equals(importingMetaDTO.getIsPartialImport())
|
||||
&& mappedImportableResourcesDTO.getRefactoringNameReference() != null) {
|
||||
updateActionNameBeforeMerge(
|
||||
importedNewActionList, mappedImportableResourcesDTO.getRefactoringNameReference());
|
||||
}
|
||||
|
||||
return Mono.zip(actionsInCurrentAppMono, actionsInOtherBranchesMono)
|
||||
.flatMap(objects -> {
|
||||
Map<String, NewAction> actionsInCurrentApp = objects.getT1();
|
||||
|
|
@ -422,6 +428,26 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
});
|
||||
}
|
||||
|
||||
private void updateActionNameBeforeMerge(List<NewAction> importedNewActionList, Set<String> refactoringNames) {
|
||||
|
||||
for (NewAction newAction : importedNewActionList) {
|
||||
String oldNameAction = newAction.getUnpublishedAction().getName(),
|
||||
newNameAction = newAction.getUnpublishedAction().getName();
|
||||
int i = 1;
|
||||
while (refactoringNames.contains(newNameAction)) {
|
||||
newNameAction = oldNameAction + i++;
|
||||
}
|
||||
String oldId = newAction.getId().split("_")[1];
|
||||
newAction.setId(newNameAction + "_" + oldId);
|
||||
newAction.getUnpublishedAction().setName(newNameAction);
|
||||
newAction.getUnpublishedAction().setFullyQualifiedName(newNameAction);
|
||||
if (newAction.getPublishedAction() != null) {
|
||||
newAction.getPublishedAction().setName(newNameAction);
|
||||
newAction.getPublishedAction().setFullyQualifiedName(newNameAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void populateNewAction(
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
|
|
|
|||
|
|
@ -68,8 +68,7 @@ public class NewPageImportableServiceCEImpl implements ImportableServiceCE<NewPa
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
|
||||
List<NewPage> importedNewPageList = applicationJson.getPageList();
|
||||
|
||||
|
|
@ -114,8 +113,7 @@ public class NewPageImportableServiceCEImpl implements ImportableServiceCE<NewPa
|
|||
public Mono<Void> updateImportedEntities(
|
||||
Application application,
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
boolean isPartialImport) {
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
|
||||
|
||||
ImportedActionAndCollectionMapsDTO actionAndCollectionMapsDTO =
|
||||
mappedImportableResourcesDTO.getActionAndCollectionMapsDTO();
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ public class PluginImportableServiceCEImpl implements ImportableServiceCE<Plugin
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
return workspaceMono
|
||||
.map(workspace -> workspace.getPlugins().stream()
|
||||
.map(WorkspacePlugin::getPluginId)
|
||||
|
|
@ -65,7 +64,6 @@ public class PluginImportableServiceCEImpl implements ImportableServiceCE<Plugin
|
|||
Mono<Workspace> workspaceMono,
|
||||
Mono<? extends ImportableArtifact> importContextMono,
|
||||
ArtifactExchangeJson importableContextJson,
|
||||
boolean isPartialImport,
|
||||
boolean isContextAgnostic) {
|
||||
return importContextMono.flatMap(importableContext -> {
|
||||
Application application = (Application) importableContext;
|
||||
|
|
@ -75,8 +73,7 @@ public class PluginImportableServiceCEImpl implements ImportableServiceCE<Plugin
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
Mono.just(application),
|
||||
applicationJson,
|
||||
isPartialImport);
|
||||
applicationJson);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,7 @@ public class ThemeImportableServiceCEImpl implements ImportableServiceCE<Theme>
|
|||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> applicationMono,
|
||||
ApplicationJson applicationJson,
|
||||
boolean isPartialImport) {
|
||||
ApplicationJson applicationJson) {
|
||||
if (Boolean.TRUE.equals(importingMetaDTO.getAppendToArtifact())) {
|
||||
// appending to existing app, theme should not change
|
||||
return Mono.empty().then();
|
||||
|
|
@ -123,7 +122,6 @@ public class ThemeImportableServiceCEImpl implements ImportableServiceCE<Theme>
|
|||
Mono<Workspace> workspaceMono,
|
||||
Mono<? extends ImportableArtifact> importContextMono,
|
||||
ArtifactExchangeJson importableContextJson,
|
||||
boolean isPartialImport,
|
||||
boolean isContextAgnostic) {
|
||||
return importContextMono.flatMap(importableContext -> {
|
||||
Application application = (Application) importableContext;
|
||||
|
|
@ -133,8 +131,7 @@ public class ThemeImportableServiceCEImpl implements ImportableServiceCE<Theme>
|
|||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
Mono.just(application),
|
||||
applicationJson,
|
||||
isPartialImport);
|
||||
applicationJson);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.appsmith.server.services;
|
||||
package com.appsmith.server.solutions;
|
||||
|
||||
import com.appsmith.external.models.ActionConfiguration;
|
||||
import com.appsmith.external.models.ActionDTO;
|
||||
|
|
@ -30,8 +30,12 @@ import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
|||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.repositories.ThemeRepository;
|
||||
import com.appsmith.server.solutions.EnvironmentPermission;
|
||||
import com.appsmith.server.solutions.PagePermission;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.LayoutActionService;
|
||||
import com.appsmith.server.services.LayoutCollectionService;
|
||||
import com.appsmith.server.services.PermissionGroupService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -0,0 +1,446 @@
|
|||
package com.appsmith.server.solutions;
|
||||
|
||||
import com.appsmith.external.models.DBAuth;
|
||||
import com.appsmith.external.models.Datasource;
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import com.appsmith.external.models.DatasourceStorageDTO;
|
||||
import com.appsmith.external.models.DefaultResources;
|
||||
import com.appsmith.external.models.Property;
|
||||
import com.appsmith.server.actioncollections.base.ActionCollectionService;
|
||||
import com.appsmith.server.applications.base.ApplicationService;
|
||||
import com.appsmith.server.datasources.base.DatasourceService;
|
||||
import com.appsmith.server.domains.ActionCollection;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.GitApplicationMetadata;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.domains.Workspace;
|
||||
import com.appsmith.server.dtos.PageDTO;
|
||||
import com.appsmith.server.helpers.MockPluginExecutor;
|
||||
import com.appsmith.server.helpers.PluginExecutorHelper;
|
||||
import com.appsmith.server.imports.internal.PartialImportService;
|
||||
import com.appsmith.server.newactions.base.NewActionService;
|
||||
import com.appsmith.server.newpages.base.NewPageService;
|
||||
import com.appsmith.server.plugins.base.PluginService;
|
||||
import com.appsmith.server.repositories.ApplicationRepository;
|
||||
import com.appsmith.server.repositories.CacheableRepositoryHelper;
|
||||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.repositories.ThemeRepository;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.PermissionGroupService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.multipart.FilePart;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import reactor.util.function.Tuple3;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@Slf4j
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest
|
||||
public class PartialImportServiceTest {
|
||||
|
||||
private static final Map<String, Datasource> datasourceMap = new HashMap<>();
|
||||
private static Plugin installedPlugin;
|
||||
private static String workspaceId;
|
||||
private static String defaultEnvironmentId;
|
||||
private static String testAppId;
|
||||
private static Datasource jsDatasource;
|
||||
private static Plugin installedJsPlugin;
|
||||
private static Boolean isSetupDone = false;
|
||||
|
||||
@Autowired
|
||||
private ApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private NewPageService newPageService;
|
||||
|
||||
@Autowired
|
||||
private SessionUserService sessionUserService;
|
||||
|
||||
@Autowired
|
||||
ApplicationPageService applicationPageService;
|
||||
|
||||
@Autowired
|
||||
PluginRepository pluginRepository;
|
||||
|
||||
@Autowired
|
||||
ApplicationRepository applicationRepository;
|
||||
|
||||
@Autowired
|
||||
DatasourceService datasourceService;
|
||||
|
||||
@Autowired
|
||||
WorkspaceService workspaceService;
|
||||
|
||||
@MockBean
|
||||
PluginExecutorHelper pluginExecutorHelper;
|
||||
|
||||
@Autowired
|
||||
ThemeRepository themeRepository;
|
||||
|
||||
@Autowired
|
||||
PermissionGroupRepository permissionGroupRepository;
|
||||
|
||||
@Autowired
|
||||
PermissionGroupService permissionGroupService;
|
||||
|
||||
@Autowired
|
||||
EnvironmentPermission environmentPermission;
|
||||
|
||||
@Autowired
|
||||
PagePermission pagePermission;
|
||||
|
||||
@SpyBean
|
||||
PluginService pluginService;
|
||||
|
||||
@Autowired
|
||||
CacheableRepositoryHelper cacheableRepositoryHelper;
|
||||
|
||||
@Autowired
|
||||
Gson gson;
|
||||
|
||||
@Autowired
|
||||
PartialImportService partialImportService;
|
||||
|
||||
@Autowired
|
||||
NewActionService newActionService;
|
||||
|
||||
@Autowired
|
||||
ActionCollectionService actionCollectionService;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any()))
|
||||
.thenReturn(Mono.just(new MockPluginExecutor()));
|
||||
|
||||
if (Boolean.TRUE.equals(isSetupDone)) {
|
||||
return;
|
||||
}
|
||||
User currentUser = sessionUserService.getCurrentUser().block();
|
||||
Set<String> beforeCreatingWorkspace =
|
||||
cacheableRepositoryHelper.getPermissionGroupsOfUser(currentUser).block();
|
||||
log.info("Permission Groups for User before creating workspace: {}", beforeCreatingWorkspace);
|
||||
installedPlugin = pluginRepository.findByPackageName("installed-plugin").block();
|
||||
Workspace workspace = new Workspace();
|
||||
workspace.setName("Import-Export-Test-Workspace");
|
||||
Workspace savedWorkspace = workspaceService.create(workspace).block();
|
||||
workspaceId = savedWorkspace.getId();
|
||||
defaultEnvironmentId = workspaceService
|
||||
.getDefaultEnvironmentId(workspaceId, environmentPermission.getExecutePermission())
|
||||
.block();
|
||||
Set<String> afterCreatingWorkspace =
|
||||
cacheableRepositoryHelper.getPermissionGroupsOfUser(currentUser).block();
|
||||
log.info("Permission Groups for User after creating workspace: {}", afterCreatingWorkspace);
|
||||
|
||||
log.info("Workspace ID: {}", workspaceId);
|
||||
log.info("Workspace Role Ids: {}", workspace.getDefaultPermissionGroups());
|
||||
log.info("Policy for created Workspace: {}", workspace.getPolicies());
|
||||
log.info("Current User ID: {}", currentUser.getId());
|
||||
|
||||
Application testApplication = new Application();
|
||||
testApplication.setName("Export-Application-Test-Application");
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
testApplication.setUpdatedAt(Instant.now());
|
||||
testApplication.setLastDeployedAt(Instant.now());
|
||||
testApplication.setModifiedBy("some-user");
|
||||
testApplication.setGitApplicationMetadata(new GitApplicationMetadata());
|
||||
|
||||
Application savedApplication = applicationPageService
|
||||
.createApplication(testApplication, workspaceId)
|
||||
.block();
|
||||
testAppId = savedApplication.getId();
|
||||
|
||||
Datasource ds1 = new Datasource();
|
||||
ds1.setName("DS1");
|
||||
ds1.setWorkspaceId(workspaceId);
|
||||
ds1.setPluginId(installedPlugin.getId());
|
||||
final DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration();
|
||||
datasourceConfiguration.setUrl("http://example.org/get");
|
||||
datasourceConfiguration.setHeaders(List.of(new Property("X-Answer", "42")));
|
||||
|
||||
HashMap<String, DatasourceStorageDTO> storages1 = new HashMap<>();
|
||||
storages1.put(
|
||||
defaultEnvironmentId, new DatasourceStorageDTO(null, defaultEnvironmentId, datasourceConfiguration));
|
||||
ds1.setDatasourceStorages(storages1);
|
||||
|
||||
Datasource ds2 = new Datasource();
|
||||
ds2.setName("DS2");
|
||||
ds2.setPluginId(installedPlugin.getId());
|
||||
ds2.setWorkspaceId(workspaceId);
|
||||
DatasourceConfiguration datasourceConfiguration2 = new DatasourceConfiguration();
|
||||
DBAuth auth = new DBAuth();
|
||||
auth.setPassword("awesome-password");
|
||||
datasourceConfiguration2.setAuthentication(auth);
|
||||
HashMap<String, DatasourceStorageDTO> storages2 = new HashMap<>();
|
||||
storages2.put(
|
||||
defaultEnvironmentId, new DatasourceStorageDTO(null, defaultEnvironmentId, datasourceConfiguration2));
|
||||
ds2.setDatasourceStorages(storages2);
|
||||
|
||||
jsDatasource = new Datasource();
|
||||
jsDatasource.setName("Default JS datasource");
|
||||
jsDatasource.setWorkspaceId(workspaceId);
|
||||
installedJsPlugin =
|
||||
pluginRepository.findByPackageName("installed-js-plugin").block();
|
||||
assert installedJsPlugin != null;
|
||||
jsDatasource.setPluginId(installedJsPlugin.getId());
|
||||
|
||||
ds1 = datasourceService.create(ds1).block();
|
||||
ds2 = datasourceService.create(ds2).block();
|
||||
datasourceMap.put("DS1", ds1);
|
||||
datasourceMap.put("DS2", ds2);
|
||||
isSetupDone = true;
|
||||
}
|
||||
|
||||
private Application createGitConnectedApp(String applicationName) {
|
||||
// Create application connected to git
|
||||
Application testApplication = new Application();
|
||||
testApplication.setName(applicationName);
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
testApplication.setUpdatedAt(Instant.now());
|
||||
testApplication.setLastDeployedAt(Instant.now());
|
||||
testApplication.setModifiedBy("some-user");
|
||||
testApplication.setGitApplicationMetadata(new GitApplicationMetadata());
|
||||
GitApplicationMetadata gitData = new GitApplicationMetadata();
|
||||
gitData.setBranchName("master");
|
||||
gitData.setDefaultBranchName("master");
|
||||
testApplication.setGitApplicationMetadata(gitData);
|
||||
|
||||
return applicationPageService
|
||||
.createApplication(testApplication, workspaceId)
|
||||
.flatMap(application1 -> {
|
||||
application1.getGitApplicationMetadata().setDefaultApplicationId(application1.getId());
|
||||
return applicationService.save(application1);
|
||||
})
|
||||
.block();
|
||||
}
|
||||
|
||||
private FilePart createFilePart(String filePath) {
|
||||
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
Flux<DataBuffer> dataBufferFlux = DataBufferUtils.read(
|
||||
new ClassPathResource(filePath), new DefaultDataBufferFactory(), 4096)
|
||||
.cache();
|
||||
|
||||
Mockito.when(filepart.content()).thenReturn(dataBufferFlux);
|
||||
Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.APPLICATION_JSON);
|
||||
|
||||
return filepart;
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testPartialImport_nonGitConnectedApp_success() {
|
||||
|
||||
// Create an application with all resources
|
||||
Application testApplication = new Application();
|
||||
testApplication.setName("testPartialImport_nonGitConnectedApp_success");
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
|
||||
testApplication = applicationPageService
|
||||
.createApplication(testApplication, workspaceId)
|
||||
.block();
|
||||
|
||||
String pageId = newPageService
|
||||
.findById(testApplication.getPages().get(0).getId(), Optional.empty())
|
||||
.block()
|
||||
.getId();
|
||||
|
||||
Part filePart = createFilePart("test_assets/ImportExportServiceTest/partial-export-resource.json");
|
||||
|
||||
Mono<Tuple3<Application, List<NewAction>, List<ActionCollection>>> result = partialImportService
|
||||
.importResourceInPage(workspaceId, testApplication.getId(), pageId, null, filePart)
|
||||
.flatMap(application -> {
|
||||
Mono<List<NewAction>> actionList = newActionService
|
||||
.findByPageId(pageId, Optional.empty())
|
||||
.collectList();
|
||||
Mono<List<ActionCollection>> actionCollectionList =
|
||||
actionCollectionService.findByPageId(pageId).collectList();
|
||||
|
||||
return Mono.zip(Mono.just(application), actionList, actionCollectionList);
|
||||
});
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(object -> {
|
||||
Application application = object.getT1();
|
||||
List<NewAction> actionList = object.getT2();
|
||||
List<ActionCollection> actionCollectionList = object.getT3();
|
||||
|
||||
// Verify that the application has the imported resource
|
||||
assertThat(application.getPages().size()).isEqualTo(1);
|
||||
|
||||
assertThat(actionCollectionList.size()).isEqualTo(1);
|
||||
assertThat(actionCollectionList
|
||||
.get(0)
|
||||
.getUnpublishedCollection()
|
||||
.getName())
|
||||
.isEqualTo("utils");
|
||||
assertThat(actionList.size()).isEqualTo(4);
|
||||
Set<String> actionNames = Set.of("DeleteQuery", "UpdateQuery", "SelectQuery", "InsertQuery");
|
||||
actionList.forEach(action -> {
|
||||
assertThat(actionNames.contains(
|
||||
action.getUnpublishedAction().getName()))
|
||||
.isTrue();
|
||||
});
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testPartialImport_gitConnectedAppDefaultBranch_success() {
|
||||
Application application = createGitConnectedApp("testPartialImport_gitConnectedAppDefaultBranch_success");
|
||||
|
||||
// update git branch name for page
|
||||
PageDTO savedPage = new PageDTO();
|
||||
savedPage.setName("Page 2");
|
||||
savedPage.setApplicationId(application.getId());
|
||||
DefaultResources defaultResources = new DefaultResources();
|
||||
defaultResources.setApplicationId(application.getId());
|
||||
defaultResources.setBranchName("master");
|
||||
savedPage.setDefaultResources(defaultResources);
|
||||
savedPage = applicationPageService
|
||||
.createPageWithBranchName(savedPage, "master")
|
||||
.block();
|
||||
|
||||
Part filePart = createFilePart("test_assets/ImportExportServiceTest/partial-export-valid-without-widget.json");
|
||||
|
||||
PageDTO finalSavedPage = savedPage;
|
||||
Mono<Tuple3<Application, List<NewAction>, List<ActionCollection>>> result = partialImportService
|
||||
.importResourceInPage(workspaceId, application.getId(), savedPage.getId(), "master", filePart)
|
||||
.flatMap(application1 -> {
|
||||
Mono<List<NewAction>> actionList = newActionService
|
||||
.findByPageId(finalSavedPage.getId(), Optional.empty())
|
||||
.collectList();
|
||||
Mono<List<ActionCollection>> actionCollectionList = actionCollectionService
|
||||
.findByPageId(finalSavedPage.getId())
|
||||
.collectList();
|
||||
return Mono.zip(Mono.just(application1), actionList, actionCollectionList);
|
||||
});
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(object -> {
|
||||
Application application1 = object.getT1();
|
||||
List<NewAction> actionList = object.getT2();
|
||||
List<ActionCollection> actionCollectionList = object.getT3();
|
||||
|
||||
// Verify that the application has the imported resource
|
||||
assertThat(application1.getPages().size()).isEqualTo(2);
|
||||
|
||||
assertThat(application1.getUnpublishedCustomJSLibs().size()).isEqualTo(1);
|
||||
|
||||
assertThat(actionCollectionList.size()).isEqualTo(1);
|
||||
assertThat(actionCollectionList
|
||||
.get(0)
|
||||
.getUnpublishedCollection()
|
||||
.getName())
|
||||
.isEqualTo("Github_Transformer");
|
||||
assertThat(actionList.size()).isEqualTo(1);
|
||||
Set<String> actionNames = Set.of("get_force_roster");
|
||||
actionList.forEach(action -> {
|
||||
assertThat(actionNames.contains(
|
||||
action.getUnpublishedAction().getName()))
|
||||
.isTrue();
|
||||
});
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testPartialImport_nameClashInAction_successWithNoNameDuplicates() {
|
||||
|
||||
// Create an application with all resources
|
||||
Application testApplication = new Application();
|
||||
testApplication.setName("testPartialImport_nameClashInAction_successWithNoNameDuplicates");
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
|
||||
testApplication = applicationPageService
|
||||
.createApplication(testApplication, workspaceId)
|
||||
.block();
|
||||
|
||||
String pageId = newPageService
|
||||
.findById(testApplication.getPages().get(0).getId(), Optional.empty())
|
||||
.block()
|
||||
.getId();
|
||||
|
||||
Part filePart = createFilePart("test_assets/ImportExportServiceTest/partial-export-resource.json");
|
||||
|
||||
Mono<Tuple3<Application, List<NewAction>, List<ActionCollection>>> result = partialImportService
|
||||
.importResourceInPage(workspaceId, testApplication.getId(), pageId, null, filePart)
|
||||
.then(partialImportService.importResourceInPage(
|
||||
workspaceId, testApplication.getId(), pageId, null, filePart))
|
||||
.flatMap(application -> {
|
||||
Mono<List<NewAction>> actionList = newActionService
|
||||
.findByPageId(pageId, Optional.empty())
|
||||
.collectList();
|
||||
Mono<List<ActionCollection>> actionCollectionList =
|
||||
actionCollectionService.findByPageId(pageId).collectList();
|
||||
|
||||
return Mono.zip(Mono.just(application), actionList, actionCollectionList);
|
||||
});
|
||||
|
||||
StepVerifier.create(result)
|
||||
.assertNext(object -> {
|
||||
Application application = object.getT1();
|
||||
List<NewAction> actionList = object.getT2();
|
||||
List<ActionCollection> actionCollectionList = object.getT3();
|
||||
|
||||
// Verify that the application has the imported resource
|
||||
assertThat(application.getPages().size()).isEqualTo(1);
|
||||
|
||||
assertThat(actionCollectionList.size()).isEqualTo(2);
|
||||
Set<String> nameList = Set.of("utils", "utils1");
|
||||
actionCollectionList.forEach(collection -> {
|
||||
assertThat(nameList.contains(
|
||||
collection.getUnpublishedCollection().getName()))
|
||||
.isTrue();
|
||||
});
|
||||
assertThat(actionList.size()).isEqualTo(8);
|
||||
Set<String> actionNames = Set.of(
|
||||
"DeleteQuery",
|
||||
"UpdateQuery",
|
||||
"SelectQuery",
|
||||
"InsertQuery",
|
||||
"DeleteQuery1",
|
||||
"UpdateQuery1",
|
||||
"SelectQuery1",
|
||||
"InsertQuery1");
|
||||
actionList.forEach(action -> {
|
||||
assertThat(actionNames.contains(
|
||||
action.getUnpublishedAction().getName()))
|
||||
.isTrue();
|
||||
});
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,6 @@ import reactor.test.StepVerifier;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
|
||||
// All the test case are for failure or exception. Test cases for valid json file is already present in
|
||||
// ImportExportApplicationServiceTest class
|
||||
|
|
@ -138,7 +137,7 @@ public class ImportApplicationTransactionServiceTest {
|
|||
Workspace newWorkspace = new Workspace();
|
||||
newWorkspace.setName("Template Workspace");
|
||||
|
||||
Mockito.when(newActionImportableService.importEntities(any(), any(), any(), any(), any(), anyBoolean()))
|
||||
Mockito.when(newActionImportableService.importEntities(any(), any(), any(), any(), any()))
|
||||
.thenReturn(Mono.error(new AppsmithException(AppsmithError.GENERIC_BAD_REQUEST)));
|
||||
|
||||
Workspace createdWorkspace = workspaceService.create(newWorkspace).block();
|
||||
|
|
@ -169,7 +168,7 @@ public class ImportApplicationTransactionServiceTest {
|
|||
Workspace newWorkspace = new Workspace();
|
||||
newWorkspace.setName("Template Workspace");
|
||||
|
||||
Mockito.when(newActionImportableService.importEntities(any(), any(), any(), any(), any(), anyBoolean()))
|
||||
Mockito.when(newActionImportableService.importEntities(any(), any(), any(), any(), any()))
|
||||
.thenReturn(Mono.error(new MongoTransactionException(
|
||||
"Command failed with error 251 (NoSuchTransaction): 'Transaction 1 has been aborted.'")));
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,189 @@
|
|||
{
|
||||
"clientSchemaVersion": 1,
|
||||
"serverSchemaVersion": 7,
|
||||
"datasourceList": [
|
||||
{
|
||||
"datasourceConfiguration": {},
|
||||
"name": "A-force Airtable",
|
||||
"pluginId": "restapi-plugin",
|
||||
"messages": [],
|
||||
"isAutoGenerated": false,
|
||||
"isValid": true,
|
||||
"embedded": false,
|
||||
"new": true
|
||||
}
|
||||
],
|
||||
"customJSLibList": [
|
||||
{
|
||||
"name": "xmlParser",
|
||||
"accessor": [
|
||||
"xmlParser"
|
||||
],
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js",
|
||||
"version": "3.17.5",
|
||||
"defs": "{\"!name\":\"LIB/xmlParser\",\"xmlParser\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertTonimn\":{\"!type\":\"fn()\",\"prototype\":{}},\"getTraversalObj\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJson\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJsonString\":{\"!type\":\"fn()\",\"prototype\":{}},\"validate\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2xParser\":{\"!type\":\"fn()\",\"prototype\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2x\":{\"!type\":\"fn()\",\"prototype\":{}}}},\"parseToNimn\":{\"!type\":\"fn()\",\"prototype\":{}}}}",
|
||||
"userPermissions": [],
|
||||
"uidString": "xmlParser_https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js",
|
||||
"new": true
|
||||
}
|
||||
],
|
||||
"actionList": [
|
||||
{
|
||||
"id": "Todays Updates_get_force_roster",
|
||||
"pluginType": "API",
|
||||
"pluginId": "restapi-plugin",
|
||||
"unpublishedAction": {
|
||||
"name": "get_force_roster",
|
||||
"datasource": {
|
||||
"id": "A-force Airtable",
|
||||
"userPermissions": [],
|
||||
"name": "A-force Airtable",
|
||||
"pluginId": "restapi-plugin",
|
||||
"messages": [],
|
||||
"isValid": true,
|
||||
"new": false
|
||||
},
|
||||
"pageId": "Todays Updates",
|
||||
"actionConfiguration": {
|
||||
"timeoutInMillisecond": 10000,
|
||||
"paginationType": "NONE",
|
||||
"path": "/v0/appgSZSXDttNUK57V/Roster",
|
||||
"headers": [],
|
||||
"autoGeneratedHeaders": [],
|
||||
"encodeParamsToggle": true,
|
||||
"queryParameters": [
|
||||
{
|
||||
"key": "view",
|
||||
"value": "Grid view"
|
||||
},
|
||||
{
|
||||
"key": "sort[0][field]",
|
||||
"value": "StartDate"
|
||||
},
|
||||
{
|
||||
"key": "sort[0][direction]",
|
||||
"value": "desc"
|
||||
},
|
||||
{
|
||||
"key": "maxRecords",
|
||||
"value": "20"
|
||||
}
|
||||
],
|
||||
"httpMethod": "GET",
|
||||
"selfReferencingDataPaths": [],
|
||||
"pluginSpecifiedTemplates": [
|
||||
{
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"executeOnLoad": true,
|
||||
"dynamicBindingPathList": [],
|
||||
"isValid": true,
|
||||
"invalids": [],
|
||||
"messages": [],
|
||||
"jsonPathKeys": [],
|
||||
"confirmBeforeExecute": false,
|
||||
"userPermissions": [],
|
||||
"validName": "get_force_roster",
|
||||
"selfReferencingDataPaths": []
|
||||
},
|
||||
"publishedAction": {
|
||||
"name": "get_force_roster",
|
||||
"datasource": {
|
||||
"id": "A-force Airtable",
|
||||
"userPermissions": [],
|
||||
"name": "A-force Airtable",
|
||||
"pluginId": "restapi-plugin",
|
||||
"messages": [],
|
||||
"isValid": true,
|
||||
"new": false
|
||||
},
|
||||
"pageId": "Todays Updates",
|
||||
"actionConfiguration": {
|
||||
"timeoutInMillisecond": 10000,
|
||||
"paginationType": "NONE",
|
||||
"path": "/v0/appgSZSXDttNUK57V/Roster",
|
||||
"headers": [],
|
||||
"autoGeneratedHeaders": [],
|
||||
"encodeParamsToggle": true,
|
||||
"queryParameters": [
|
||||
{
|
||||
"key": "view",
|
||||
"value": "Grid view"
|
||||
},
|
||||
{
|
||||
"key": "sort[0][field]",
|
||||
"value": "StartDate"
|
||||
},
|
||||
{
|
||||
"key": "sort[0][direction]",
|
||||
"value": "desc"
|
||||
},
|
||||
{
|
||||
"key": "maxRecords",
|
||||
"value": "20"
|
||||
}
|
||||
],
|
||||
"httpMethod": "GET",
|
||||
"selfReferencingDataPaths": [],
|
||||
"pluginSpecifiedTemplates": [
|
||||
{
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"executeOnLoad": true,
|
||||
"dynamicBindingPathList": [],
|
||||
"isValid": true,
|
||||
"invalids": [],
|
||||
"messages": [],
|
||||
"jsonPathKeys": [],
|
||||
"confirmBeforeExecute": false,
|
||||
"userPermissions": [],
|
||||
"validName": "get_force_roster",
|
||||
"selfReferencingDataPaths": []
|
||||
},
|
||||
"new": false
|
||||
}
|
||||
],
|
||||
"actionCollectionList": [
|
||||
{
|
||||
"id": "Todays Updates_Github_Transformer",
|
||||
"unpublishedCollection": {
|
||||
"name": "Github_Transformer",
|
||||
"pageId": "Todays Updates",
|
||||
"pluginId": "js-plugin",
|
||||
"pluginType": "JS",
|
||||
"actions": [],
|
||||
"archivedActions": [],
|
||||
"body": "export default {\n\tresults: [],\n\tgetCriticalIssues: () => {\n\t\treturn fetchCriticalIssues.data.map((issue) => { \n\t\t\treturn { \n\t\t\t\ttitle: issue.title, \n\t\t\t\tuser: issue.user.login, \n\t\t\t\tage: moment(issue.created_at).fromNow(), \n\t\t\t\tlabels: issue.labels.map((label) => label.name).join(', '),\n\t\t\t\tassignees: issue.assignees.map((label) => label.login).join(', '), \n\t\t\t\tlink: issue.html_url, \n\t\t\t\tbody: issue.body, \n\t\t\t\tnumber: issue.number,\n\t\t\t}\n\t\t})\n\t}\n}",
|
||||
"variables": [
|
||||
{
|
||||
"name": "results",
|
||||
"value": "[]"
|
||||
}
|
||||
],
|
||||
"userPermissions": []
|
||||
},
|
||||
"publishedCollection": {
|
||||
"name": "Github_Transformer",
|
||||
"pageId": "Todays Updates",
|
||||
"pluginId": "js-plugin",
|
||||
"pluginType": "JS",
|
||||
"actions": [],
|
||||
"archivedActions": [],
|
||||
"body": "export default {\n\tresults: [],\n\tgetCriticalIssues: () => {\n\t\treturn fetchCriticalIssues.data.map((issue) => { \n\t\t\treturn { \n\t\t\t\ttitle: issue.title, \n\t\t\t\tuser: issue.user.login, \n\t\t\t\tage: moment(issue.created_at).fromNow(), \n\t\t\t\tlabels: issue.labels.map((label) => label.name).join(', '),\n\t\t\t\tassignees: issue.assignees.map((label) => label.login).join(', '), \n\t\t\t\tlink: issue.html_url, \n\t\t\t\tbody: issue.body, \n\t\t\t\tnumber: issue.number,\n\t\t\t}\n\t\t})\n\t}\n}",
|
||||
"variables": [
|
||||
{
|
||||
"name": "results",
|
||||
"value": "[]"
|
||||
}
|
||||
],
|
||||
"userPermissions": []
|
||||
},
|
||||
"new": false
|
||||
}
|
||||
],
|
||||
"widgets": ""
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user