diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java index 76fb4b2edd..960f34e453 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCE.java @@ -79,7 +79,7 @@ public interface CustomApplicationRepositoryCE extends AppsmithRepository findByNameAndWorkspaceId(String applicationName, String workspaceId, AclPermission permission); + Mono countByNameAndWorkspaceId(String applicationName, String workspaceId, AclPermission permission); Flux getAllApplicationIdsInWorkspaceAccessibleToARoleWithPermission( String workspaceId, AclPermission permission, String permissionGroupId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java index d70cc25f58..da482078c4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomApplicationRepositoryCEImpl.java @@ -318,13 +318,13 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp } @Override - public Mono findByNameAndWorkspaceId( - String applicationName, String workspaceId, AclPermission permission) { + public Mono countByNameAndWorkspaceId(String applicationName, String workspaceId, AclPermission permission) { Criteria workspaceIdCriteria = where(fieldName(QApplication.application.workspaceId)).is(workspaceId); Criteria applicationNameCriteria = where(fieldName(QApplication.application.name)).is(applicationName); - return queryOne(List.of(workspaceIdCriteria, applicationNameCriteria), permission); + + return count(List.of(workspaceIdCriteria, applicationNameCriteria), permission); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java index bc34c133db..c144f1a41a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java @@ -1363,23 +1363,25 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE { Mono userMono = sessionUserService.getCurrentUser().cache(); Mono applicationWithPoliciesMono = this.setApplicationPolicies(userMono, application.getWorkspaceId(), application); - Mono applicationMono = applicationService.findByNameAndWorkspaceId( + Mono applicationNameTakenMono = applicationService.isApplicationNameTaken( actualName, application.getWorkspaceId(), MANAGE_APPLICATIONS); // We are taking pessimistic approach as this flow is used in import application where we are using transactions // which creates problem if we hit duplicate key exception - return applicationMono - .flatMap(application1 -> this.createOrUpdateSuffixedApplication(application, name, 1 + suffix)) - .switchIfEmpty(Mono.defer( - () -> applicationWithPoliciesMono.zipWith(userMono).flatMap(tuple -> { - Application application1 = tuple.getT1(); - application1.setModifiedBy( - tuple.getT2().getUsername()); // setting modified by to current user - // We can't use create or createApplication method here as we are expecting update operation - // if the - // _id is available with application object - return applicationService.save(application); - }))); + return applicationNameTakenMono.flatMap(isNameTaken -> { + if (isNameTaken) { + return this.createOrUpdateSuffixedApplication(application, name, 1 + suffix); + } else { + return applicationWithPoliciesMono.zipWith(userMono).flatMap(tuple -> { + Application application1 = tuple.getT1(); + application1.setModifiedBy(tuple.getT2().getUsername()); // setting modified by to current user + // We can't use create or createApplication method here as we are expecting update operation + // if the + // _id is available with application object + return applicationService.save(application); + }); + } + }); } /** diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java index 513b3e3063..69d3e08f94 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCE.java @@ -98,7 +98,7 @@ public interface ApplicationServiceCE extends CrudService { public Mono deleteAppNavigationLogo(String branchName, String applicationId); - Mono findByNameAndWorkspaceId(String applicationName, String workspaceId, AclPermission permission); + Mono isApplicationNameTaken(String applicationName, String workspaceId, AclPermission permission); Mono isApplicationConnectedToGit(String applicationId); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java index e85d5b912a..438b9aaa85 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationServiceCEImpl.java @@ -980,9 +980,10 @@ public class ApplicationServiceCEImpl extends BaseService findByNameAndWorkspaceId( - String applicationName, String workspaceId, AclPermission permission) { - return repository.findByNameAndWorkspaceId(applicationName, workspaceId, permission); + public Mono isApplicationNameTaken(String applicationName, String workspaceId, AclPermission permission) { + return repository + .countByNameAndWorkspaceId(applicationName, workspaceId, permission) + .map(count -> count > 0); } @Override diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java index 2ccaca6aa7..f4298e668d 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java @@ -3,6 +3,7 @@ package com.appsmith.server.services; import com.appsmith.git.constants.CommonConstants; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.GitApplicationMetadata; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Workspace; @@ -287,4 +288,42 @@ public class ApplicationPageServiceTest { }) .verifyComplete(); } + + @Test + @WithUserDetails("api_user") + public void createOrUpdateSuffixedApplication_GitConnectedAppExistsWithSameName_AppCreatedWithSuffixedName() { + // create a Git connected application with two branches + final String appName = "app" + UUID.randomUUID(); + Application application = new Application(); + application.setName(appName); + GitApplicationMetadata gitApplicationMetadata = new GitApplicationMetadata(); + gitApplicationMetadata.setBranchName("branch1"); + application.setGitApplicationMetadata(gitApplicationMetadata); + + Mono importAppMono = applicationPageService + .createApplication(application, workspace.getId()) + .flatMap(createdApp -> { + createdApp.getGitApplicationMetadata().setDefaultApplicationId(createdApp.getId()); + return applicationService.save(createdApp); + }) + .flatMap(createdApp -> { + createdApp.setId(null); + createdApp.getGitApplicationMetadata().setBranchName("branch2"); + // just duplicate the app, we're not considering the pages, they remain same in both apps + return applicationRepository.save(createdApp); + }) + .flatMap(createdApp -> { + Application newApplication = new Application(); + newApplication.setName(appName); + newApplication.setWorkspaceId(workspace.getId()); + return applicationPageService.createOrUpdateSuffixedApplication( + newApplication, newApplication.getName(), 0); + }); + + StepVerifier.create(importAppMono) + .assertNext(application1 -> { + assertThat(application1.getName()).isEqualTo(appName + " (1)"); + }) + .verifyComplete(); + } }