diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java index da9412dc4a..90e800d91f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java @@ -591,9 +591,9 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica /** * This function will take the application reference object to hydrate the application in mongoDB * - * @param organizationId organization to which application is going to be stored - * @param applicationJson application resource which contains necessary information to save the application - * @param applicationId application which needs to be saved with the updated resources + * @param organizationId organization to which application is going to be stored + * @param applicationJson application resource which contains necessary information to import the application + * @param applicationId application which needs to be saved with the updated resources * @return Updated application */ public Mono importApplicationInOrganization(String organizationId, @@ -689,6 +689,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica // Check for duplicate datasources to avoid duplicates in target organization .flatMap(datasource -> { + final String importedDatasourceName = datasource.getName(); // Check if the datasource has gitSyncId and if it's already in DB if (datasource.getGitSyncId() != null && savedDatasourcesGitIdToDatasourceMap.containsKey(datasource.getGitSyncId())) { @@ -702,7 +703,11 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica datasource.setPluginId(null); AppsmithBeanUtils.copyNestedNonNullProperties(datasource, existingDatasource); existingDatasource.setStructure(null); - return datasourceService.update(existingDatasource.getId(), existingDatasource); + return datasourceService.update(existingDatasource.getId(), existingDatasource) + .map(datasource1 -> { + datasourceMap.put(importedDatasourceName, datasource1.getId()); + return datasource1; + }); } // This is explicitly copied over from the map we created before @@ -719,11 +724,11 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica updateAuthenticationDTO(datasource, decryptedFields); } - return createUniqueDatasourceIfNotPresent(existingDatasourceFlux, datasource, organizationId, applicationId); - }) - .map(datasource -> { - datasourceMap.put(datasource.getName(), datasource.getId()); - return datasource; + return createUniqueDatasourceIfNotPresent(existingDatasourceFlux, datasource, organizationId) + .map(datasource1 -> { + datasourceMap.put(importedDatasourceName, datasource1.getId()); + return datasource1; + }); }) .collectList(); }) @@ -1726,9 +1731,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica */ private Mono createUniqueDatasourceIfNotPresent(Flux existingDatasourceFlux, Datasource datasource, - String organizationId, - String applicationId) { - + String organizationId) { /* 1. If same datasource is present return 2. If unable to find the datasource create a new datasource with unique name and return @@ -1743,16 +1746,8 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica } return existingDatasourceFlux - .map(ds -> { - final DatasourceConfiguration dsAuthConfig = ds.getDatasourceConfiguration(); - if (dsAuthConfig != null && dsAuthConfig.getAuthentication() != null) { - dsAuthConfig.getAuthentication().setAuthenticationResponse(null); - dsAuthConfig.getAuthentication().setAuthenticationType(null); - } - return ds; - }) // For git import exclude datasource configuration - .filter(ds -> applicationId != null ? ds.getName().equals(datasource.getName()) : ds.softEquals(datasource)) + .filter(ds -> ds.getName().equals(datasource.getName()) && datasource.getPluginId().equals(ds.getPluginId())) .next() // Get the first matching datasource, we don't need more than one here. .switchIfEmpty(Mono.defer(() -> { if (datasourceConfig != null && datasourceConfig.getAuthentication() != null) { diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/GitServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/GitServiceTest.java index f6d32b84bd..00bd79ff3b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/GitServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/GitServiceTest.java @@ -1702,7 +1702,7 @@ public class GitServiceTest { StepVerifier .create(applicationMono) .expectErrorMatches(throwable -> throwable instanceof AppsmithException - && throwable.getMessage().equals(AppsmithError.GIT_ACTION_FAILED.getMessage("checkout", "origin/branchInLocal already exists in remote"))) + && throwable.getMessage().equals(AppsmithError.GIT_ACTION_FAILED.getMessage("checkout", "origin/branchInLocal already exists in local - branchInLocal"))) .verify(); } @@ -2486,7 +2486,7 @@ public class GitServiceTest { @Test @WithUserDetails(value = "api_user") - public void importApplicationFromGit_validRequestWithDuplicateDatasourceOfSameTypeCancelledMidway_Success() throws GitAPIException, IOException { + public void importApplicationFromGit_validRequestWithDuplicateDatasourceOfSameTypeCancelledMidway_Success() { Organization organization = new Organization(); organization.setName("gitImportOrgCancelledMidway"); final String testOrgId = organizationService.create(organization) @@ -2497,6 +2497,7 @@ public class GitServiceTest { GitAuth gitAuth = gitService.generateSSHKey().block(); ApplicationJson applicationJson = createAppJson(filePath).block(); + applicationJson.getExportedApplication().setName(null); applicationJson.getDatasourceList().get(0).setName("db-auth-testGitImportRepo"); String pluginId = pluginRepository.findByPackageName("mongo-plugin").block().getId(); @@ -2521,7 +2522,7 @@ public class GitServiceTest { // Wait for git clone to complete Mono gitConnectedAppFromDbMono = Mono.just(testOrgId) - .flatMap(application -> { + .flatMap(ignore -> { try { // Before fetching the git connected application, sleep for 5 seconds to ensure that the clone // completes diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java index 3d2068df89..962faf40cf 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java @@ -2182,5 +2182,111 @@ public class ImportExportApplicationServiceTests { }) .verifyComplete(); } + + @Test + @WithUserDetails(value = "api_user") + public void importApplication_datasourceWithSameNameAndDifferentPlugin_importedWithValidActionsAndSuffixedDatasource() { + + ApplicationJson applicationJson = createAppJson("test_assets/ImportExportServiceTest/valid-application.json").block(); + + Organization testOrganization = new Organization(); + testOrganization.setName("Duplicate datasource with different plugin org"); + testOrganization = organizationService.create(testOrganization).block(); + + Datasource testDatasource = new Datasource(); + // Chose any plugin except for mongo, as json static file has mongo plugin for datasource + Plugin postgreSQLPlugin = pluginRepository.findByName("PostgreSQL").block(); + testDatasource.setPluginId(postgreSQLPlugin.getId()); + testDatasource.setOrganizationId(testOrganization.getId()); + final String datasourceName = applicationJson.getDatasourceList().get(0).getName(); + testDatasource.setName(datasourceName); + datasourceService.create(testDatasource).block(); + + final Mono resultMono = importExportApplicationService.importApplicationInOrganization(testOrganization.getId(), applicationJson); + + StepVerifier + .create(resultMono + .flatMap(application -> Mono.zip( + Mono.just(application), + datasourceService.findAllByOrganizationId(application.getOrganizationId(), MANAGE_DATASOURCES).collectList(), + newActionService.findAllByApplicationIdAndViewMode(application.getId(), false, READ_ACTIONS, null).collectList() + ))) + .assertNext(tuple -> { + final Application application = tuple.getT1(); + final List datasourceList = tuple.getT2(); + final List actionList = tuple.getT3(); + + assertThat(application.getName()).isEqualTo("valid_application"); + + List datasourceNameList = new ArrayList<>(); + assertThat(datasourceList).isNotEmpty(); + datasourceList.forEach(datasource -> { + assertThat(datasource.getOrganizationId()).isEqualTo(application.getOrganizationId()); + datasourceNameList.add(datasource.getName()); + }); + // Check if both suffixed and newly imported datasource are present + assertThat(datasourceNameList).contains(datasourceName, datasourceName + " #1"); + + assertThat(actionList).isNotEmpty(); + actionList.forEach(newAction -> { + ActionDTO actionDTO = newAction.getUnpublishedAction(); + assertThat(actionDTO.getDatasource()).isNotNull(); + }); + }) + .verifyComplete(); + } + + @Test + @WithUserDetails(value = "api_user") + public void importApplication_datasourceWithSameNameAndPlugin_importedWithValidActionsWithoutSuffixedDatasource() { + + ApplicationJson applicationJson = createAppJson("test_assets/ImportExportServiceTest/valid-application.json").block(); + + Organization testOrganization = new Organization(); + testOrganization.setName("Duplicate datasource with same plugin org"); + testOrganization = organizationService.create(testOrganization).block(); + + Datasource testDatasource = new Datasource(); + // Chose plugin same as mongo, as json static file has mongo plugin for datasource + Plugin postgreSQLPlugin = pluginRepository.findByName("MongoDB").block(); + testDatasource.setPluginId(postgreSQLPlugin.getId()); + testDatasource.setOrganizationId(testOrganization.getId()); + final String datasourceName = applicationJson.getDatasourceList().get(0).getName(); + testDatasource.setName(datasourceName); + datasourceService.create(testDatasource).block(); + + final Mono resultMono = importExportApplicationService.importApplicationInOrganization(testOrganization.getId(), applicationJson); + + StepVerifier + .create(resultMono + .flatMap(application -> Mono.zip( + Mono.just(application), + datasourceService.findAllByOrganizationId(application.getOrganizationId(), MANAGE_DATASOURCES).collectList(), + newActionService.findAllByApplicationIdAndViewMode(application.getId(), false, READ_ACTIONS, null).collectList() + ))) + .assertNext(tuple -> { + final Application application = tuple.getT1(); + final List datasourceList = tuple.getT2(); + final List actionList = tuple.getT3(); + + assertThat(application.getName()).isEqualTo("valid_application"); + + List datasourceNameList = new ArrayList<>(); + assertThat(datasourceList).isNotEmpty(); + datasourceList.forEach(datasource -> { + assertThat(datasource.getOrganizationId()).isEqualTo(application.getOrganizationId()); + datasourceNameList.add(datasource.getName()); + }); + // Check that there are no datasources are created with suffix names as datasource's are of same plugin + assertThat(datasourceNameList).contains(datasourceName); + + assertThat(actionList).isNotEmpty(); + actionList.forEach(newAction -> { + ActionDTO actionDTO = newAction.getUnpublishedAction(); + assertThat(actionDTO.getDatasource()).isNotNull(); + }); + }) + .verifyComplete(); + } }